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
16static char const RCSID[] =
17"$Id: if.c,v 1.1.1.1 2008/10/15 03:31:00 james26_jang 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
68void dlpromisconreq( int fd, u_long  level);
69void dlinforeq(int fd);
70void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen);
71void dlinfoack(int fd, char *bufp);
72void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest);
73void dlattachreq(int fd, u_long ppa);
74void dlokack(int fd, char *bufp);
75void dlbindack(int fd, char *bufp);
76int strioctl(int fd, int cmd, int timout, int len, char *dp);
77void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller);
78void sigalrm(int sig);
79void expecting(int prim, union DL_primitives *dlp);
80char *dlprim(u_long prim);
81
82/* #define DL_DEBUG */
83
84static	int     dl_abssaplen;
85static	int     dl_saplen;
86static	int 	dl_addrlen;
87
88#endif
89
90#ifdef USE_BPF
91#include <net/bpf.h>
92#include <fcntl.h>
93
94unsigned char *bpfBuffer;	/* Packet filter buffer */
95int bpfLength = 0;		/* Packet filter buffer length */
96int bpfSize = 0;		/* Number of unread bytes in buffer */
97int bpfOffset = 0;		/* Current offset in bpfBuffer */
98#endif
99
100extern 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
105UINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY;
106UINT16_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***********************************************************************/
123UINT16_t
124etherType(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***********************************************************************/
144void
145getHWaddr(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***********************************************************************/
201void
202initFilter(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***********************************************************************/
263int
264openInterface(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***********************************************************************/
407int
408openInterface(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***********************************************************************/
500void
501sendPacket(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***********************************************************************/
573void
574clearPacketHeader(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***********************************************************************/
592void
593receivePacket(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***********************************************************************/
670int
671openInterface(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
728void 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
748void 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
766void 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
794void 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
826void 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
849void 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
868void 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
900void 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
926int 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
943void 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
1005void sigalrm(int sig)
1006{
1007        (void) fatal("sigalrm:  TIMEOUT");
1008}
1009
1010void 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
1020char *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 */
1059