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