I see you have abandoned this, but I'll answer it for anyone else looking for the solution.
I ran into the same problem when trying to do a similar thing. I discovered that you have to link all your packets together before you can call CalculateTCPChecksum()
So to fix the example asked in the question, this should work (I haven't tested this code but it is very similar to the code I wrote that I got working):
public void packetstuff(string toIp, string fromIp, byte[] payload)
{
ushort tcpSourcePort = 123;
ushort tcpDestinationPort = 321;
var tcpPacket = new TcpPacket(tcpSourcePort, tcpDestinationPort);
var ipSourceAddress = System.Net.IPAddress.Parse(fromIp);
var ipDestinationAddress = System.Net.IPAddress.Parse(toIp);
var ipPacket = new IPv4Packet(ipSourceAddress, ipDestinationAddress);
var sourceHwAddress = "MY-MA-CA-DD-RE-SS";
var ethernetSourceHwAddress = System.Net.NetworkInformation.PhysicalAddress.Parse(sourceHwAddress);
var destinationHwAddress = "MY-MA-CA-DD-RE-SS";
var ethernetDestinationHwAddress = System.Net.NetworkInformation.PhysicalAddress.Parse(destinationHwAddress);
var ethernetPacket = new EthernetPacket(ethernetSourceHwAddress,
ethernetDestinationHwAddress,
EthernetPacketType.None);
ethernetPacket.PayloadPacket = ipPacket;
ipPacket.ParentPacket = ethernetPacket;
if (tcpPacket != null)
{
ipPacket.PayloadPacket = tcpPacket;
tcpPacket.ParentPacket = ip;
ipPacket.UpdateIPChecksum();
tcpPacket.Checksum = (ushort)tcpPacket.CalculateTCPChecksum();
}
else
ipPacket.UpdateIPChecksum();
ethernetPacket.UpdateCalculatedValues();
packetBytes = ethernetPacket.Bytes;
Thread producer = new Thread(new ThreadStart(ThreadRun));
device.Open();
producer.Start();
}