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