Can someone please suggest why the code below doesn't do as expected? I expect it to bind an AF_PACKET socket to an interface and receive packets with ethertype 0x5eeb that arrive at multicast MAC address 77:68:76:68:76:69 on that interface. In practice, nothing arrives.
If I comment out the call to bind(), it receives packets with ethertype 0x5eeb that are addressed to 77:68:76:68:76:69 and are received on any interface on the system, not just eth0. (There are no packets with ethertype 0x5eeb sent to any other address, so this may be coincidence.) If I change either use of ether_type to be ETH_P_ALL instead (and re-instate the bind() call), then it receives all ethernet frames received on eth0. Is this a bug? Or is it as expected and I have to use some other mechanism (BPF?) to filter the frames? Thanks for any assistance, Tom Code: #include <arpa/inet.h> #include <linux/if_packet.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/if.h> #include <net/ethernet.h> #include <string.h> #include <stdio.h> #include <stdlib.h> const unsigned short eth_type = 0x5eeb; int main() { int fd = socket(AF_PACKET, SOCK_RAW, htons(eth_type)); if (fd < 0) { perror("socket"); exit(1); } struct ifreq ifr; const char * if_name = "eth0"; size_t if_name_len = strlen (if_name); memcpy(ifr.ifr_name, if_name, if_name_len); ioctl(fd, SIOCGIFINDEX, &ifr); printf("Interface has index %d\n", ifr.ifr_ifindex); struct sockaddr_ll addr = {0}; addr.sll_family = AF_PACKET; addr.sll_ifindex = ifr.ifr_ifindex; addr.sll_protocol = htons(eth_type); addr.sll_pkttype = PACKET_MULTICAST; if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("bind"); exit(1); } unsigned char mcast[ETH_ALEN] = {0x77, 0x68, 0x76, 0x68, 0x76, 0x69}; struct packet_mreq mreq = {0}; mreq.mr_ifindex = ifr.ifr_ifindex; mreq.mr_type = PACKET_MR_MULTICAST; memcpy(mreq.mr_address, mcast, ETH_ALEN); mreq.mr_alen = ETH_ALEN; if(setsockopt(fd, SOL_SOCKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { perror("setsockopt"); exit(1); } char buf [2048]; struct sockaddr_ll src_addr; socklen_t src_addr_len = sizeof(src_addr); ssize_t count = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr*)&src_addr, &src_addr_len); if (count == -1) { perror("recvfrom"); exit(1); } else { printf("Received frame.\n"); printf("Dest MAC: "); for (int ii = 0; ii < 5; ii++) { printf("%02hhx:", buf[ii]); } printf("%02hhx\n", buf[5]); printf("Src MAC: "); for (int ii = 6; ii < 11; ii++) { printf("%02hhx:", buf[ii]); } printf("%02hhx\n", buf[11]); } } And here is a short Python3 programme to generate such frames (install pyroute2 package and run as `sudo python3 test.py eth0`): import socket from pyroute2 import IPDB import sys import struct import binascii import time ip = IPDB() SMAC=bytes.fromhex(ip.interfaces[sys.argv[1]]['address'].replace(':', '')) DMAC=bytes.fromhex('776876687669') s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW) s.bind((sys.argv[1], 0x5eeb)) #s.bind((sys.argv[1], 0)) dgram = struct.pack("!6s6sHH", DMAC, SMAC, 0x5eeb, 0x7668) print(' '.join('{:02x}'.format(x) for x in dgram)) while True: s.send(dgram) time.sleep(0.1)