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