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-2012 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$";
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
74static void 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);
86static char *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
100static unsigned char *bpfBuffer;	/* Packet filter buffer */
101static int bpfLength = 0;		/* Packet filter buffer length */
102       int bpfSize = 0;		        /* Number of unread bytes in buffer */
103static int 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", 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* mtu    -- if non-NULL, set to the MTU
416*%RETURNS:
417* A raw socket for talking to the Ethernet card.  Exits on error.
418*%DESCRIPTION:
419* Opens a raw Ethernet socket
420***********************************************************************/
421int
422openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr, UINT16_t *mtu)
423{
424    int optval=1;
425    int fd;
426    struct ifreq ifr;
427    int domain, stype;
428
429#ifdef HAVE_STRUCT_SOCKADDR_LL
430    struct sockaddr_ll sa;
431#else
432    struct sockaddr sa;
433#endif
434
435    memset(&sa, 0, sizeof(sa));
436
437#ifdef HAVE_STRUCT_SOCKADDR_LL
438    domain = PF_PACKET;
439    stype = SOCK_RAW;
440#else
441    domain = PF_INET;
442    stype = SOCK_PACKET;
443#endif
444
445    if ((fd = socket(domain, stype, htons(type))) < 0) {
446	/* Give a more helpful message for the common error case */
447	if (errno == EPERM) {
448	    rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
449	}
450	fatalSys("socket");
451    }
452
453    if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
454	fatalSys("setsockopt");
455    }
456
457    /* Fill in hardware address */
458    if (hwaddr) {
459	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
460	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
461	    fatalSys("ioctl(SIOCGIFHWADDR)");
462	}
463	memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
464#ifdef ARPHRD_ETHER
465	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
466	    char buffer[256];
467	    sprintf(buffer, "Interface %.16s is not Ethernet", ifname);
468	    rp_fatal(buffer);
469	}
470#endif
471	if (NOT_UNICAST(hwaddr)) {
472	    char buffer[256];
473	    sprintf(buffer,
474		    "Interface %.16s has broadcast/multicast MAC address??",
475		    ifname);
476	    rp_fatal(buffer);
477	}
478    }
479
480    /* Sanity check on MTU */
481    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
482    if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
483	fatalSys("ioctl(SIOCGIFMTU)");
484    }
485    if (ifr.ifr_mtu < ETH_DATA_LEN) {
486	char buffer[256];
487	sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d.  You may have serious connection problems.",
488		ifname, ifr.ifr_mtu, ETH_DATA_LEN);
489	printErr(buffer);
490    }
491    if (mtu) *mtu = ifr.ifr_mtu;
492
493#ifdef HAVE_STRUCT_SOCKADDR_LL
494    /* Get interface index */
495    sa.sll_family = AF_PACKET;
496    sa.sll_protocol = htons(type);
497
498    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
499    if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
500	fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
501    }
502    sa.sll_ifindex = ifr.ifr_ifindex;
503
504#else
505    strcpy(sa.sa_data, ifname);
506#endif
507
508    /* We're only interested in packets on specified interface */
509    if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
510	fatalSys("bind");
511    }
512
513    return fd;
514}
515
516#endif /* USE_LINUX */
517
518/***********************************************************************
519*%FUNCTION: sendPacket
520*%ARGUMENTS:
521* sock -- socket to send to
522* pkt -- the packet to transmit
523* size -- size of packet (in bytes)
524*%RETURNS:
525* 0 on success; -1 on failure
526*%DESCRIPTION:
527* Transmits a packet
528***********************************************************************/
529int
530sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
531{
532#if defined(USE_BPF)
533    if (write(sock, pkt, size) < 0) {
534	sysErr("write (sendPacket)");
535	return -1;
536    }
537#elif defined(HAVE_STRUCT_SOCKADDR_LL)
538    if (send(sock, pkt, size, 0) < 0 && (errno != ENOBUFS)) {
539	sysErr("send (sendPacket)");
540	return -1;
541    }
542#else
543#ifdef USE_DLPI
544
545#define ABS(x)          ((x) < 0 ? -(x) : (x))
546
547	u_char  addr[MAXDLADDR];
548	u_char  phys[MAXDLADDR];
549	u_char  sap[MAXDLADDR];
550	u_char    xmitbuf[MAXDLBUF];
551	int	data_size;
552
553	short	tmp_sap;
554
555	tmp_sap = htons(pkt->ethHdr.h_proto);
556	data_size = size - sizeof(struct ethhdr);
557
558	memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL);
559	memcpy((char *)sap,  (char *)&tmp_sap, sizeof(ushort_t));
560	memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size);
561
562	if (dl_saplen > 0) {  /* order is sap+phys */
563		(void) memcpy((char*)addr, (char*)&sap, dl_abssaplen);
564		(void) memcpy((char*)addr+dl_abssaplen, (char*)phys, ETHERADDRL);
565	} else {        /* order is phys+sap */
566		(void) memcpy((char*)addr, (char*)phys, ETHERADDRL);
567		(void) memcpy((char*)addr+ETHERADDRL, (char*)&sap, dl_abssaplen);
568	}
569
570#ifdef DL_DEBUG
571	printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n",
572		addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],
573		addr[6],addr[7]);
574#endif
575
576	dlunitdatareq(sock, addr, dl_addrlen, 0, 0, xmitbuf, data_size);
577
578
579
580#else
581    struct sockaddr sa;
582
583    if (!conn) {
584	rp_fatal("relay and server not supported on Linux 2.0 kernels");
585    }
586    strcpy(sa.sa_data, conn->ifName);
587    if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
588	sysErr("sendto (sendPacket)");
589	return -1;
590    }
591#endif
592#endif
593    return 0;
594}
595
596#ifdef USE_BPF
597/***********************************************************************
598*%FUNCTION: clearPacketHeader
599*%ARGUMENTS:
600* pkt -- packet that needs its head clearing
601*%RETURNS:
602* nothing
603*%DESCRIPTION:
604* Clears a PPPoE packet header after a truncated packet has been
605* received.  Insures that the packet will fail any integrity tests
606* and will be discarded by upper level routines.  Also resets the
607* bpfSize and bpfOffset variables to force a new read on the next
608* call to receivePacket().
609***********************************************************************/
610void
611clearPacketHeader(PPPoEPacket *pkt)
612{
613    bpfSize = bpfOffset = 0;
614    memset(pkt, 0, HDR_SIZE);
615}
616#endif
617
618/***********************************************************************
619*%FUNCTION: receivePacket
620*%ARGUMENTS:
621* sock -- socket to read from
622* pkt -- place to store the received packet
623* size -- set to size of packet in bytes
624*%RETURNS:
625* >= 0 if all OK; < 0 if error
626*%DESCRIPTION:
627* Receives a packet
628***********************************************************************/
629int
630receivePacket(int sock, PPPoEPacket *pkt, int *size)
631{
632#ifdef USE_BPF
633    struct bpf_hdr hdr;
634    int seglen, copylen;
635
636    if (bpfSize <= 0) {
637	bpfOffset = 0;
638	if ((bpfSize = read(sock, bpfBuffer, bpfLength)) < 0) {
639	    sysErr("read (receivePacket)");
640	    return -1;
641	}
642    }
643    if (bpfSize < sizeof(hdr)) {
644	syslog(LOG_ERR, "Truncated bpf packet header: len=%d", bpfSize);
645	clearPacketHeader(pkt);		/* resets bpfSize and bpfOffset */
646	return 0;
647    }
648    memcpy(&hdr, bpfBuffer + bpfOffset, sizeof(hdr));
649    if (hdr.bh_caplen != hdr.bh_datalen) {
650	syslog(LOG_ERR, "Truncated bpf packet: caplen=%d, datalen=%d",
651	       hdr.bh_caplen, hdr.bh_datalen);
652	clearPacketHeader(pkt);		/* resets bpfSize and bpfOffset */
653	return 0;
654    }
655    seglen = hdr.bh_hdrlen + hdr.bh_caplen;
656    if (seglen > bpfSize) {
657	syslog(LOG_ERR, "Truncated bpf packet: seglen=%d, bpfSize=%d",
658	       seglen, bpfSize);
659	clearPacketHeader(pkt);		/* resets bpfSize and bpfOffset */
660	return 0;
661    }
662    seglen = BPF_WORDALIGN(seglen);
663    *size = copylen = ((hdr.bh_caplen < sizeof(PPPoEPacket)) ?
664			hdr.bh_caplen : sizeof(PPPoEPacket));
665    memcpy(pkt, bpfBuffer + bpfOffset + hdr.bh_hdrlen, copylen);
666    if (seglen >= bpfSize) {
667	bpfSize = bpfOffset = 0;
668    } else {
669	bpfSize -= seglen;
670	bpfOffset += seglen;
671    }
672#else
673#ifdef USE_DLPI
674	struct strbuf data;
675	int flags = 0;
676	int retval;
677
678	data.buf = (char *) pkt;
679	data.maxlen = MAXDLBUF;
680	data.len = 0;
681
682	if ((retval = getmsg(sock, NULL, &data, &flags)) < 0) {
683	    sysErr("read (receivePacket)");
684	    return -1;
685	}
686
687	*size = data.len;
688
689#else
690    if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
691	sysErr("recv (receivePacket)");
692	return -1;
693    }
694#endif
695#endif
696    return 0;
697}
698
699#ifdef USE_DLPI
700/**********************************************************************
701*%FUNCTION: openInterface
702*%ARGUMENTS:
703* ifname -- name of interface
704* type -- Ethernet frame type
705* hwaddr -- if non-NULL, set to the hardware address
706*%RETURNS:
707* A raw socket for talking to the Ethernet card.  Exits on error.
708*%DESCRIPTION:
709* Opens a raw Ethernet socket
710***********************************************************************/
711int
712openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
713{
714    int fd;
715    long buf[MAXDLBUF];
716
717	union   DL_primitives   *dlp;
718
719    char base_dev[PATH_MAX];
720    int ppa;
721
722    if(strlen(ifname) > PATH_MAX) {
723	rp_fatal("socket: Interface name too long");
724    }
725
726    if (strlen(ifname) < 2) {
727	rp_fatal("socket: Interface name too short");
728    }
729
730    ppa = atoi(&ifname[strlen(ifname)-1]);
731    strncpy(base_dev, ifname, PATH_MAX);
732    base_dev[strlen(base_dev)-1] = '\0';
733
734/* rearranged order of DLPI code - delphys 20010803 */
735    dlp = (union DL_primitives*) buf;
736
737    if ( (fd = open(base_dev, O_RDWR)) < 0) {
738	/* Give a more helpful message for the common error case */
739	if (errno == EPERM) {
740	    rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
741	}
742	/* Common error is to omit /dev/ */
743	if (errno == ENOENT) {
744	    char ifname[512];
745	    snprintf(ifname, sizeof(ifname), "/dev/%s", base_dev);
746	    if ((fd = open(ifname, O_RDWR)) < 0) {
747		if (errno == EPERM) {
748		    rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
749		}
750	    }
751	}
752    }
753    if (fd < 0) {
754	fatalSys("socket");
755    }
756
757/* rearranged order of DLPI code - delphys 20010803 */
758    dlattachreq(fd, ppa);
759    dlokack(fd, (char *)buf);
760
761    dlbindreq(fd, type, 0, DL_CLDLS, 0, 0);
762    dlbindack(fd, (char *)buf);
763
764    dlinforeq(fd);
765    dlinfoack(fd, (char *)buf);
766
767    dl_abssaplen = ABS(dlp->info_ack.dl_sap_length);
768    dl_saplen = dlp->info_ack.dl_sap_length;
769    if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen))
770	fatalSys("invalid destination physical address length");
771    dl_addrlen = dl_abssaplen + ETHERADDRL;
772
773/* ethernet address retrieved as part of DL_INFO_ACK - delphys 20010803 */
774    memcpy(hwaddr, (u_char*)((char*)(dlp) + (int)(dlp->info_ack.dl_addr_offset)), ETHERADDRL);
775
776    if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) {
777	fatalSys("DLIOCRAW");
778    }
779
780    if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH");
781
782    return fd;
783}
784
785/* cloned from dlcommon.c */
786
787static void
788dlpromisconreq(int fd, u_long level)
789{
790	dl_promiscon_req_t      promiscon_req;
791	struct  strbuf  ctl;
792	int     flags;
793
794	promiscon_req.dl_primitive = DL_PROMISCON_REQ;
795	promiscon_req.dl_level = level;
796
797	ctl.maxlen = 0;
798	ctl.len = sizeof (promiscon_req);
799	ctl.buf = (char *) &promiscon_req;
800
801	flags = 0;
802
803	if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
804		fatalSys("dlpromiscon:  putmsg");
805
806}
807
808void dlinforeq(int fd)
809{
810	dl_info_req_t   info_req;
811	struct  strbuf  ctl;
812	int     flags;
813
814	info_req.dl_primitive = DL_INFO_REQ;
815
816	ctl.maxlen = 0;
817	ctl.len = sizeof (info_req);
818	ctl.buf = (char *) &info_req;
819
820	flags = RS_HIPRI;
821
822	if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
823		fatalSys("dlinforeq:  putmsg");
824}
825
826void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen)
827{
828	long    buf[MAXDLBUF];
829	union   DL_primitives   *dlp;
830	struct  strbuf  data, ctl;
831
832	dlp = (union DL_primitives*) buf;
833
834	dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
835	dlp->unitdata_req.dl_dest_addr_length = addrlen;
836	dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
837	dlp->unitdata_req.dl_priority.dl_min = minpri;
838	dlp->unitdata_req.dl_priority.dl_max = maxpri;
839
840	(void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);
841
842	ctl.maxlen = 0;
843	ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
844	ctl.buf = (char *) buf;
845
846	data.maxlen = 0;
847	data.len = datalen;
848	data.buf = (char *) datap;
849
850	if (putmsg(fd, &ctl, &data, 0) < 0)
851		fatalSys("dlunitdatareq:  putmsg");
852}
853
854void dlinfoack(int fd, char *bufp)
855{
856	union   DL_primitives   *dlp;
857	struct  strbuf  ctl;
858	int     flags;
859
860	ctl.maxlen = MAXDLBUF;
861	ctl.len = 0;
862	ctl.buf = bufp;
863
864	strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack");
865
866	dlp = (union DL_primitives *) ctl.buf;
867
868	expecting(DL_INFO_ACK, dlp);
869
870	if (ctl.len < sizeof (dl_info_ack_t)) {
871		char buffer[256];
872		sprintf(buffer, "dlinfoack:  response ctl.len too short:  %d", ctl.len);
873		rp_fatal(buffer);
874	}
875
876	if (flags != RS_HIPRI)
877		rp_fatal("dlinfoack:  DL_INFO_ACK was not M_PCPROTO");
878
879	if (ctl.len < sizeof (dl_info_ack_t)) {
880		char buffer[256];
881		sprintf(buffer, "dlinfoack:  short response ctl.len:  %d", ctl.len);
882		rp_fatal(buffer);
883	}
884}
885
886void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest)
887{
888	dl_bind_req_t   bind_req;
889	struct  strbuf  ctl;
890	int     flags;
891
892	bind_req.dl_primitive = DL_BIND_REQ;
893	bind_req.dl_sap = sap;
894	bind_req.dl_max_conind = max_conind;
895	bind_req.dl_service_mode = service_mode;
896	bind_req.dl_conn_mgmt = conn_mgmt;
897	bind_req.dl_xidtest_flg = xidtest;
898
899	ctl.maxlen = 0;
900	ctl.len = sizeof (bind_req);
901	ctl.buf = (char *) &bind_req;
902
903	flags = 0;
904
905	if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
906		fatalSys("dlbindreq:  putmsg");
907}
908
909void dlattachreq(int fd, u_long ppa)
910{
911	dl_attach_req_t attach_req;
912	struct  strbuf  ctl;
913	int     flags;
914
915	attach_req.dl_primitive = DL_ATTACH_REQ;
916	attach_req.dl_ppa = ppa;
917
918	ctl.maxlen = 0;
919	ctl.len = sizeof (attach_req);
920	ctl.buf = (char *) &attach_req;
921
922	flags = 0;
923
924	if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
925		fatalSys("dlattachreq:  putmsg");
926}
927
928void dlokack(int fd, char *bufp)
929{
930	union   DL_primitives   *dlp;
931	struct  strbuf  ctl;
932	int     flags;
933
934	ctl.maxlen = MAXDLBUF;
935	ctl.len = 0;
936	ctl.buf = bufp;
937
938	strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack");
939
940	dlp = (union DL_primitives *) ctl.buf;
941
942	expecting(DL_OK_ACK, dlp);
943
944	if (ctl.len < sizeof (dl_ok_ack_t)) {
945		char buffer[256];
946		sprintf(buffer, "dlokack:  response ctl.len too short:  %d", ctl.len);
947		rp_fatal(buffer);
948	}
949
950	if (flags != RS_HIPRI)
951		rp_fatal("dlokack:  DL_OK_ACK was not M_PCPROTO");
952
953	if (ctl.len < sizeof (dl_ok_ack_t)) {
954		char buffer[256];
955		sprintf(buffer, "dlokack:  short response ctl.len:  %d", ctl.len);
956		rp_fatal(buffer);
957	}
958}
959
960void dlbindack(int fd, char *bufp)
961{
962	union   DL_primitives   *dlp;
963	struct  strbuf  ctl;
964	int     flags;
965
966	ctl.maxlen = MAXDLBUF;
967	ctl.len = 0;
968	ctl.buf = bufp;
969
970	strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack");
971
972	dlp = (union DL_primitives *) ctl.buf;
973
974	expecting(DL_BIND_ACK, dlp);
975
976	if (flags != RS_HIPRI)
977		rp_fatal("dlbindack:  DL_OK_ACK was not M_PCPROTO");
978
979	if (ctl.len < sizeof (dl_bind_ack_t)) {
980		char buffer[256];
981		sprintf(buffer, "dlbindack:  short response ctl.len:  %d", ctl.len);
982		rp_fatal(buffer);
983	}
984}
985
986int strioctl(int fd, int cmd, int timout, int len, char *dp)
987{
988	struct  strioctl        sioc;
989	int     rc;
990
991	sioc.ic_cmd = cmd;
992	sioc.ic_timout = timout;
993	sioc.ic_len = len;
994	sioc.ic_dp = dp;
995	rc = ioctl(fd, I_STR, &sioc);
996
997	if (rc < 0)
998		return (rc);
999	else
1000		return (sioc.ic_len);
1001}
1002
1003void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller)
1004{
1005	int     rc;
1006	static  char    errmsg[80];
1007
1008	/*
1009	 * Start timer.
1010	 */
1011	(void) signal(SIGALRM, sigalrm);
1012	if (alarm(MAXWAIT) < 0) {
1013		(void) sprintf(errmsg, "%s:  alarm", caller);
1014		fatalSys(errmsg);
1015	}
1016
1017	/*
1018	 * Set flags argument and issue getmsg().
1019	 */
1020	*flagsp = 0;
1021	if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
1022		(void) sprintf(errmsg, "%s:  getmsg", caller);
1023		fatalSys(errmsg);
1024	}
1025
1026	/*
1027	 * Stop timer.
1028	 */
1029	if (alarm(0) < 0) {
1030		(void) sprintf(errmsg, "%s:  alarm", caller);
1031		fatalSys(errmsg);
1032	}
1033
1034	/*
1035	 * Check for MOREDATA and/or MORECTL.
1036	 */
1037	if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
1038		char buffer[256];
1039		sprintf(buffer, "%s:  MORECTL|MOREDATA", caller);
1040		rp_fatal(buffer);
1041	}
1042
1043	if (rc & MORECTL) {
1044		char buffer[256];
1045		sprintf(buffer, "%s:  MORECTL", caller);
1046		rp_fatal(buffer);
1047	}
1048
1049	if (rc & MOREDATA) {
1050		char buffer[256];
1051		sprintf(buffer, "%s:  MOREDATA", caller);
1052		rp_fatal(buffer);
1053	}
1054
1055	/*
1056	 * Check for at least sizeof (long) control data portion.
1057	 */
1058	if (ctlp->len < sizeof (long)) {
1059		char buffer[256];
1060		sprintf(buffer, "getmsg:  control portion length < sizeof (long):  %d", ctlp->len);
1061		rp_fatal(buffer);
1062	}
1063}
1064
1065void sigalrm(int sig)
1066{
1067	(void) rp_fatal("sigalrm:  TIMEOUT");
1068}
1069
1070void expecting(int prim, union DL_primitives *dlp)
1071{
1072	if (dlp->dl_primitive != (u_long)prim) {
1073		char buffer[256];
1074		sprintf(buffer, "expected %s got %s", dlprim(prim), dlprim(dlp->dl_primitive));
1075		rp_fatal(buffer);
1076		exit(1);
1077	}
1078}
1079
1080static char *
1081dlprim(u_long prim)
1082{
1083	static  char    primbuf[80];
1084
1085	switch ((int)prim) {
1086		CASERET(DL_INFO_REQ);
1087		CASERET(DL_INFO_ACK);
1088		CASERET(DL_ATTACH_REQ);
1089		CASERET(DL_DETACH_REQ);
1090		CASERET(DL_BIND_REQ);
1091		CASERET(DL_BIND_ACK);
1092		CASERET(DL_UNBIND_REQ);
1093		CASERET(DL_OK_ACK);
1094		CASERET(DL_ERROR_ACK);
1095		CASERET(DL_SUBS_BIND_REQ);
1096		CASERET(DL_SUBS_BIND_ACK);
1097		CASERET(DL_UNITDATA_REQ);
1098		CASERET(DL_UNITDATA_IND);
1099		CASERET(DL_UDERROR_IND);
1100		CASERET(DL_UDQOS_REQ);
1101		CASERET(DL_CONNECT_REQ);
1102		CASERET(DL_CONNECT_IND);
1103		CASERET(DL_CONNECT_RES);
1104		CASERET(DL_CONNECT_CON);
1105		CASERET(DL_TOKEN_REQ);
1106		CASERET(DL_TOKEN_ACK);
1107		CASERET(DL_DISCONNECT_REQ);
1108		CASERET(DL_DISCONNECT_IND);
1109		CASERET(DL_RESET_REQ);
1110		CASERET(DL_RESET_IND);
1111		CASERET(DL_RESET_RES);
1112		CASERET(DL_RESET_CON);
1113		default:
1114			(void) sprintf(primbuf, "unknown primitive 0x%lx", prim);
1115			return (primbuf);
1116	}
1117}
1118
1119#endif /* USE_DLPI */
1120