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