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