EtherLib/prefab/conn_blocks/igmp_connblock.c
Epagris 8044d8a8b6 - RawPckt: force FCS computation feature added
- IGMP transmission reworked
- IPv4: method for filling in checksum in rendered binary data added
2024-10-20 15:38:36 +02:00

129 lines
4.3 KiB
C

#include "igmp_connblock.h"
#include <stddef.h>
#include "../packet_parsers/packet_parsers.h"
#include "../../utils.h"
#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"
static bool filtIgmp(const PcktSieveFilterCondition * filtCond, const PcktProps * contProps, const PcktProps * ownProps, EthInterface * intf) {
IPv4Props * ipProps = (IPv4Props *) contProps;
IgmpProps * icmpProps = (IgmpProps *) ownProps;
return ipProps->Protocol == ETH_IGMP_PACKET_CLASS;
}
ConnBlock igmp_new_connblock(struct EthInterface_ *intf) {
ConnBlock igmpConnB;
connb_init_defaults(&igmpConnB);
ConnBlock ipConnB = ipv4_new_connblock(intf, IPv4_IF_ADDR, NULL); // create new IPv4 connection block
PcktSieveFilterCondition filtCond;
packfiltcond_zero(&filtCond);
PcktSieveLayerTag tag;
tag.p = intf; // Ethernet-interface passed in 'tag.p'
igmpConnB.sieveLayer = packsieve_new_layer(ipConnB.sieveLayer, &filtCond, false, filtIgmp, NULL, tag, ETH_IGMP_PACKET_CLASS);
ASSERT_NULL(igmpConnB.sieveLayer);
igmpConnB.sieve = &intf->sieve;
igmpConnB.sieveLayer->connBReportFn = igmp_print_report;
return igmpConnB;
}
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);
PcktHeaderElement * ethHeader = ALLOC_HEADER_ELEMENT(EthernetProps);
igmpHeader->next = NULL;
igmpHeader->prev = ipHeader;
ipHeader->next = igmpHeader;
ipHeader->prev = ethHeader;
ethHeader->next = ipHeader;
ethHeader->prev = NULL;
// prepare headers
IgmpProps * igmpProps = HEADER_FETCH_PROPS(IgmpProps, igmpHeader);
IPv4Props * ipProps = HEADER_FETCH_PROPS(IPv4Props, ipHeader);
EthernetProps * ethProps = HEADER_FETCH_PROPS(EthernetProps, ethHeader);
// fetch sieve layers and fill transmit headers
PcktSieveLayer * layer = connBlock->sieveLayer; // UDP layer
igmpProps->type = mt;
igmpProps->maxRespTime = 0;
igmpProps->checksum = 0;
igmpProps->groupAddr = ga;
// common fields for packet assembly
igmpProps->headerSize = ETH_IGMP_HEADER_SIZE;
igmpProps->hdrInsFn = insert_igmp_header;
// IP
layer = layer->parent;
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, 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;
// 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);
// insert Ethernet header
insert_ethernet_header(txBuf, ethHeader, NULL);
// 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
// insert IGMP header
insert_igmp_header(txBuf + ETH_ETHERNET_HEADER_SIZE + ETH_IPv4_HEADER_SIZE, igmpHeader, intf);
// 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) {
igmp_send(connBlock, ga, IGMP_MT_MEMBERSHIP_REPORT);
}
void igmp_leave_group(ConnBlock *connBlock, ip4_addr ga) {
igmp_send(connBlock, ga, IGMP_MT_LEAVE_GROUP);
}
void igmp_print_report(const ConnBlock* connBlock) {
INFO("IGMP");
}