OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / rp-pppoe / if.c
1 /***********************************************************************
2 *
3 * if.c
4 *
5 * Implementation of user-space PPPoE redirector for Linux.
6 *
7 * Functions for opening a raw socket and reading/writing raw Ethernet frames.
8 *
9 * Copyright (C) 2000 by Roaring Penguin Software Inc.
10 *
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.
13 *
14 ***********************************************************************/
15
16 static char const RCSID[] =
17 "$Id: if.c,v 1.16 2000/09/11 16:12:19 dfs Exp $";
18
19 #include "pppoe.h"
20
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24
25 #ifdef HAVE_NETPACKET_PACKET_H
26 #include <netpacket/packet.h>
27 #elif defined(HAVE_LINUX_IF_PACKET_H)
28 #include <linux/if_packet.h>
29 #endif
30
31 #ifdef HAVE_NET_ETHERNET_H
32 #include <net/ethernet.h>
33 #endif
34
35 #ifdef HAVE_ASM_TYPES_H
36 #include <asm/types.h>
37 #endif
38
39 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
41 #endif
42
43 #ifdef HAVE_SYSLOG_H
44 #include <syslog.h>
45 #endif
46
47 #include <errno.h>
48 #include <stdlib.h>
49 #include <string.h>
50
51 #ifdef USE_DLPI
52
53 #include <limits.h>
54 #include <fcntl.h>
55 #include <stdlib.h>
56 #include <sys/types.h>
57 #include <sys/time.h>
58 #include <sys/stream.h>
59 #include <sys/stropts.h>
60 #include <sys/dlpi.h>
61 #include <sys/bufmod.h>
62 #include <stdio.h>
63 #include <signal.h>
64 #include <stropts.h>
65
66 /* function declarations */
67
68 void dlpromisconreq( int fd, u_long  level);
69 void dlinforeq(int fd);
70 void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen);
71 void dlinfoack(int fd, char *bufp);
72 void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest);
73 void dlattachreq(int fd, u_long ppa);
74 void dlokack(int fd, char *bufp);
75 void dlbindack(int fd, char *bufp);
76 int strioctl(int fd, int cmd, int timout, int len, char *dp);
77 void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller);
78 void sigalrm(int sig);
79 void expecting(int prim, union DL_primitives *dlp);
80 char *dlprim(u_long prim);
81
82 /* #define DL_DEBUG */
83
84 static  int     dl_abssaplen;
85 static  int     dl_saplen;
86 static  int     dl_addrlen;
87
88 #endif
89
90 #ifdef USE_BPF
91 #include <net/bpf.h>
92 #include <fcntl.h>
93
94 unsigned char *bpfBuffer;       /* Packet filter buffer */
95 int bpfLength = 0;              /* Packet filter buffer length */
96 int bpfSize = 0;                /* Number of unread bytes in buffer */
97 int bpfOffset = 0;              /* Current offset in bpfBuffer */
98 #endif
99
100 extern char *IfName;    /* For brain-dead Linux 2.0-kernel SOCK_PACKET */
101
102 /* Initialize frame types to RFC 2516 values.  Some broken peers apparently
103    use different frame types... sigh... */
104
105 UINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY;
106 UINT16_t Eth_PPPOE_Session   = ETH_PPPOE_SESSION;
107
108 /**********************************************************************
109 *%FUNCTION: etherType
110 *%ARGUMENTS:
111 * packet -- a received PPPoE packet
112 *%RETURNS:
113 * ethernet packet type (see /usr/include/net/ethertypes.h)
114 *%DESCRIPTION:
115 * Checks the ethernet packet header to determine its type.
116 * We should only be receveing DISCOVERY and SESSION types if the BPF
117 * is set up correctly.  Logs an error if an unexpected type is received.
118 * Note that the ethernet type names come from "pppoe.h" and the packet
119 * packet structure names use the LINUX dialect to maintain consistency
120 * with the rest of this file.  See the BSD section of "pppoe.h" for
121 * translations of the data structure names.
122 ***********************************************************************/
123 UINT16_t
124 etherType(struct PPPoEPacket *packet)
125 {
126     UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);
127     if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {
128         syslog(LOG_ERR, "Invalid ether type 0x%x", type);
129     }
130     return type;
131 }
132
133 #ifdef USE_BPF
134 /**********************************************************************
135 *%FUNCTION: getHWaddr
136 *%ARGUMENTS:
137 * ifname -- name of interface
138 * hwaddr -- buffer for ehthernet address
139 *%RETURNS:
140 * Nothing
141 *%DESCRIPTION:
142 * Locates the Ethernet hardware address for an interface.
143 ***********************************************************************/
144 void
145 getHWaddr(int sock, char const *ifname, unsigned char *hwaddr)
146 {
147     char inbuf[8192];
148     const struct sockaddr_dl *sdl;
149     struct ifconf ifc;
150     struct ifreq ifreq, *ifr;
151     int i;
152     int found = 0;
153
154     ifc.ifc_len = sizeof(inbuf);
155     ifc.ifc_buf = inbuf;
156     if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
157         fatalSys("SIOCGIFCONF");
158     }
159     ifr = ifc.ifc_req;
160     ifreq.ifr_name[0] = '\0';
161     for (i = 0; i < ifc.ifc_len; ) {
162         ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
163         i += sizeof(ifr->ifr_name) +
164                     (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
165                     ? ifr->ifr_addr.sa_len
166                     : sizeof(struct sockaddr));
167         if (ifr->ifr_addr.sa_family == AF_LINK) {
168             sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
169             if ((sdl->sdl_type == IFT_ETHER) &&
170                 (sdl->sdl_alen == ETH_ALEN) &&
171                 !strncmp(ifname, ifr->ifr_name, sizeof(ifr->ifr_name))) {
172                 if (found) {
173                     char buffer[256];
174                     sprintf(buffer, "interface %.16s has more than one ethernet address", ifname);
175                     fatal(buffer);
176                 } else {
177                     found = 1;
178                     memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);
179                 }
180             }
181         }
182     }
183     if (!found) {
184         char buffer[256];
185         sprintf(buffer, "interface %.16s has no ethernet address", ifname);
186         fatal(buffer);
187     }
188 }
189
190 /**********************************************************************
191 *%FUNCTION: initFilter
192 *%ARGUMENTS:
193 * fd -- file descriptor of BSD device
194 * type -- Ethernet frame type (0 for watch mode)
195 * hwaddr -- buffer with ehthernet address
196 *%RETURNS:
197 * Nothing
198 *%DESCRIPTION:
199 * Initializes the packet filter rules.
200 ***********************************************************************/
201 void
202 initFilter(int fd, UINT16_t type, unsigned char *hwaddr)
203 {
204     /* Packet Filter Instructions:
205      * Note that the ethernet type names come from "pppoe.h" and are
206      * used here to maintain consistency with the rest of this file. */
207     static struct bpf_insn bpfRun[] = {         /* run PPPoE */
208         BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),     /* ethernet type */
209         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 1, 0),
210         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 5),
211         BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0),      /* first word of dest. addr */
212 #define PPPOE_FILTER_CMPW 4                     /* offset of word compare */
213         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),
214         BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4),      /* next 1/2 word of dest. */
215 #define PPPOE_FILTER_CMPH 6                     /* offset of 1/2 word compare */
216         BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
217         BPF_STMT(BPF_RET+BPF_K, (u_int) -1),    /* keep packet */
218         BPF_STMT(BPF_RET+BPF_K, 0),             /* drop packet */
219     };
220
221     /* Fix the potentially varying parts */
222     bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
223     bpfRun[1].jt   = 1;
224     bpfRun[1].jf   = 0;
225     bpfRun[1].k    = Eth_PPPOE_Session;
226
227     bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
228     bpfRun[2].jt   = 0;
229     bpfRun[2].jf   = 5;
230     bpfRun[2].k    = Eth_PPPOE_Discovery;
231
232     {
233       struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])];
234       struct bpf_program bpfProgram;
235       memcpy(bpfInsn, bpfRun, sizeof(bpfRun));
236       bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) |
237                                       (hwaddr[2] << 8) | hwaddr[3]);
238       bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]);
239       bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));
240       bpfProgram.bf_insns = &bpfInsn[0];
241       
242       /* Apply the filter */
243       if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {
244         fatalSys("ioctl(BIOCSETF)");
245       }
246     }
247 }
248
249 /**********************************************************************
250 *%FUNCTION: openInterface
251 *%ARGUMENTS:
252 * ifname -- name of interface
253 * type -- Ethernet frame type (0 for any frame type)
254 * hwaddr -- if non-NULL, set to the hardware address
255 *%RETURNS:
256 * A file descriptor for talking with the Ethernet card.  Exits on error.
257 * Note that the Linux version of this routine returns a socket instead.
258 *%DESCRIPTION:
259 * Opens a BPF on an interface for all PPPoE traffic (discovery and
260 * session).  If 'type' is 0, uses promiscuous mode to watch any PPPoE
261 * traffic on this network.
262 ***********************************************************************/
263 int
264 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
265 {
266     static int fd = -1;
267     char bpfName[32];
268     u_int optval;
269     struct bpf_version bpf_ver;
270     struct ifreq ifr;
271     int sock;
272     int i;
273
274     /* BSD only opens one socket for both Discovery and Session packets */
275     if (fd >= 0) {
276         return fd;
277     }
278
279     /* Find a free BPF device */
280     for (i = 0; i < 256; i++) {
281         sprintf(bpfName, "/dev/bpf%d", i);
282         if (((fd = open(bpfName, O_RDWR, 0)) >= 0) ||
283             (errno != EBUSY)) {
284             break;
285         }
286     }
287     if (fd < 0) {
288         switch (errno) {
289         case EACCES:            /* permission denied */
290             {
291                 char buffer[256];
292                 sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName);
293                 fatal(buffer);
294             }
295             break;
296         case EBUSY:
297         case ENOENT:            /* no such file */
298             if (i == 0) {
299                 fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)");
300             } else {
301                 fatal("All /dev/bpf* devices are in use");
302             }
303             break;
304         }
305         fatalSys(bpfName);
306     }
307
308     if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
309         fatalSys("socket");
310     }
311
312     /* Check that the interface is up */
313     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
314     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
315         fatalSys("ioctl(SIOCGIFFLAGS)");
316     }
317     if ((ifr.ifr_flags & IFF_UP) == 0) {
318         char buffer[256];
319         sprintf(buffer, "Interface %.16s is not up\n", ifname);
320         fatal(buffer);
321     }
322
323     /* Fill in hardware address and initialize the packet filter rules */
324     if (hwaddr == NULL) {
325         fatal("openInterface: no hwaddr arg.");
326     }
327     getHWaddr(sock, ifname, hwaddr);
328     initFilter(fd, type, hwaddr);
329
330     /* Sanity check on MTU -- apparently does not work on OpenBSD */
331 #if !defined(__OpenBSD__)
332     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
333     if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) {
334         fatalSys("ioctl(SIOCGIFMTU)");
335     }
336     if (ifr.ifr_mtu < ETH_DATA_LEN) {
337         char buffer[256];
338         sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d.  You may have serious connection problems.",
339                 ifname, ifr.ifr_mtu, ETH_DATA_LEN);
340         printErr(buffer);
341     }
342 #endif
343
344     /* done with the socket */
345     if (close(sock) < 0) {
346         fatalSys("close");
347     }
348
349     /* Check the BPF version number */
350     if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) {
351         fatalSys("ioctl(BIOCVERSION)");
352     }
353     if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) ||
354         (bpf_ver.bv_minor < BPF_MINOR_VERSION)) {
355         char buffer[256];
356         sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)", 
357                         BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
358                         bpf_ver.bv_major, bpf_ver.bv_minor);
359         fatal(buffer);
360     }
361
362     /* allocate a receive packet buffer */
363     if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) {
364         fatalSys("ioctl(BIOCGBLEN)");
365     }
366     if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) {
367         fatal("malloc");
368     }
369
370     /* reads should return as soon as there is a packet available */
371     optval = 1;
372     if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) {
373         fatalSys("ioctl(BIOCIMMEDIATE)");
374     }
375
376     /* Bind the interface to the filter */
377     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
378     if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
379         char buffer[256];
380         sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s",
381                 ifname);
382         fatal(buffer);
383     }
384
385     syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",
386            ifname, 
387            hwaddr[0], hwaddr[1], hwaddr[2],
388            hwaddr[3], hwaddr[4], hwaddr[5],
389            bpfName, bpfLength);
390     return fd;
391 }
392
393 #endif /* USE_BPF */
394
395 #ifdef USE_LINUX_PACKET
396 /**********************************************************************
397 *%FUNCTION: openInterface
398 *%ARGUMENTS:
399 * ifname -- name of interface
400 * type -- Ethernet frame type
401 * hwaddr -- if non-NULL, set to the hardware address
402 *%RETURNS:
403 * A raw socket for talking to the Ethernet card.  Exits on error.
404 *%DESCRIPTION:
405 * Opens a raw Ethernet socket
406 ***********************************************************************/
407 int
408 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
409 {
410     int optval=1;
411     int fd;
412     struct ifreq ifr;
413     int domain, stype;
414
415 #ifdef HAVE_STRUCT_SOCKADDR_LL
416     struct sockaddr_ll sa;
417 #else
418     struct sockaddr sa;
419 #endif
420
421     memset(&sa, 0, sizeof(sa));
422
423 #ifdef HAVE_STRUCT_SOCKADDR_LL
424     domain = PF_PACKET;
425     stype = SOCK_RAW;
426 #else
427     domain = PF_INET;
428     stype = SOCK_PACKET;
429 #endif
430
431     if ((fd = socket(domain, stype, htons(type))) < 0) {
432         /* Give a more helpful message for the common error case */
433         if (errno == EPERM) {
434             fatal("Cannot create raw socket -- pppoe must be run as root.");
435         }
436         fatalSys("socket");
437     }
438
439     if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
440         fatalSys("setsockopt");
441     }
442
443     /* Fill in hardware address */
444     if (hwaddr) {
445         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
446         if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
447             fatalSys("ioctl(SIOCGIFHWADDR)");
448         }
449         memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
450     }
451
452     /* Sanity check on MTU */
453     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
454     if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
455         fatalSys("ioctl(SIOCGIFMTU)");
456     }
457     if (ifr.ifr_mtu < ETH_DATA_LEN) {
458         char buffer[256];
459         sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d.  You may have serious connection problems.",
460                 ifname, ifr.ifr_mtu, ETH_DATA_LEN);
461         printErr(buffer);
462     }
463
464 #ifdef HAVE_STRUCT_SOCKADDR_LL
465     /* Get interface index */
466     sa.sll_family = AF_PACKET;
467     sa.sll_protocol = htons(type);
468
469     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
470     if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
471         fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
472     }
473     sa.sll_ifindex = ifr.ifr_ifindex;
474
475 #else
476     strcpy(sa.sa_data, ifname);
477 #endif
478
479     /* We're only interested in packets on specified interface */
480     if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
481         fatalSys("bind");
482     }
483
484     return fd;
485 }
486
487 #endif /* USE_LINUX */
488
489 /***********************************************************************
490 *%FUNCTION: sendPacket
491 *%ARGUMENTS:
492 * sock -- socket to send to
493 * pkt -- the packet to transmit
494 * size -- size of packet (in bytes)
495 *%RETURNS:
496 * Nothing
497 *%DESCRIPTION:
498 * Transmits a packet
499 ***********************************************************************/
500 void
501 sendPacket(int sock, struct PPPoEPacket *pkt, int size)
502 {
503 #if defined(USE_BPF)
504     if (write(sock, pkt, size) < 0) {
505         fatalSys("write (sendPacket)");
506     }
507 #elif defined(HAVE_STRUCT_SOCKADDR_LL)
508     if (send(sock, pkt, size, 0) < 0) {
509         fatalSys("send (sendPacket)");
510     }
511 #else
512 #ifdef USE_DLPI
513
514 #define ABS(x)          ((x) < 0 ? -(x) : (x))
515
516         u_char  addr[MAXDLADDR];
517         u_char  phys[MAXDLADDR];
518         u_char  sap[MAXDLADDR];
519         u_char    xmitbuf[MAXDLBUF];
520         int     data_size;
521
522         short   tmp_sap;
523
524         tmp_sap = htons(pkt->ethHdr.h_proto); 
525         data_size = size - sizeof(struct ethhdr); 
526
527         memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL);
528         memcpy((char *)sap,  (char *)&tmp_sap, sizeof(ushort_t));
529         memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size); 
530
531         if (dl_saplen > 0) {  /* order is sap+phys */
532                 (void) memcpy((char*)addr, (char*)&sap, dl_abssaplen);
533                 (void) memcpy((char*)addr+dl_abssaplen, (char*)phys, ETHERADDRL);
534         } else {        /* order is phys+sap */
535                 (void) memcpy((char*)addr, (char*)phys, ETHERADDRL);
536                 (void) memcpy((char*)addr+ETHERADDRL, (char*)&sap, dl_abssaplen);
537         }
538
539 #ifdef DL_DEBUG
540         printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n", 
541                 addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],
542                 addr[6],addr[7]);
543 #endif
544
545         dlunitdatareq(sock, addr, dl_addrlen, 0, 0, xmitbuf, data_size);
546
547
548
549 #else
550     struct sockaddr sa;
551     strcpy(sa.sa_data, IfName);
552     if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
553         fatalSys("sendto (sendPacket)");
554     }
555 #endif
556 #endif
557 }
558
559 #ifdef USE_BPF
560 /***********************************************************************
561 *%FUNCTION: clearPacketHeader
562 *%ARGUMENTS:
563 * pkt -- packet that needs its head clearing
564 *%RETURNS:
565 * nothing
566 *%DESCRIPTION:
567 * Clears a PPPoE packet header after a truncated packet has been
568 * received.  Insures that the packet will fail any integrity tests
569 * and will be discarded by upper level routines.  Also resets the
570 * bpfSize and bpfOffset variables to force a new read on the next
571 * call to receivePacket().
572 ***********************************************************************/
573 void
574 clearPacketHeader(struct PPPoEPacket *pkt)
575 {
576     bpfSize = bpfOffset = 0;
577     memset(pkt, 0, HDR_SIZE);
578 }
579 #endif
580
581 /***********************************************************************
582 *%FUNCTION: receivePacket
583 *%ARGUMENTS:
584 * sock -- socket to read from
585 * pkt -- place to store the received packet
586 * size -- set to size of packet in bytes
587 *%RETURNS:
588 * Nothing
589 *%DESCRIPTION:
590 * Receives a packet
591 ***********************************************************************/
592 void
593 receivePacket(int sock, struct PPPoEPacket *pkt, int *size)
594 {
595 #ifdef USE_BPF
596     struct bpf_hdr hdr;
597     int seglen, copylen;
598
599     if (bpfSize <= 0) {
600         bpfOffset = 0;
601         if ((bpfSize = read(sock, bpfBuffer, bpfLength)) < 0) {
602             fatalSys("read (receivePacket)");
603         }
604     }
605     if (bpfSize < sizeof(hdr)) {
606         syslog(LOG_ERR, "Truncated bpf packet header: len=%d", bpfSize);
607         clearPacketHeader(pkt);         /* resets bpfSize and bpfOffset */
608         return;
609     }
610     memcpy(&hdr, bpfBuffer + bpfOffset, sizeof(hdr));
611     if (hdr.bh_caplen != hdr.bh_datalen) {
612         syslog(LOG_ERR, "Truncated bpf packet: caplen=%d, datalen=%d",
613                hdr.bh_caplen, hdr.bh_datalen);
614         clearPacketHeader(pkt);         /* resets bpfSize and bpfOffset */
615         return;
616     }
617     seglen = hdr.bh_hdrlen + hdr.bh_caplen;
618     if (seglen > bpfSize) {
619         syslog(LOG_ERR, "Truncated bpf packet: seglen=%d, bpfSize=%d",
620                seglen, bpfSize);
621         clearPacketHeader(pkt);         /* resets bpfSize and bpfOffset */
622         return;
623     }
624     seglen = BPF_WORDALIGN(seglen);
625     *size = copylen = ((hdr.bh_caplen < sizeof(struct PPPoEPacket)) ?
626                         hdr.bh_caplen : sizeof(struct PPPoEPacket));
627     memcpy(pkt, bpfBuffer + bpfOffset + hdr.bh_hdrlen, copylen);
628     if (seglen >= bpfSize) {
629         bpfSize = bpfOffset = 0;
630     } else {
631         bpfSize -= seglen;
632         bpfOffset += seglen;
633     }
634 #else
635 #ifdef USE_DLPI
636         struct strbuf data; 
637         int flags = 0;  
638         int retval; 
639
640         data.buf = (char *) pkt; 
641         data.maxlen = MAXDLBUF; 
642         data.len = 0; 
643         
644         if ((retval = getmsg(sock, NULL, &data, &flags)) < 0) {
645             fatalSys("read (receivePacket)");
646         }
647
648         *size = data.len; 
649
650 #else
651     if ((*size = recv(sock, pkt, sizeof(struct PPPoEPacket), 0)) < 0) {
652         fatalSys("recv (receivePacket)");
653     }
654 #endif
655 #endif
656 }
657
658 #ifdef USE_DLPI
659 /**********************************************************************
660 *%FUNCTION: openInterface
661 *%ARGUMENTS:
662 * ifname -- name of interface
663 * type -- Ethernet frame type
664 * hwaddr -- if non-NULL, set to the hardware address
665 *%RETURNS:
666 * A raw socket for talking to the Ethernet card.  Exits on error.
667 *%DESCRIPTION:
668 * Opens a raw Ethernet socket
669 ***********************************************************************/
670 int
671 openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
672 {
673     int fd;
674     long buf[MAXDLBUF]; 
675
676         union   DL_primitives   *dlp;
677
678     char base_dev[PATH_MAX]; 
679     int ppa; 
680
681     if(strlen(ifname) > PATH_MAX) {
682         fatal("socket: string to long"); 
683     }
684
685     ppa = atoi(&ifname[strlen(ifname)-1]);
686     strncpy(base_dev, ifname, PATH_MAX); 
687     base_dev[strlen(base_dev)-1] = '\0'; 
688
689     if (( fd = open(base_dev, O_RDWR)) < 0) {
690         /* Give a more helpful message for the common error case */
691         if (errno == EPERM) {
692             fatal("Cannot create raw socket -- pppoe must be run as root.");
693         }
694         fatalSys("socket");
695     }
696
697         dlinforeq(fd);
698         dlinfoack(fd, (char *)buf);
699
700         dlp = (union DL_primitives*) buf;
701
702         dl_abssaplen = ABS(dlp->info_ack.dl_sap_length);
703         dl_saplen = dlp->info_ack.dl_sap_length;
704         if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen))
705                 fatalSys("invalid destination physical address length");
706         dl_addrlen = dl_abssaplen + ETHERADDRL;
707
708         dlattachreq(fd, ppa); 
709         dlokack(fd, (char *)buf);
710
711         dlbindreq(fd, htons(type), 0, DL_CLDLS, 0, 0);
712         dlbindack(fd, (char *)buf);
713
714         dlpromisconreq(fd, DL_PROMISC_PHYS); 
715         dlokack(fd, (char *)buf); 
716
717         if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) { 
718                 fatalSys("DLIOCRAW"); 
719         }
720
721         if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH");
722
723     return fd;
724 }
725
726 /* cloned from dlcommon.c */
727
728 void dlpromisconreq(int fd, u_long level)
729 {
730         dl_promiscon_req_t      promiscon_req;
731         struct  strbuf  ctl;
732         int     flags;
733
734         promiscon_req.dl_primitive = DL_PROMISCON_REQ;
735         promiscon_req.dl_level = level;
736
737         ctl.maxlen = 0;
738         ctl.len = sizeof (promiscon_req);
739         ctl.buf = (char *) &promiscon_req;
740
741         flags = 0;
742
743         if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
744                 fatalSys("dlpromiscon:  putmsg");
745
746 }
747
748 void dlinforeq(int fd)
749 {
750         dl_info_req_t   info_req;
751         struct  strbuf  ctl;
752         int     flags;
753
754         info_req.dl_primitive = DL_INFO_REQ;
755
756         ctl.maxlen = 0;
757         ctl.len = sizeof (info_req);
758         ctl.buf = (char *) &info_req;
759
760         flags = RS_HIPRI;
761
762         if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
763                 fatalSys("dlinforeq:  putmsg");
764 }
765
766 void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen)
767 {
768         long    buf[MAXDLBUF];
769         union   DL_primitives   *dlp;
770         struct  strbuf  data, ctl;
771
772         dlp = (union DL_primitives*) buf;
773
774         dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
775         dlp->unitdata_req.dl_dest_addr_length = addrlen;
776         dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
777         dlp->unitdata_req.dl_priority.dl_min = minpri;
778         dlp->unitdata_req.dl_priority.dl_max = maxpri;
779
780         (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);
781
782         ctl.maxlen = 0;
783         ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
784         ctl.buf = (char *) buf;
785
786         data.maxlen = 0;
787         data.len = datalen;
788         data.buf = (char *) datap;
789
790         if (putmsg(fd, &ctl, &data, 0) < 0)
791                 fatalSys("dlunitdatareq:  putmsg");
792 }
793
794 void dlinfoack(int fd, char *bufp)
795 {
796         union   DL_primitives   *dlp;
797         struct  strbuf  ctl;
798         int     flags;
799
800         ctl.maxlen = MAXDLBUF;
801         ctl.len = 0;
802         ctl.buf = bufp;
803
804         strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack");
805
806         dlp = (union DL_primitives *) ctl.buf;
807
808         expecting(DL_INFO_ACK, dlp);
809
810         if (ctl.len < sizeof (dl_info_ack_t)) {
811                 char buffer[256];
812                 sprintf(buffer, "dlinfoack:  response ctl.len too short:  %d", ctl.len); 
813                 fatal(buffer); 
814         }
815
816         if (flags != RS_HIPRI)
817                 fatal("dlinfoack:  DL_INFO_ACK was not M_PCPROTO");
818
819         if (ctl.len < sizeof (dl_info_ack_t)) {
820                 char buffer[256];
821                 sprintf(buffer, "dlinfoack:  short response ctl.len:  %d", ctl.len); 
822                 fatal(buffer); 
823         }
824 }
825
826 void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest)
827 {
828         dl_bind_req_t   bind_req;
829         struct  strbuf  ctl;
830         int     flags;
831
832         bind_req.dl_primitive = DL_BIND_REQ;
833         bind_req.dl_sap = sap;
834         bind_req.dl_max_conind = max_conind;
835         bind_req.dl_service_mode = service_mode;
836         bind_req.dl_conn_mgmt = conn_mgmt;
837         bind_req.dl_xidtest_flg = xidtest;
838
839         ctl.maxlen = 0;
840         ctl.len = sizeof (bind_req);
841         ctl.buf = (char *) &bind_req;
842
843         flags = 0;
844
845         if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
846                 fatalSys("dlbindreq:  putmsg");
847 }
848
849 void dlattachreq(int fd, u_long ppa)
850 {
851         dl_attach_req_t attach_req;
852         struct  strbuf  ctl;
853         int     flags;
854
855         attach_req.dl_primitive = DL_ATTACH_REQ;
856         attach_req.dl_ppa = ppa;
857
858         ctl.maxlen = 0;
859         ctl.len = sizeof (attach_req);
860         ctl.buf = (char *) &attach_req;
861
862         flags = 0;
863
864         if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
865                 fatalSys("dlattachreq:  putmsg");
866 }
867
868 void dlokack(int fd, char *bufp)
869 {
870         union   DL_primitives   *dlp;
871         struct  strbuf  ctl;
872         int     flags;
873
874         ctl.maxlen = MAXDLBUF;
875         ctl.len = 0;
876         ctl.buf = bufp;
877
878         strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack");
879
880         dlp = (union DL_primitives *) ctl.buf;
881
882         expecting(DL_OK_ACK, dlp);
883
884         if (ctl.len < sizeof (dl_ok_ack_t)) { 
885                 char buffer[256];
886                 sprintf(buffer, "dlokack:  response ctl.len too short:  %d", ctl.len);
887                 fatal(buffer); 
888         }
889
890         if (flags != RS_HIPRI)
891                 fatal("dlokack:  DL_OK_ACK was not M_PCPROTO");
892
893         if (ctl.len < sizeof (dl_ok_ack_t)) {
894                 char buffer[256]; 
895                 sprintf(buffer, "dlokack:  short response ctl.len:  %d", ctl.len);
896                 fatal(buffer); 
897         }
898 }
899
900 void dlbindack(int fd, char *bufp)
901 {
902         union   DL_primitives   *dlp;
903         struct  strbuf  ctl;
904         int     flags;
905
906         ctl.maxlen = MAXDLBUF;
907         ctl.len = 0;
908         ctl.buf = bufp;
909
910         strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack");
911
912         dlp = (union DL_primitives *) ctl.buf;
913
914         expecting(DL_BIND_ACK, dlp);
915
916         if (flags != RS_HIPRI)
917                 fatal("dlbindack:  DL_OK_ACK was not M_PCPROTO");
918
919         if (ctl.len < sizeof (dl_bind_ack_t)) {
920                 char buffer[256];
921                 sprintf(buffer, "dlbindack:  short response ctl.len:  %d", ctl.len);
922                 fatal(buffer); 
923         }
924 }
925
926 int strioctl(int fd, int cmd, int timout, int len, char *dp)
927 {
928         struct  strioctl        sioc;
929         int     rc;
930
931         sioc.ic_cmd = cmd;
932         sioc.ic_timout = timout;
933         sioc.ic_len = len;
934         sioc.ic_dp = dp;
935         rc = ioctl(fd, I_STR, &sioc);
936
937         if (rc < 0)
938                 return (rc);
939         else
940                 return (sioc.ic_len);
941 }
942
943 void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller)
944 {
945         int     rc;
946         static  char    errmsg[80];
947
948         /*
949          * Start timer.
950          */
951         (void) signal(SIGALRM, sigalrm);
952         if (alarm(MAXWAIT) < 0) {
953                 (void) sprintf(errmsg, "%s:  alarm", caller);
954                 fatalSys(errmsg);
955         }
956
957         /*
958          * Set flags argument and issue getmsg().
959          */
960         *flagsp = 0;
961         if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
962                 (void) sprintf(errmsg, "%s:  getmsg", caller);
963                 fatalSys(errmsg);
964         }
965
966         /*
967          * Stop timer.
968          */
969         if (alarm(0) < 0) {
970                 (void) sprintf(errmsg, "%s:  alarm", caller);
971                 fatalSys(errmsg);
972         }
973
974         /*
975          * Check for MOREDATA and/or MORECTL.
976          */
977         if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
978                 char buffer[256]; 
979                 sprintf(buffer, "%s:  MORECTL|MOREDATA", caller);
980                 fatal(buffer);
981         }
982                 
983         if (rc & MORECTL) {
984                 char buffer[256];
985                 sprintf(buffer, "%s:  MORECTL", caller);
986                 fatal(buffer); 
987         }
988         
989         if (rc & MOREDATA) {
990                 char buffer[256]; 
991                 sprintf(buffer, "%s:  MOREDATA", caller);
992                 fatal(buffer);
993         }
994
995         /*
996          * Check for at least sizeof (long) control data portion.
997          */
998         if (ctlp->len < sizeof (long)) {
999                 char buffer[256]; 
1000                 sprintf(buffer, "getmsg:  control portion length < sizeof (long):  %d", ctlp->len);
1001                 fatal(buffer); 
1002         }
1003 }
1004
1005 void sigalrm(int sig)
1006 {
1007         (void) fatal("sigalrm:  TIMEOUT");
1008 }
1009
1010 void expecting(int prim, union DL_primitives *dlp)
1011 {
1012         if (dlp->dl_primitive != (u_long)prim) {
1013                 char buffer[256]; 
1014                 sprintf(buffer, "expected %s got %s", dlprim(prim), dlprim(dlp->dl_primitive));
1015                 fatal(buffer); 
1016                 exit(1); 
1017         }
1018 }
1019
1020 char *dlprim(u_long prim)
1021 {
1022         static  char    primbuf[80];
1023
1024         switch ((int)prim) {
1025                 CASERET(DL_INFO_REQ);
1026                 CASERET(DL_INFO_ACK);
1027                 CASERET(DL_ATTACH_REQ);
1028                 CASERET(DL_DETACH_REQ);
1029                 CASERET(DL_BIND_REQ);
1030                 CASERET(DL_BIND_ACK);
1031                 CASERET(DL_UNBIND_REQ);
1032                 CASERET(DL_OK_ACK);
1033                 CASERET(DL_ERROR_ACK);
1034                 CASERET(DL_SUBS_BIND_REQ);
1035                 CASERET(DL_SUBS_BIND_ACK);
1036                 CASERET(DL_UNITDATA_REQ);
1037                 CASERET(DL_UNITDATA_IND);
1038                 CASERET(DL_UDERROR_IND);
1039                 CASERET(DL_UDQOS_REQ);
1040                 CASERET(DL_CONNECT_REQ);
1041                 CASERET(DL_CONNECT_IND);
1042                 CASERET(DL_CONNECT_RES);
1043                 CASERET(DL_CONNECT_CON);
1044                 CASERET(DL_TOKEN_REQ);
1045                 CASERET(DL_TOKEN_ACK);
1046                 CASERET(DL_DISCONNECT_REQ);
1047                 CASERET(DL_DISCONNECT_IND);
1048                 CASERET(DL_RESET_REQ);
1049                 CASERET(DL_RESET_IND);
1050                 CASERET(DL_RESET_RES);
1051                 CASERET(DL_RESET_CON);
1052                 default:
1053                         (void) sprintf(primbuf, "unknown primitive 0x%lx", prim);
1054                         return (primbuf);
1055         }
1056 }
1057
1058 #endif /* USE_DLPI */