Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / rp-pppoe / src / if.c
blobd85dc97fd1032d11dfc180d14e8232dedf492a48
1 /***********************************************************************
3 * if.c
5 * Implementation of user-space PPPoE redirector for Linux.
7 * Functions for opening a raw socket and reading/writing raw Ethernet frames.
9 * Copyright (C) 2000-2012 by Roaring Penguin Software Inc.
11 * This program may be distributed according to the terms of the GNU
12 * General Public License, version 2 or (at your option) any later version.
14 * LIC: GPL
16 ***********************************************************************/
18 static char const RCSID[] =
19 "$Id$";
21 #include "pppoe.h"
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
27 #ifdef HAVE_NETPACKET_PACKET_H
28 #include <netpacket/packet.h>
29 #elif defined(HAVE_LINUX_IF_PACKET_H)
30 #include <linux/if_packet.h>
31 #endif
33 #ifdef HAVE_NET_ETHERNET_H
34 #include <net/ethernet.h>
35 #endif
37 #ifdef HAVE_ASM_TYPES_H
38 #include <asm/types.h>
39 #endif
41 #ifdef HAVE_SYS_IOCTL_H
42 #include <sys/ioctl.h>
43 #endif
45 #ifdef HAVE_SYSLOG_H
46 #include <syslog.h>
47 #endif
49 #include <errno.h>
50 #include <stdlib.h>
51 #include <string.h>
53 #ifdef HAVE_NET_IF_ARP_H
54 #include <net/if_arp.h>
55 #endif
57 #ifdef USE_DLPI
59 #include <limits.h>
60 #include <fcntl.h>
61 #include <stdlib.h>
62 #include <sys/types.h>
63 #include <sys/time.h>
64 #include <sys/stream.h>
65 #include <sys/stropts.h>
66 #include <sys/dlpi.h>
67 #include <sys/bufmod.h>
68 #include <stdio.h>
69 #include <signal.h>
70 #include <stropts.h>
72 /* function declarations */
74 static void dlpromisconreq( int fd, u_long level);
75 void dlinforeq(int fd);
76 void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen);
77 void dlinfoack(int fd, char *bufp);
78 void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest);
79 void dlattachreq(int fd, u_long ppa);
80 void dlokack(int fd, char *bufp);
81 void dlbindack(int fd, char *bufp);
82 int strioctl(int fd, int cmd, int timout, int len, char *dp);
83 void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller);
84 void sigalrm(int sig);
85 void expecting(int prim, union DL_primitives *dlp);
86 static char *dlprim(u_long prim);
88 /* #define DL_DEBUG */
90 static int dl_abssaplen;
91 static int dl_saplen;
92 static int dl_addrlen;
94 #endif
96 #ifdef USE_BPF
97 #include <net/bpf.h>
98 #include <fcntl.h>
100 static unsigned char *bpfBuffer; /* Packet filter buffer */
101 static int bpfLength = 0; /* Packet filter buffer length */
102 int bpfSize = 0; /* Number of unread bytes in buffer */
103 static int bpfOffset = 0; /* Current offset in bpfBuffer */
104 #endif
106 /* Initialize frame types to RFC 2516 values. Some broken peers apparently
107 use different frame types... sigh... */
109 UINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY;
110 UINT16_t Eth_PPPOE_Session = ETH_PPPOE_SESSION;
112 /**********************************************************************
113 *%FUNCTION: etherType
114 *%ARGUMENTS:
115 * packet -- a received PPPoE packet
116 *%RETURNS:
117 * ethernet packet type (see /usr/include/net/ethertypes.h)
118 *%DESCRIPTION:
119 * Checks the ethernet packet header to determine its type.
120 * We should only be receveing DISCOVERY and SESSION types if the BPF
121 * is set up correctly. Logs an error if an unexpected type is received.
122 * Note that the ethernet type names come from "pppoe.h" and the packet
123 * packet structure names use the LINUX dialect to maintain consistency
124 * with the rest of this file. See the BSD section of "pppoe.h" for
125 * translations of the data structure names.
126 ***********************************************************************/
127 UINT16_t
128 etherType(PPPoEPacket *packet)
130 UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);
131 if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {
132 syslog(LOG_ERR, "Invalid ether type 0x%x", type);
134 return type;
137 #ifdef USE_BPF
138 /**********************************************************************
139 *%FUNCTION: getHWaddr
140 *%ARGUMENTS:
141 * ifname -- name of interface
142 * hwaddr -- buffer for ehthernet address
143 *%RETURNS:
144 * Nothing
145 *%DESCRIPTION:
146 * Locates the Ethernet hardware address for an interface.
147 ***********************************************************************/
148 void
149 getHWaddr(int sock, char const *ifname, unsigned char *hwaddr)
151 char inbuf[8192];
152 const struct sockaddr_dl *sdl;
153 struct ifconf ifc;
154 struct ifreq ifreq, *ifr;
155 int i;
156 int found = 0;
158 ifc.ifc_len = sizeof(inbuf);
159 ifc.ifc_buf = inbuf;
160 if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
161 fatalSys("SIOCGIFCONF");
163 ifr = ifc.ifc_req;
164 ifreq.ifr_name[0] = '\0';
165 for (i = 0; i < ifc.ifc_len; ) {
166 ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
167 i += sizeof(ifr->ifr_name) +
168 (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
169 ? ifr->ifr_addr.sa_len
170 : sizeof(struct sockaddr));
171 if (ifr->ifr_addr.sa_family == AF_LINK) {
172 sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
173 if ((sdl->sdl_type == IFT_ETHER) &&
174 (sdl->sdl_alen == ETH_ALEN) &&
175 !strncmp(ifname, ifr->ifr_name, sizeof(ifr->ifr_name))) {
176 if (found) {
177 char buffer[256];
178 sprintf(buffer, "interface %.16s has more than one ethernet address", ifname);
179 rp_fatal(buffer);
180 } else {
181 found = 1;
182 memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);
187 if (!found) {
188 char buffer[256];
189 sprintf(buffer, "interface %.16s has no ethernet address", ifname);
190 rp_fatal(buffer);
194 /**********************************************************************
195 *%FUNCTION: initFilter
196 *%ARGUMENTS:
197 * fd -- file descriptor of BSD device
198 * type -- Ethernet frame type (0 for watch mode)
199 * hwaddr -- buffer with ehthernet address
200 *%RETURNS:
201 * Nothing
202 *%DESCRIPTION:
203 * Initializes the packet filter rules.
204 ***********************************************************************/
205 void
206 initFilter(int fd, UINT16_t type, unsigned char *hwaddr)
208 /* Packet Filter Instructions:
209 * Note that the ethernet type names come from "pppoe.h" and are
210 * used here to maintain consistency with the rest of this file. */
211 static struct bpf_insn bpfRun[] = { /* run PPPoE */
212 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), /* ethernet type */
213 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0),
214 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9),
215 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
216 #define PPPOE_BCAST_CMPW 4 /* offset of word compare */
217 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2),
218 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
219 #define PPPOE_BCAST_CMPH 6 /* offset of 1/2 word compare */
220 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0),
221 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */
222 #define PPPOE_FILTER_CMPW 8 /* offset of word compare */
223 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),
224 BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */
225 #define PPPOE_FILTER_CMPH 10 /* offset of 1/rd compare */
226 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
227 BPF_STMT(BPF_RET+BPF_K, (u_int) -1), /* keep packet */
228 BPF_STMT(BPF_RET+BPF_K, 0), /* drop packet */
231 /* Fix the potentially varying parts */
232 bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
233 bpfRun[1].jt = 5;
234 bpfRun[1].jf = 0;
235 bpfRun[1].k = Eth_PPPOE_Session;
237 bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
238 bpfRun[2].jt = 0;
239 bpfRun[2].jf = 9;
240 bpfRun[2].k = Eth_PPPOE_Discovery;
243 struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])];
244 struct bpf_program bpfProgram;
245 memcpy(bpfInsn, bpfRun, sizeof(bpfRun));
246 bpfInsn[PPPOE_BCAST_CMPW].k = ((0xff << 24) | (0xff << 16) |
247 (0xff << 8) | 0xff);
248 bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff << 8) | 0xff);
249 bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) |
250 (hwaddr[2] << 8) | hwaddr[3]);
251 bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]);
252 bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));
253 bpfProgram.bf_insns = &bpfInsn[0];
255 /* Apply the filter */
256 if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {
257 fatalSys("ioctl(BIOCSETF)");
262 /**********************************************************************
263 *%FUNCTION: openInterface
264 *%ARGUMENTS:
265 * ifname -- name of interface
266 * type -- Ethernet frame type (0 for any frame type)
267 * hwaddr -- if non-NULL, set to the hardware address
268 *%RETURNS:
269 * A file descriptor for talking with the Ethernet card. Exits on error.
270 * Note that the Linux version of this routine returns a socket instead.
271 *%DESCRIPTION:
272 * Opens a BPF on an interface for all PPPoE traffic (discovery and
273 * session). If 'type' is 0, uses promiscuous mode to watch any PPPoE
274 * traffic on this network.
275 ***********************************************************************/
277 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
279 static int fd = -1;
280 char bpfName[32];
281 u_int optval;
282 struct bpf_version bpf_ver;
283 struct ifreq ifr;
284 int sock;
285 int i;
287 /* BSD only opens one socket for both Discovery and Session packets */
288 if (fd >= 0) {
289 return fd;
292 /* Find a free BPF device */
293 for (i = 0; i < 256; i++) {
294 sprintf(bpfName, "/dev/bpf%d", i);
295 if (((fd = open(bpfName, O_RDWR, 0)) >= 0) ||
296 (errno != EBUSY)) {
297 break;
300 if (fd < 0) {
301 switch (errno) {
302 case EACCES: /* permission denied */
304 char buffer[256];
305 sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName);
306 rp_fatal(buffer);
308 break;
309 case EBUSY:
310 case ENOENT: /* no such file */
311 if (i == 0) {
312 rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)");
313 } else {
314 rp_fatal("All /dev/bpf* devices are in use");
316 break;
318 fatalSys(bpfName);
321 if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
322 fatalSys("socket");
325 /* Check that the interface is up */
326 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
327 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
328 fatalSys("ioctl(SIOCGIFFLAGS)");
330 if ((ifr.ifr_flags & IFF_UP) == 0) {
331 char buffer[256];
332 sprintf(buffer, "Interface %.16s is not up", ifname);
333 rp_fatal(buffer);
336 /* Fill in hardware address and initialize the packet filter rules */
337 if (hwaddr == NULL) {
338 rp_fatal("openInterface: no hwaddr arg.");
340 getHWaddr(sock, ifname, hwaddr);
341 initFilter(fd, type, hwaddr);
343 /* Sanity check on MTU -- apparently does not work on OpenBSD */
344 #if !defined(__OpenBSD__)
345 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
346 if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) {
347 fatalSys("ioctl(SIOCGIFMTU)");
349 if (ifr.ifr_mtu < ETH_DATA_LEN) {
350 char buffer[256];
351 sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
352 ifname, ifr.ifr_mtu, ETH_DATA_LEN);
353 printErr(buffer);
355 #endif
357 /* done with the socket */
358 if (close(sock) < 0) {
359 fatalSys("close");
362 /* Check the BPF version number */
363 if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) {
364 fatalSys("ioctl(BIOCVERSION)");
366 if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) ||
367 (bpf_ver.bv_minor < BPF_MINOR_VERSION)) {
368 char buffer[256];
369 sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)",
370 BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
371 bpf_ver.bv_major, bpf_ver.bv_minor);
372 rp_fatal(buffer);
375 /* allocate a receive packet buffer */
376 if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) {
377 fatalSys("ioctl(BIOCGBLEN)");
379 if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) {
380 rp_fatal("malloc");
383 /* reads should return as soon as there is a packet available */
384 optval = 1;
385 if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) {
386 fatalSys("ioctl(BIOCIMMEDIATE)");
389 /* Bind the interface to the filter */
390 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
391 if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
392 char buffer[256];
393 sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s",
394 ifname);
395 rp_fatal(buffer);
398 syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",
399 ifname,
400 hwaddr[0], hwaddr[1], hwaddr[2],
401 hwaddr[3], hwaddr[4], hwaddr[5],
402 bpfName, bpfLength);
403 return fd;
406 #endif /* USE_BPF */
408 #ifdef USE_LINUX_PACKET
409 /**********************************************************************
410 *%FUNCTION: openInterface
411 *%ARGUMENTS:
412 * ifname -- name of interface
413 * type -- Ethernet frame type
414 * hwaddr -- if non-NULL, set to the hardware address
415 * mtu -- if non-NULL, set to the MTU
416 *%RETURNS:
417 * A raw socket for talking to the Ethernet card. Exits on error.
418 *%DESCRIPTION:
419 * Opens a raw Ethernet socket
420 ***********************************************************************/
422 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr, UINT16_t *mtu)
424 int optval=1;
425 int fd;
426 struct ifreq ifr;
427 int domain, stype;
429 #ifdef HAVE_STRUCT_SOCKADDR_LL
430 struct sockaddr_ll sa;
431 #else
432 struct sockaddr sa;
433 #endif
435 memset(&sa, 0, sizeof(sa));
437 #ifdef HAVE_STRUCT_SOCKADDR_LL
438 domain = PF_PACKET;
439 stype = SOCK_RAW;
440 #else
441 domain = PF_INET;
442 stype = SOCK_PACKET;
443 #endif
445 if ((fd = socket(domain, stype, htons(type))) < 0) {
446 /* Give a more helpful message for the common error case */
447 if (errno == EPERM) {
448 rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
450 fatalSys("socket");
453 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
454 fatalSys("setsockopt");
457 /* Fill in hardware address */
458 if (hwaddr) {
459 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
460 if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
461 fatalSys("ioctl(SIOCGIFHWADDR)");
463 memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
464 #ifdef ARPHRD_ETHER
465 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
466 char buffer[256];
467 sprintf(buffer, "Interface %.16s is not Ethernet", ifname);
468 rp_fatal(buffer);
470 #endif
471 if (NOT_UNICAST(hwaddr)) {
472 char buffer[256];
473 sprintf(buffer,
474 "Interface %.16s has broadcast/multicast MAC address??",
475 ifname);
476 rp_fatal(buffer);
480 /* Sanity check on MTU */
481 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
482 if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
483 fatalSys("ioctl(SIOCGIFMTU)");
485 if (ifr.ifr_mtu < ETH_DATA_LEN) {
486 char buffer[256];
487 sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.",
488 ifname, ifr.ifr_mtu, ETH_DATA_LEN);
489 printErr(buffer);
491 if (mtu) *mtu = ifr.ifr_mtu;
493 #ifdef HAVE_STRUCT_SOCKADDR_LL
494 /* Get interface index */
495 sa.sll_family = AF_PACKET;
496 sa.sll_protocol = htons(type);
498 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
499 if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
500 fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
502 sa.sll_ifindex = ifr.ifr_ifindex;
504 #else
505 strcpy(sa.sa_data, ifname);
506 #endif
508 /* We're only interested in packets on specified interface */
509 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
510 fatalSys("bind");
513 return fd;
516 #endif /* USE_LINUX */
518 /***********************************************************************
519 *%FUNCTION: sendPacket
520 *%ARGUMENTS:
521 * sock -- socket to send to
522 * pkt -- the packet to transmit
523 * size -- size of packet (in bytes)
524 *%RETURNS:
525 * 0 on success; -1 on failure
526 *%DESCRIPTION:
527 * Transmits a packet
528 ***********************************************************************/
530 sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
532 #if defined(USE_BPF)
533 if (write(sock, pkt, size) < 0) {
534 sysErr("write (sendPacket)");
535 return -1;
537 #elif defined(HAVE_STRUCT_SOCKADDR_LL)
538 if (send(sock, pkt, size, 0) < 0 && (errno != ENOBUFS)) {
539 sysErr("send (sendPacket)");
540 return -1;
542 #else
543 #ifdef USE_DLPI
545 #define ABS(x) ((x) < 0 ? -(x) : (x))
547 u_char addr[MAXDLADDR];
548 u_char phys[MAXDLADDR];
549 u_char sap[MAXDLADDR];
550 u_char xmitbuf[MAXDLBUF];
551 int data_size;
553 short tmp_sap;
555 tmp_sap = htons(pkt->ethHdr.h_proto);
556 data_size = size - sizeof(struct ethhdr);
558 memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL);
559 memcpy((char *)sap, (char *)&tmp_sap, sizeof(ushort_t));
560 memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size);
562 if (dl_saplen > 0) { /* order is sap+phys */
563 (void) memcpy((char*)addr, (char*)&sap, dl_abssaplen);
564 (void) memcpy((char*)addr+dl_abssaplen, (char*)phys, ETHERADDRL);
565 } else { /* order is phys+sap */
566 (void) memcpy((char*)addr, (char*)phys, ETHERADDRL);
567 (void) memcpy((char*)addr+ETHERADDRL, (char*)&sap, dl_abssaplen);
570 #ifdef DL_DEBUG
571 printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n",
572 addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],
573 addr[6],addr[7]);
574 #endif
576 dlunitdatareq(sock, addr, dl_addrlen, 0, 0, xmitbuf, data_size);
580 #else
581 struct sockaddr sa;
583 if (!conn) {
584 rp_fatal("relay and server not supported on Linux 2.0 kernels");
586 strcpy(sa.sa_data, conn->ifName);
587 if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
588 sysErr("sendto (sendPacket)");
589 return -1;
591 #endif
592 #endif
593 return 0;
596 #ifdef USE_BPF
597 /***********************************************************************
598 *%FUNCTION: clearPacketHeader
599 *%ARGUMENTS:
600 * pkt -- packet that needs its head clearing
601 *%RETURNS:
602 * nothing
603 *%DESCRIPTION:
604 * Clears a PPPoE packet header after a truncated packet has been
605 * received. Insures that the packet will fail any integrity tests
606 * and will be discarded by upper level routines. Also resets the
607 * bpfSize and bpfOffset variables to force a new read on the next
608 * call to receivePacket().
609 ***********************************************************************/
610 void
611 clearPacketHeader(PPPoEPacket *pkt)
613 bpfSize = bpfOffset = 0;
614 memset(pkt, 0, HDR_SIZE);
616 #endif
618 /***********************************************************************
619 *%FUNCTION: receivePacket
620 *%ARGUMENTS:
621 * sock -- socket to read from
622 * pkt -- place to store the received packet
623 * size -- set to size of packet in bytes
624 *%RETURNS:
625 * >= 0 if all OK; < 0 if error
626 *%DESCRIPTION:
627 * Receives a packet
628 ***********************************************************************/
630 receivePacket(int sock, PPPoEPacket *pkt, int *size)
632 #ifdef USE_BPF
633 struct bpf_hdr hdr;
634 int seglen, copylen;
636 if (bpfSize <= 0) {
637 bpfOffset = 0;
638 if ((bpfSize = read(sock, bpfBuffer, bpfLength)) < 0) {
639 sysErr("read (receivePacket)");
640 return -1;
643 if (bpfSize < sizeof(hdr)) {
644 syslog(LOG_ERR, "Truncated bpf packet header: len=%d", bpfSize);
645 clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
646 return 0;
648 memcpy(&hdr, bpfBuffer + bpfOffset, sizeof(hdr));
649 if (hdr.bh_caplen != hdr.bh_datalen) {
650 syslog(LOG_ERR, "Truncated bpf packet: caplen=%d, datalen=%d",
651 hdr.bh_caplen, hdr.bh_datalen);
652 clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
653 return 0;
655 seglen = hdr.bh_hdrlen + hdr.bh_caplen;
656 if (seglen > bpfSize) {
657 syslog(LOG_ERR, "Truncated bpf packet: seglen=%d, bpfSize=%d",
658 seglen, bpfSize);
659 clearPacketHeader(pkt); /* resets bpfSize and bpfOffset */
660 return 0;
662 seglen = BPF_WORDALIGN(seglen);
663 *size = copylen = ((hdr.bh_caplen < sizeof(PPPoEPacket)) ?
664 hdr.bh_caplen : sizeof(PPPoEPacket));
665 memcpy(pkt, bpfBuffer + bpfOffset + hdr.bh_hdrlen, copylen);
666 if (seglen >= bpfSize) {
667 bpfSize = bpfOffset = 0;
668 } else {
669 bpfSize -= seglen;
670 bpfOffset += seglen;
672 #else
673 #ifdef USE_DLPI
674 struct strbuf data;
675 int flags = 0;
676 int retval;
678 data.buf = (char *) pkt;
679 data.maxlen = MAXDLBUF;
680 data.len = 0;
682 if ((retval = getmsg(sock, NULL, &data, &flags)) < 0) {
683 sysErr("read (receivePacket)");
684 return -1;
687 *size = data.len;
689 #else
690 if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
691 sysErr("recv (receivePacket)");
692 return -1;
694 #endif
695 #endif
696 return 0;
699 #ifdef USE_DLPI
700 /**********************************************************************
701 *%FUNCTION: openInterface
702 *%ARGUMENTS:
703 * ifname -- name of interface
704 * type -- Ethernet frame type
705 * hwaddr -- if non-NULL, set to the hardware address
706 *%RETURNS:
707 * A raw socket for talking to the Ethernet card. Exits on error.
708 *%DESCRIPTION:
709 * Opens a raw Ethernet socket
710 ***********************************************************************/
712 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
714 int fd;
715 long buf[MAXDLBUF];
717 union DL_primitives *dlp;
719 char base_dev[PATH_MAX];
720 int ppa;
722 if(strlen(ifname) > PATH_MAX) {
723 rp_fatal("socket: Interface name too long");
726 if (strlen(ifname) < 2) {
727 rp_fatal("socket: Interface name too short");
730 ppa = atoi(&ifname[strlen(ifname)-1]);
731 strncpy(base_dev, ifname, PATH_MAX);
732 base_dev[strlen(base_dev)-1] = '\0';
734 /* rearranged order of DLPI code - delphys 20010803 */
735 dlp = (union DL_primitives*) buf;
737 if ( (fd = open(base_dev, O_RDWR)) < 0) {
738 /* Give a more helpful message for the common error case */
739 if (errno == EPERM) {
740 rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
742 /* Common error is to omit /dev/ */
743 if (errno == ENOENT) {
744 char ifname[512];
745 snprintf(ifname, sizeof(ifname), "/dev/%s", base_dev);
746 if ((fd = open(ifname, O_RDWR)) < 0) {
747 if (errno == EPERM) {
748 rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
753 if (fd < 0) {
754 fatalSys("socket");
757 /* rearranged order of DLPI code - delphys 20010803 */
758 dlattachreq(fd, ppa);
759 dlokack(fd, (char *)buf);
761 dlbindreq(fd, type, 0, DL_CLDLS, 0, 0);
762 dlbindack(fd, (char *)buf);
764 dlinforeq(fd);
765 dlinfoack(fd, (char *)buf);
767 dl_abssaplen = ABS(dlp->info_ack.dl_sap_length);
768 dl_saplen = dlp->info_ack.dl_sap_length;
769 if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen))
770 fatalSys("invalid destination physical address length");
771 dl_addrlen = dl_abssaplen + ETHERADDRL;
773 /* ethernet address retrieved as part of DL_INFO_ACK - delphys 20010803 */
774 memcpy(hwaddr, (u_char*)((char*)(dlp) + (int)(dlp->info_ack.dl_addr_offset)), ETHERADDRL);
776 if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) {
777 fatalSys("DLIOCRAW");
780 if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH");
782 return fd;
785 /* cloned from dlcommon.c */
787 static void
788 dlpromisconreq(int fd, u_long level)
790 dl_promiscon_req_t promiscon_req;
791 struct strbuf ctl;
792 int flags;
794 promiscon_req.dl_primitive = DL_PROMISCON_REQ;
795 promiscon_req.dl_level = level;
797 ctl.maxlen = 0;
798 ctl.len = sizeof (promiscon_req);
799 ctl.buf = (char *) &promiscon_req;
801 flags = 0;
803 if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
804 fatalSys("dlpromiscon: putmsg");
808 void dlinforeq(int fd)
810 dl_info_req_t info_req;
811 struct strbuf ctl;
812 int flags;
814 info_req.dl_primitive = DL_INFO_REQ;
816 ctl.maxlen = 0;
817 ctl.len = sizeof (info_req);
818 ctl.buf = (char *) &info_req;
820 flags = RS_HIPRI;
822 if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
823 fatalSys("dlinforeq: putmsg");
826 void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen)
828 long buf[MAXDLBUF];
829 union DL_primitives *dlp;
830 struct strbuf data, ctl;
832 dlp = (union DL_primitives*) buf;
834 dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
835 dlp->unitdata_req.dl_dest_addr_length = addrlen;
836 dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
837 dlp->unitdata_req.dl_priority.dl_min = minpri;
838 dlp->unitdata_req.dl_priority.dl_max = maxpri;
840 (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);
842 ctl.maxlen = 0;
843 ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
844 ctl.buf = (char *) buf;
846 data.maxlen = 0;
847 data.len = datalen;
848 data.buf = (char *) datap;
850 if (putmsg(fd, &ctl, &data, 0) < 0)
851 fatalSys("dlunitdatareq: putmsg");
854 void dlinfoack(int fd, char *bufp)
856 union DL_primitives *dlp;
857 struct strbuf ctl;
858 int flags;
860 ctl.maxlen = MAXDLBUF;
861 ctl.len = 0;
862 ctl.buf = bufp;
864 strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack");
866 dlp = (union DL_primitives *) ctl.buf;
868 expecting(DL_INFO_ACK, dlp);
870 if (ctl.len < sizeof (dl_info_ack_t)) {
871 char buffer[256];
872 sprintf(buffer, "dlinfoack: response ctl.len too short: %d", ctl.len);
873 rp_fatal(buffer);
876 if (flags != RS_HIPRI)
877 rp_fatal("dlinfoack: DL_INFO_ACK was not M_PCPROTO");
879 if (ctl.len < sizeof (dl_info_ack_t)) {
880 char buffer[256];
881 sprintf(buffer, "dlinfoack: short response ctl.len: %d", ctl.len);
882 rp_fatal(buffer);
886 void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest)
888 dl_bind_req_t bind_req;
889 struct strbuf ctl;
890 int flags;
892 bind_req.dl_primitive = DL_BIND_REQ;
893 bind_req.dl_sap = sap;
894 bind_req.dl_max_conind = max_conind;
895 bind_req.dl_service_mode = service_mode;
896 bind_req.dl_conn_mgmt = conn_mgmt;
897 bind_req.dl_xidtest_flg = xidtest;
899 ctl.maxlen = 0;
900 ctl.len = sizeof (bind_req);
901 ctl.buf = (char *) &bind_req;
903 flags = 0;
905 if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
906 fatalSys("dlbindreq: putmsg");
909 void dlattachreq(int fd, u_long ppa)
911 dl_attach_req_t attach_req;
912 struct strbuf ctl;
913 int flags;
915 attach_req.dl_primitive = DL_ATTACH_REQ;
916 attach_req.dl_ppa = ppa;
918 ctl.maxlen = 0;
919 ctl.len = sizeof (attach_req);
920 ctl.buf = (char *) &attach_req;
922 flags = 0;
924 if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
925 fatalSys("dlattachreq: putmsg");
928 void dlokack(int fd, char *bufp)
930 union DL_primitives *dlp;
931 struct strbuf ctl;
932 int flags;
934 ctl.maxlen = MAXDLBUF;
935 ctl.len = 0;
936 ctl.buf = bufp;
938 strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack");
940 dlp = (union DL_primitives *) ctl.buf;
942 expecting(DL_OK_ACK, dlp);
944 if (ctl.len < sizeof (dl_ok_ack_t)) {
945 char buffer[256];
946 sprintf(buffer, "dlokack: response ctl.len too short: %d", ctl.len);
947 rp_fatal(buffer);
950 if (flags != RS_HIPRI)
951 rp_fatal("dlokack: DL_OK_ACK was not M_PCPROTO");
953 if (ctl.len < sizeof (dl_ok_ack_t)) {
954 char buffer[256];
955 sprintf(buffer, "dlokack: short response ctl.len: %d", ctl.len);
956 rp_fatal(buffer);
960 void dlbindack(int fd, char *bufp)
962 union DL_primitives *dlp;
963 struct strbuf ctl;
964 int flags;
966 ctl.maxlen = MAXDLBUF;
967 ctl.len = 0;
968 ctl.buf = bufp;
970 strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack");
972 dlp = (union DL_primitives *) ctl.buf;
974 expecting(DL_BIND_ACK, dlp);
976 if (flags != RS_HIPRI)
977 rp_fatal("dlbindack: DL_OK_ACK was not M_PCPROTO");
979 if (ctl.len < sizeof (dl_bind_ack_t)) {
980 char buffer[256];
981 sprintf(buffer, "dlbindack: short response ctl.len: %d", ctl.len);
982 rp_fatal(buffer);
986 int strioctl(int fd, int cmd, int timout, int len, char *dp)
988 struct strioctl sioc;
989 int rc;
991 sioc.ic_cmd = cmd;
992 sioc.ic_timout = timout;
993 sioc.ic_len = len;
994 sioc.ic_dp = dp;
995 rc = ioctl(fd, I_STR, &sioc);
997 if (rc < 0)
998 return (rc);
999 else
1000 return (sioc.ic_len);
1003 void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller)
1005 int rc;
1006 static char errmsg[80];
1009 * Start timer.
1011 (void) signal(SIGALRM, sigalrm);
1012 if (alarm(MAXWAIT) < 0) {
1013 (void) sprintf(errmsg, "%s: alarm", caller);
1014 fatalSys(errmsg);
1018 * Set flags argument and issue getmsg().
1020 *flagsp = 0;
1021 if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
1022 (void) sprintf(errmsg, "%s: getmsg", caller);
1023 fatalSys(errmsg);
1027 * Stop timer.
1029 if (alarm(0) < 0) {
1030 (void) sprintf(errmsg, "%s: alarm", caller);
1031 fatalSys(errmsg);
1035 * Check for MOREDATA and/or MORECTL.
1037 if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
1038 char buffer[256];
1039 sprintf(buffer, "%s: MORECTL|MOREDATA", caller);
1040 rp_fatal(buffer);
1043 if (rc & MORECTL) {
1044 char buffer[256];
1045 sprintf(buffer, "%s: MORECTL", caller);
1046 rp_fatal(buffer);
1049 if (rc & MOREDATA) {
1050 char buffer[256];
1051 sprintf(buffer, "%s: MOREDATA", caller);
1052 rp_fatal(buffer);
1056 * Check for at least sizeof (long) control data portion.
1058 if (ctlp->len < sizeof (long)) {
1059 char buffer[256];
1060 sprintf(buffer, "getmsg: control portion length < sizeof (long): %d", ctlp->len);
1061 rp_fatal(buffer);
1065 void sigalrm(int sig)
1067 (void) rp_fatal("sigalrm: TIMEOUT");
1070 void expecting(int prim, union DL_primitives *dlp)
1072 if (dlp->dl_primitive != (u_long)prim) {
1073 char buffer[256];
1074 sprintf(buffer, "expected %s got %s", dlprim(prim), dlprim(dlp->dl_primitive));
1075 rp_fatal(buffer);
1076 exit(1);
1080 static char *
1081 dlprim(u_long prim)
1083 static char primbuf[80];
1085 switch ((int)prim) {
1086 CASERET(DL_INFO_REQ);
1087 CASERET(DL_INFO_ACK);
1088 CASERET(DL_ATTACH_REQ);
1089 CASERET(DL_DETACH_REQ);
1090 CASERET(DL_BIND_REQ);
1091 CASERET(DL_BIND_ACK);
1092 CASERET(DL_UNBIND_REQ);
1093 CASERET(DL_OK_ACK);
1094 CASERET(DL_ERROR_ACK);
1095 CASERET(DL_SUBS_BIND_REQ);
1096 CASERET(DL_SUBS_BIND_ACK);
1097 CASERET(DL_UNITDATA_REQ);
1098 CASERET(DL_UNITDATA_IND);
1099 CASERET(DL_UDERROR_IND);
1100 CASERET(DL_UDQOS_REQ);
1101 CASERET(DL_CONNECT_REQ);
1102 CASERET(DL_CONNECT_IND);
1103 CASERET(DL_CONNECT_RES);
1104 CASERET(DL_CONNECT_CON);
1105 CASERET(DL_TOKEN_REQ);
1106 CASERET(DL_TOKEN_ACK);
1107 CASERET(DL_DISCONNECT_REQ);
1108 CASERET(DL_DISCONNECT_IND);
1109 CASERET(DL_RESET_REQ);
1110 CASERET(DL_RESET_IND);
1111 CASERET(DL_RESET_RES);
1112 CASERET(DL_RESET_CON);
1113 default:
1114 (void) sprintf(primbuf, "unknown primitive 0x%lx", prim);
1115 return (primbuf);
1119 #endif /* USE_DLPI */