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