diff --git a/packet.h b/packet.h index accb2c6..091c467 100644 --- a/packet.h +++ b/packet.h @@ -3,6 +3,8 @@ #include +#include + /** * \struct RawPckt * \brief Raw packet received on wire @@ -20,6 +22,9 @@ uint32_t arg; ///> User-defined argument } tx; } ext; ///> Extensions + struct { + bool calculate_ethernet_CRC : 1; ///> Instruct the packet assembler to always computer FCS regardless of device capabilities + } opts; } RawPckt; struct PcktHeaderElement_; diff --git a/pckt_assembler.c b/pckt_assembler.c index dc4d776..fdeb36f 100644 --- a/pckt_assembler.c +++ b/pckt_assembler.c @@ -28,7 +28,7 @@ int pckt_assemble(RawPckt *raw, Pckt *cooked, EthInterface *intf) { hdrIter = hdrIter->next; } frameSize = headerSize + cooked->payloadSize;// + 4; // header + payload - bool computeCRC = !(intf->capabilities & ETHINF_CAP_TX_CRC_OFFLOAD); + bool computeCRC = (!(intf->capabilities & ETHINF_CAP_TX_CRC_OFFLOAD)) || raw->opts.calculate_ethernet_CRC; if (computeCRC) { // + CRC32 checksum area if needed frameSize += 4; } @@ -73,10 +73,10 @@ int pckt_assemble(RawPckt *raw, Pckt *cooked, EthInterface *intf) { } } - // insert CRC32 if interface is not capable of inserting CRC + // insert CRC32 if interface cannot handle CRC calculation or if explicitly requested if (computeCRC) { uint32_t crc = crc32(raw->payload, frameSize - 4); - memcpy(raw->payload + frameSize - 4, (const uint8_t *)&crc, 4); + memcpy(raw->payload + frameSize - 4, &crc, 4); } // turn off TX timestamping by default diff --git a/prefab/conn_blocks/arp_connblock.c b/prefab/conn_blocks/arp_connblock.c index 48bf9c1..8c1eaf0 100644 --- a/prefab/conn_blocks/arp_connblock.c +++ b/prefab/conn_blocks/arp_connblock.c @@ -80,6 +80,7 @@ void arp_send(const ConnBlock *connBlock, const ArpProps *props) { // send packet RawPckt rpckt; + memset(&rpckt, 0, sizeof(RawPckt)); rpckt.size = txBufSize; rpckt.payload = txBuf; rpckt.ext.tx.txTsCb = NULL; diff --git a/prefab/conn_blocks/custom_ethertype_connblock.c b/prefab/conn_blocks/custom_ethertype_connblock.c index 23c806d..b0a2cc0 100644 --- a/prefab/conn_blocks/custom_ethertype_connblock.c +++ b/prefab/conn_blocks/custom_ethertype_connblock.c @@ -73,6 +73,7 @@ int cet_send_arg(cbd d, const uint8_t *dest, const uint8_t *data, uint16_t size, cooked.time_ns = 0; RawPckt raw; + memset(&raw, 0, sizeof(RawPckt)); pckt_assemble(&raw, &cooked, connBlock.sieve->intf); raw.ext.tx.arg = arg; // assign argument raw.ext.tx.txTsCb = connBlock.sieveLayer->txTsCb; // assign with TX timestamp callback diff --git a/prefab/conn_blocks/icmp_connblock.c b/prefab/conn_blocks/icmp_connblock.c index 09596f4..c1ff70d 100644 --- a/prefab/conn_blocks/icmp_connblock.c +++ b/prefab/conn_blocks/icmp_connblock.c @@ -81,6 +81,7 @@ static int icmp_recv_cb(const Pckt * pckt, PcktSieveLayerTag tag) { // assemble packet RawPckt raw; + memset(&raw, 0, sizeof(RawPckt)); pckt_assemble(&raw, &reply, intf); // release headers diff --git a/prefab/conn_blocks/igmp_connblock.c b/prefab/conn_blocks/igmp_connblock.c index 2bc008c..f118f68 100644 --- a/prefab/conn_blocks/igmp_connblock.c +++ b/prefab/conn_blocks/igmp_connblock.c @@ -7,6 +7,7 @@ #include "../../dynmem.h" #include "../../pckt_assembler.h" #include "../../eth_interface.h" +#include "etherlib/prefab/packet_parsers/ipv4_packet.h" #include "ipv4_connblock.h" #include "../packet_parsers/igmp_packet.h" @@ -37,6 +38,9 @@ ConnBlock igmp_new_connblock(struct EthInterface_ *intf) { } static void igmp_send(ConnBlock * connBlock, ip4_addr ga, int mt) { + // fetch interface + EthInterface * intf = connBlock->sieve->intf; + // allocate headers PcktHeaderElement * igmpHeader = ALLOC_HEADER_ELEMENT(IgmpProps); PcktHeaderElement * ipHeader = ALLOC_HEADER_ELEMENT(IPv4Props); @@ -67,34 +71,49 @@ static void igmp_send(ConnBlock * connBlock, ip4_addr ga, int mt) { // IP layer = layer->parent; - ipv4_fill_props(ipProps, ETH_IGMP_HEADER_SIZE, ETH_IGMP_PACKET_CLASS, connBlock->sieve->intf->ip, ga); + ipv4_fill_props(ipProps, ETH_IGMP_HEADER_SIZE, ETH_IGMP_PACKET_CLASS, intf->ip, ga); // Ethernet ethmc_from_ipmc(ethProps->destAddr, ga); - memcpy(ethProps->sourceAddr, connBlock->sieve->intf->mac, ETH_HW_ADDR_LEN); + memcpy(ethProps->sourceAddr, intf->mac, ETH_HW_ADDR_LEN); ethProps->length_type = ETH_IPv4_PACKET_CLASS; // common fields for packet assembly ethProps->hdrInsFn = insert_ethernet_header; ethProps->headerSize = ETH_ETHERNET_HEADER_SIZE; - Pckt cooked; - cooked.payload = NULL; - cooked.payloadSize = 0; - cooked.header = ethHeader; + // allocate transmit buffer + uint32_t txHeaderSize = ETH_ETHERNET_HEADER_SIZE + ETH_IPv4_HEADER_SIZE + ETH_IGMP_HEADER_SIZE; + uint32_t txBufSize = MAX(txHeaderSize + 4, ETH_FRAME_MIN_SIZE); + uint8_t *txBuf = dynmem_alloc(txBufSize); + memset(txBuf, 0, txBufSize); - // NOT FILLED FIELDS - cooked.headerSize = 0; - cooked.time_s = 0; - cooked.time_ns = 0; + // insert Ethernet header + insert_ethernet_header(txBuf, ethHeader, NULL); - RawPckt raw; - pckt_assemble(&raw, &cooked, connBlock->sieve->intf); + // insert IPv4 header + insert_ipv4_header(txBuf + ETH_ETHERNET_HEADER_SIZE, ipHeader, intf); + ipv4_fill_in_chksum(txBuf + ETH_ETHERNET_HEADER_SIZE); // fill-in IPv4 checksum - ethinf_transmit(connBlock->sieve->intf, &raw); + // insert IGMP header + insert_igmp_header(txBuf + ETH_ETHERNET_HEADER_SIZE + ETH_IPv4_HEADER_SIZE, igmpHeader, intf); - // free headers - pckthdr_chain_free(ethHeader); + // release headers + dynmem_free(ethHeader); + dynmem_free(ipHeader); + dynmem_free(igmpHeader); + + // calculate CRC + uint32_t crc = crc32(txBuf, txBufSize - 4); + memcpy(txBuf + txBufSize - 4, &crc, 4); + + // send packet + RawPckt rpckt; + memset(&rpckt, 0, sizeof(RawPckt)); + rpckt.size = txBufSize; + rpckt.payload = txBuf; + rpckt.ext.tx.txTsCb = NULL; + ethinf_transmit(intf, &rpckt); } void igmp_report_membership(ConnBlock * connBlock, ip4_addr ga) { diff --git a/prefab/conn_blocks/tcp_connblock.c b/prefab/conn_blocks/tcp_connblock.c index 1c7c5f4..04b7851 100644 --- a/prefab/conn_blocks/tcp_connblock.c +++ b/prefab/conn_blocks/tcp_connblock.c @@ -694,6 +694,7 @@ int tcp_send_segment(const struct ConnBlock_ *connBlock, TcpFlag flags, TcpOptio cooked.time_ns = 0; RawPckt raw; + memset(&raw, 0, sizeof(RawPckt)); pckt_assemble(&raw, &cooked, connBlock->sieve->intf); ethinf_transmit(connBlock->sieve->intf, &raw); diff --git a/prefab/conn_blocks/udp_connblock.c b/prefab/conn_blocks/udp_connblock.c index df54d76..692dca3 100644 --- a/prefab/conn_blocks/udp_connblock.c +++ b/prefab/conn_blocks/udp_connblock.c @@ -120,6 +120,7 @@ int udp_sendto_arg(cbd d, const uint8_t *data, uint32_t size, ip4_addr addr, uin cooked.time_ns = 0; RawPckt raw; + memset(&raw, 0, sizeof(RawPckt)); pckt_assemble(&raw, &cooked, connBlock.sieve->intf); raw.ext.tx.arg = arg; // assign argument raw.ext.tx.txTsCb = connBlock.sieveLayer->txTsCb; // assign with TX timestamp callback diff --git a/prefab/packet_parsers/ipv4_packet.c b/prefab/packet_parsers/ipv4_packet.c index b32a135..08635c8 100644 --- a/prefab/packet_parsers/ipv4_packet.c +++ b/prefab/packet_parsers/ipv4_packet.c @@ -145,3 +145,9 @@ void ipv4_fill_props(IPv4Props *ipProps, ipProps->headerSize = ETH_IPv4_HEADER_SIZE; } + +void ipv4_fill_in_chksum(uint8_t * hdr) { + uint8_t * ChkSumPtr = hdr + 10; // create a pointer to checksum position + uint16_t checksum = chksum(hdr, ETH_IPv4_HEADER_SIZE, false); // compute checksum + memcpy(ChkSumPtr, &checksum, 2); // copy checksum to the proper position +} \ No newline at end of file diff --git a/prefab/packet_parsers/ipv4_packet.h b/prefab/packet_parsers/ipv4_packet.h index d262bf5..a55fb08 100644 --- a/prefab/packet_parsers/ipv4_packet.h +++ b/prefab/packet_parsers/ipv4_packet.h @@ -76,4 +76,10 @@ void ethmc_from_ipmc(uint8_t * hwa, ip4_addr ipa); */ void ipv4_fill_props(IPv4Props *ipProps, uint32_t payloadSize, uint16_t protocol, ip4_addr srcIpA, ip4_addr dstIpA); +/** + * Fill in IPv4 checksum, based on header data. + * @param hdr Pointer to the IPv4 header's beginning. Checksum field's position will be written. +*/ +void ipv4_fill_in_chksum(uint8_t * hdr); + #endif //ETHERLIB_IPV4_PACKET_H