1.\" $OpenBSD: frame.4,v 1.2 2024/12/16 21:39:29 jmc Exp $ 2.\" 3.\" Copyright (c) 2024 David Gwynne <dlg@openbsd.org> 4.\" 5.\" Permission to use, copy, modify, and distribute this software for any 6.\" purpose with or without fee is hereby granted, provided that the above 7.\" copyright notice and this permission notice appear in all copies. 8.\" 9.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16.\" 17.Dd $Mdocdate: December 16 2024 $ 18.Dt FRAME 4 19.Os 20.Sh NAME 21.Nm frame 22.Nd frame protocol family 23.Sh SYNOPSIS 24.Cd "pseudo-device af_frame" 25.Pp 26.In sys/types.h 27.In net/frame.h 28.Sh DESCRIPTION 29The 30.Nm 31protocol family provides an interface for sending and receiving low 32level network interface frames through the normal 33.Xr socket 2 34mechanisms. 35.Pp 36The 37.Nm 38protocol family supports the 39.Dv SOCK_DGRAM 40socket type. 41Only root may create 42.Nm 43protocol family sockets. 44.Pp 45.Nm 46protocol family sockets are designed as an alternative to 47.Xr bpf 4 48for handling low data and packet rate communication protocols. 49Rather than filtering every frame entering the system before the 50network stack, like 51.Xr bpf 4 , 52processing of the 53.Nm 54protocol family runs after the built in protocol handlers in the kernel, 55thus avoiding the overhead. 56For this reason, it is not possible to handle IPv4 or IPv6 packets 57with 58.Nm 59protocol sockets because the kernel network stack consumes them 60before the receive handling for 61.Nm 62sockets is run. 63.Pp 64Sockets can be created in the 65.Nm 66protocol family by using 67.Dv AF_FRAME 68as the 69.Fa domain 70argument to 71.Xr socket 2 . 72The type of interface, as per 73.In net/if_types.h , 74is specified as the socket 75.Fa protocol . 76Currently only Ethernet interfaces are supported. 77.Pp 78Sockets bound to the 79.Nm 80family use the following address structure: 81.Bd -literal -offset indent 82#define FRAME_ADDRLEN 8 83#define FRAME_DATALEN 32 84 85struct sockaddr_frame { 86 uint8_t sfrm_len; 87 uint8_t sfrm_family; 88 uint16_t sfrm_proto; 89 unsigned int sfrm_ifindex; 90 uint8_t sfrm_addr[FRAME_ADDRLEN]; 91 char sfrm_ifname[IFNAMSIZ]; 92 uint8_t sfrm_data[FRAME_DATALEN]; 93}; 94.Ed 95.Pp 96The interface used for transmitting or receiving frames with a 97.Nm 98domain socket may be specified by using an interface index with 99.Fa sfrm_ifindex , 100or by name with 101.Fa sfrm_ifname . 102The use of other 103.Vt struct sockaddr_frame 104fields depends on the type of interface. 105.Ss Ethernet frame sockets 106A 107.Nm 108socket for use with Ethernet interfaces can be created using 109.Dv IFT_ETHER 110as the 111.Fa protocol 112argument to 113.Xr socket 2 : 114.Bd -literal -offset indent 115int sock = socket(AF_FRAME, SOCK_DGRAM, IFT_ETHER); 116.Ed 117.Pp 118The Ethernet protocol is specified with 119.Fa sfrm_proto 120in network byte order. 121Ethernet addresses are specified using the first 6 bytes of 122.Fa sfrm_addr . 123.Pp 124Ethernet 125.Nm 126sockets may receive frames on all interfaces by specifying 0 for 127.Va sfrm_ifindex 128when using 129.Xr bind 2 . 130Similarly, a 131.Dq wildcard 132local address of all zeros can be specified in 133.Fa sfrm_addr . 134.Pp 135An interface and address must be specified when sending Ethernet frames. 136.Pp 137Ethernet sockets support the following 138.Nm 139socket options 140using 141.Dv IFT_ETHER 142as the 143.Fa level 144argument with 145.Xr setsockopt 2 146and 147.Xr getsockopt 2 : 148.Bl -tag -width Ds 149.It Dv FRAME_RECVDSTADDR Ft int 150Enable or disable the reception of the Ethernet destination address as a 151.Vt struct ether_addr 152control message for frames received with 153.Xr recvmsg 2 . 154.It Dv FRAME_RECVPRIO Ft int 155Enable or disable the reception of the mbuf packet priority field as an 156.Vt int 157sized control message for frames received with 158.Xr recvmsg 2 . 159.It Dv FRAME_ADD_MEMBERSHIP Ft struct frame_mreq 160Configure an Ethernet interface to enable reception of 161frames destined to the specified multicast Ethernet address. 162.Bd -literal -offset indent 163struct frame_mreq { 164 unsigned int fmr_ifindex; 165 uint8_t fmr_addr[FRAME_ADDRLEN]; 166 char fmr_ifname[IFNAMSIZ]; 167}; 168.Ed 169.Pp 170An interface must be specified using either 171.Fa fmr_ifindex 172or 173.Fa fmr_ifname . 174The multicast Ethernet address is specified in the first 6 bytes of 175.Fa fmr_addr . 176.It Dv FRAME_DEL_MEMBERSHIP Ft struct frame_mreq 177Configure an Ethernet interface to disable reception of frames destined 178to the specified multicast Ethernet address. 179.It Dv FRAME_SENDPRIO Ft int 180Specify an mbuf priority value between 181.Dv IF_HDRPRIO_MIN 182.Pq 0 183and 184.Dv IF_HDRPRIO_MAX 185.Pq 7 186for frames sent with the Ethernet 187.Nm 188socket, or 189.Dv IF_HDRPRIO_PACKET 190to use the existing mbuf priority value. 191The default is 192.Dv IF_HDRPRIO_PACKET . 193.El 194.Sh EXAMPLES 195To receive LLDP frames on the em0 Ethernet interface: 196.Bd -literal -offset indent 197struct sockaddr_frame sfrm = { 198 .sfrm_family = AF_FRAME, 199 .sfrm_ifname = "em0", 200 .sfrm_proto = htons(ETHERTYPE_LLDP), 201}; 202struct frame_mreq fmr = { 203 .fmr_ifname = "em0", 204 .fmr_addr = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }, 205}; 206int sock; 207 208sock = socket(AF_FRAME, SOCK_DGRAM, IFT_ETHER); 209if (sock == -1) 210 err(1, "ethernet frame socket"); 211if (bind(sock, (struct addrinfo *)&sfrm, sizeof(sfrm)) == -1) 212 err(1, "bind"); 213if (setsockopt(sock, IFT_ETHER, FRAME_ADD_MEMBERSHIP, 214 &fmr, sizeof(fmr)) == -1) 215 err(1, "join lldp multicast group"); 216 217for (;;) { 218 socklen_t sfrmlen = sizeof(sfrm); 219 uint8_t frame[2048]; 220 ssize_t rv; 221 222 rv = recvfrom(sock, frame, sizeof(frame), 0, 223 (struct sockaddr *)&sfrm, &sfrmlen); 224 if (rv == -1) 225 err(1, "lldp recv"); 226 printf("received %zd bytes from %s", rv, 227 ether_ntoa((struct ether_addr *)sfrm->sfrm_addr)); 228} 229.Ed 230.Sh SEE ALSO 231.Xr socket 2 , 232.Xr netintro 4 233.Sh HISTORY 234.Nm 235domain sockets appeared in 236.Ox 7.7 . 237.\" The 238.\" .Ox 239.\" implementation was influenced by the Linux 240.\" .Dv AF_PACKET 241.\" .Dq packet interface on device level 242.\" socket interface, but is not compatible with it. 243.Sh AUTHORS 244.An David Gwynne Aq Mt dlg@openbsd.org . 245