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