void dlbindack(int fd, char *bufp) { union DL_primitives *dlp; struct strbuf ctl; int flags; ctl.maxlen = MAXDLBUF; ctl.len = 0; ctl.buf = bufp; strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack"); dlp = (union DL_primitives *) ctl.buf; expecting(DL_BIND_ACK, dlp); if (flags != RS_HIPRI) rp_fatal("dlbindack: DL_OK_ACK was not M_PCPROTO"); if (ctl.len < sizeof (dl_bind_ack_t)) { char buffer[256]; sprintf(buffer, "dlbindack: short response ctl.len: %d", ctl.len); rp_fatal(buffer); } }
/********************************************************************** *%FUNCTION: openInterface *%ARGUMENTS: * ifname -- name of interface * type -- Ethernet frame type * hwaddr -- if non-NULL, set to the hardware address *%RETURNS: * A raw socket for talking to the Ethernet card. Exits on error. *%DESCRIPTION: * Opens a raw Ethernet socket ***********************************************************************/ int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr) { int fd; long buf[MAXDLBUF]; union DL_primitives *dlp; char base_dev[PATH_MAX]; int ppa; if(strlen(ifname) > PATH_MAX) { rp_fatal("socket: string to long"); } ppa = atoi(&ifname[strlen(ifname)-1]); strncpy(base_dev, ifname, PATH_MAX); base_dev[strlen(base_dev)-1] = '\0'; /* rearranged order of DLPI code - delphys 20010803 */ dlp = (union DL_primitives*) buf; if (( fd = open(base_dev, O_RDWR)) < 0) { /* Give a more helpful message for the common error case */ if (errno == EPERM) { rp_fatal("Cannot create raw socket -- pppoe must be run as root."); } fatalSys("socket"); } /* rearranged order of DLPI code - delphys 20010803 */ dlattachreq(fd, ppa); dlokack(fd, (char *)buf); dlbindreq(fd, type, 0, DL_CLDLS, 0, 0); dlbindack(fd, (char *)buf); dlinforeq(fd); dlinfoack(fd, (char *)buf); dl_abssaplen = ABS(dlp->info_ack.dl_sap_length); dl_saplen = dlp->info_ack.dl_sap_length; if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen)) fatalSys("invalid destination physical address length"); dl_addrlen = dl_abssaplen + ETHERADDRL; /* ethernet address retrieved as part of DL_INFO_ACK - delphys 20010803 */ memcpy(hwaddr, (u_char*)((char*)(dlp) + (int)(dlp->info_ack.dl_addr_offset)), ETHERADDRL); if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) { fatalSys("DLIOCRAW"); } if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH"); return fd; }
/********************************************************************** *%FUNCTION: initRelay *%ARGUMENTS: * nsess -- maximum allowable number of sessions *%RETURNS: * Nothing *%DESCRIPTION: * Initializes relay hash table and session tables. ***********************************************************************/ void initRelay(int nsess) { int i; NumSessions = 0; MaxSessions = nsess; AllSessions = calloc(MaxSessions, sizeof(PPPoESession)); if (!AllSessions) { rp_fatal("Unable to allocate memory for PPPoE session table"); } AllHashes = calloc(MaxSessions*2, sizeof(SessionHash)); if (!AllHashes) { rp_fatal("Unable to allocate memory for PPPoE hash table"); } /* Initialize sessions in a linked list */ AllSessions[0].prev = NULL; if (MaxSessions > 1) { AllSessions[0].next = &AllSessions[1]; } else { AllSessions[0].next = NULL; } for (i=1; i<MaxSessions-1; i++) { AllSessions[i].prev = &AllSessions[i-1]; AllSessions[i].next = &AllSessions[i+1]; } if (MaxSessions > 1) { AllSessions[MaxSessions-1].prev = &AllSessions[MaxSessions-2]; AllSessions[MaxSessions-1].next = NULL; } FreeSessions = AllSessions; ActiveSessions = NULL; /* Initialize session numbers which we hand out */ for (i=0; i<MaxSessions; i++) { AllSessions[i].sesNum = htons((UINT16_t) i+1); } /* Initialize hashes in a linked list */ AllHashes[0].prev = NULL; AllHashes[0].next = &AllHashes[1]; for (i=1; i<2*MaxSessions-1; i++) { AllHashes[i].prev = &AllHashes[i-1]; AllHashes[i].next = &AllHashes[i+1]; } AllHashes[2*MaxSessions-1].prev = &AllHashes[2*MaxSessions-2]; AllHashes[2*MaxSessions-1].next = NULL; FreeHashes = AllHashes; }
/*********************************************************************** *%FUNCTION: sendPacket *%ARGUMENTS: * sock -- socket to send to * pkt -- the packet to transmit * size -- size of packet (in bytes) *%RETURNS: * 0 on success; -1 on failure *%DESCRIPTION: * Transmits a packet ***********************************************************************/ int sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size) { #if defined(USE_BPF) if (write(sock, pkt, size) < 0) { sysErr("write (sendPacket)"); return -1; } #elif defined(HAVE_STRUCT_SOCKADDR_LL) if (send(sock, pkt, size, 0) < 0) { sysErr("send (sendPacket)"); return -1; } #else struct sockaddr sa; if (!conn) { rp_fatal("relay and server not supported on Linux 2.0 kernels"); } strcpy(sa.sa_data, conn->ifName); if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) { sysErr("sendto (sendPacket)"); return -1; } #endif return 0; }
/********************************************************************** *%FUNCTION: getHWaddr *%ARGUMENTS: * ifname -- name of interface * hwaddr -- buffer for ehthernet address *%RETURNS: * Nothing *%DESCRIPTION: * Locates the Ethernet hardware address for an interface. ***********************************************************************/ void getHWaddr(int sock, char const *ifname, unsigned char *hwaddr) { char inbuf[8192]; const struct sockaddr_dl *sdl; struct ifconf ifc; struct ifreq ifreq, *ifr; int i; int found = 0; ifc.ifc_len = sizeof(inbuf); ifc.ifc_buf = inbuf; if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { fatalSys("SIOCGIFCONF"); } ifr = ifc.ifc_req; ifreq.ifr_name[0] = '\0'; for (i = 0; i < ifc.ifc_len; ) { ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i); i += sizeof(ifr->ifr_name) + (ifr->ifr_addr.sa_len > sizeof(struct sockaddr) ? ifr->ifr_addr.sa_len : sizeof(struct sockaddr)); if (ifr->ifr_addr.sa_family == AF_LINK) { sdl = (const struct sockaddr_dl *) &ifr->ifr_addr; if ((sdl->sdl_type == IFT_ETHER) && (sdl->sdl_alen == ETH_ALEN) && !strncmp(ifname, ifr->ifr_name, sizeof(ifr->ifr_name))) { if (found) { char buffer[256]; sprintf(buffer, "interface %.16s has more than one ethernet address", ifname); rp_fatal(buffer); } else { found = 1; memcpy(hwaddr, LLADDR(sdl), ETH_ALEN); } } } } if (!found) { char buffer[256]; sprintf(buffer, "interface %.16s has no ethernet address", ifname); rp_fatal(buffer); } test_func(); }
void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller) { int rc; static char errmsg[80]; (void) signal(SIGALRM, sigalrm); if (alarm(MAXWAIT) < 0) { (void) sprintf(errmsg, "%s: alarm", caller); fatalSys(errmsg); } *flagsp = 0; if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) { (void) sprintf(errmsg, "%s: getmsg", caller); fatalSys(errmsg); } if (alarm(0) < 0) { (void) sprintf(errmsg, "%s: alarm", caller); fatalSys(errmsg); } if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) { char buffer[256]; sprintf(buffer, "%s: MORECTL|MOREDATA", caller); rp_fatal(buffer); } if (rc & MORECTL) { char buffer[256]; sprintf(buffer, "%s: MORECTL", caller); rp_fatal(buffer); } if (rc & MOREDATA) { char buffer[256]; sprintf(buffer, "%s: MOREDATA", caller); rp_fatal(buffer); } if (ctlp->len < sizeof (long)) { char buffer[256]; sprintf(buffer, "getmsg: control portion length < sizeof (long): %d", ctlp->len); rp_fatal(buffer); } }
void expecting(int prim, union DL_primitives *dlp) { if (dlp->dl_primitive != (u_long)prim) { char buffer[256]; sprintf(buffer, "expected %s got %s", dlprim(prim), dlprim(dlp->dl_primitive)); rp_fatal(buffer); exit(1); } }
/********************************************************************** *%FUNCTION: discovery *%ARGUMENTS: * conn -- PPPoE connection info structure *%RETURNS: * Nothing *%DESCRIPTION: * Performs the PPPoE discovery phase ***********************************************************************/ void discovery(PPPoEConnection *conn) { int padiAttempts; int padrAttempts; int timeout = conn->discoveryTimeout; /* Skip discovery? */ if (conn->skipDiscovery) { conn->discoveryState = STATE_SESSION; if (conn->killSession) { sendPADT(conn, "RP-PPPoE: Session killed manually"); exit(0); } return; } SEND_PADI: padiAttempts = 0; do { #ifdef PLUGIN if (got_sigterm || got_sighup) return; #endif padiAttempts++; if (padiAttempts > MAX_PADI_ATTEMPTS) { if (persist) { padiAttempts = 0; timeout = conn->discoveryTimeout; printErr("Timeout waiting for PADO packets"); } else { #ifdef PLUGIN printErr("Timeout waiting for PADO packets"); return; #else rp_fatal("Timeout waiting for PADO packets"); #endif } } sendPADI(conn); conn->discoveryState = STATE_SENT_PADI; waitForPADO(conn, timeout); /* If we're just probing for access concentrators, don't do exponential backoff. This reduces the time for an unsuccessful probe to 15 seconds. */ if (!conn->printACNames) { timeout *= 2; } if (conn->printACNames && conn->numPADOs) { break; } } while (conn->discoveryState == STATE_SENT_PADI); /* If we're only printing access concentrator names, we're done */ if (conn->printACNames) { exit(0); } timeout = conn->discoveryTimeout; padrAttempts = 0; do { #ifdef PLUGIN if (got_sigterm || got_sighup) return; #endif padrAttempts++; if (padrAttempts > MAX_PADI_ATTEMPTS) { if (persist) { padrAttempts = 0; timeout = conn->discoveryTimeout; printErr("Timeout waiting for PADS packets"); /* Go back to sending PADI again */ goto SEND_PADI; } else { #ifdef PLUGIN printErr("Timeout waiting for PADS packets"); return; #else rp_fatal("Timeout waiting for PADS packets"); #endif } } sendPADR(conn); conn->discoveryState = STATE_SENT_PADR; waitForPADS(conn, timeout); timeout *= 2; } while (conn->discoveryState == STATE_SENT_PADR); #ifdef PLUGIN if (!conn->seenMaxPayload) { /* RFC 4638: MUST limit MTU/MRU to 1492 */ if (lcp_allowoptions[0].mru > ETH_PPPOE_MTU) lcp_allowoptions[0].mru = ETH_PPPOE_MTU; if (lcp_wantoptions[0].mru > ETH_PPPOE_MTU) lcp_wantoptions[0].mru = ETH_PPPOE_MTU; } #endif /* We're done. */ conn->discoveryState = STATE_SESSION; return; }
void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller) { int rc; static char errmsg[80]; /* * Start timer. */ (void) signal(SIGALRM, sigalrm); if (alarm(MAXWAIT) < 0) { (void) sprintf(errmsg, "%s: alarm", caller); fatalSys(errmsg); } /* * Set flags argument and issue getmsg(). */ *flagsp = 0; if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) { (void) sprintf(errmsg, "%s: getmsg", caller); fatalSys(errmsg); } /* * Stop timer. */ if (alarm(0) < 0) { (void) sprintf(errmsg, "%s: alarm", caller); fatalSys(errmsg); } /* * Check for MOREDATA and/or MORECTL. */ if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) { char buffer[256]; sprintf(buffer, "%s: MORECTL|MOREDATA", caller); rp_fatal(buffer); } if (rc & MORECTL) { char buffer[256]; sprintf(buffer, "%s: MORECTL", caller); rp_fatal(buffer); } if (rc & MOREDATA) { char buffer[256]; sprintf(buffer, "%s: MOREDATA", caller); rp_fatal(buffer); } /* * Check for at least sizeof (long) control data portion. */ if (ctlp->len < sizeof (long)) { char buffer[256]; sprintf(buffer, "getmsg: control portion length < sizeof (long): %d", ctlp->len); rp_fatal(buffer); } }
/********************************************************************** *%FUNCTION: discovery *%ARGUMENTS: * conn -- PPPoE connection info structure *%RETURNS: * Nothing *%DESCRIPTION: * Performs the PPPoE discovery phase ***********************************************************************/ void discovery(PPPoEConnection *conn) { int padiAttempts = 0; int padrAttempts = 0; int timeout = PADI_TIMEOUT; /* Skip discovery and don't open discovery socket? */ if (conn->skipDiscovery && conn->noDiscoverySocket) { conn->discoveryState = STATE_SESSION; return; } conn->discoverySocket = openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth); /* Skip discovery? */ if (conn->skipDiscovery) { conn->discoveryState = STATE_SESSION; if (conn->killSession) { sendPADT(conn, "RP-PPPoE: Session killed manually"); exit(0); } return; } do { padiAttempts++; if (padiAttempts > MAX_PADI_ATTEMPTS) { system("rm /etc/ppp/connectfile"); rp_fatal("Timeout waiting for PADO packets0"); } sendPADI(conn); conn->discoveryState = STATE_SENT_PADI; waitForPADO(conn, timeout); #if 0 // RexHua to Reduce connect time /* If we're just probing for access concentrators, don't do exponential backoff. This reduces the time for an unsuccessful probe to 15 seconds. */ if (!conn->printACNames) { timeout *= 2; } #endif if (conn->printACNames && conn->numPADOs) { break; } } while (conn->discoveryState == STATE_SENT_PADI); /* If we're only printing access concentrator names, we're done */ if (conn->printACNames) { printf("--------------------------------------------------\n"); exit(0); } timeout = PADI_TIMEOUT; do { padrAttempts++; if (padrAttempts > MAX_PADI_ATTEMPTS) { rp_fatal("Timeout waiting for PADS packets"); } sendPADR(conn); conn->discoveryState = STATE_SENT_PADR; waitForPADS(conn, timeout); #if 0 // RexHua to Reduce connect time timeout *= 2; #endif } while (conn->discoveryState == STATE_SENT_PADR); /* We're done. */ conn->discoveryState = STATE_SESSION; return; }
int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr) { static int fd = -1; char bpfName[32]; u_int optval; struct bpf_version bpf_ver; struct ifreq ifr; int sock; int i; if (fd >= 0) { return fd; } for (i = 0; i < 256; i++) { sprintf(bpfName, "/dev/bpf%d", i); if (((fd = open(bpfName, O_RDWR, 0)) >= 0) || (errno != EBUSY)) { break; } } if (fd < 0) { switch (errno) { case EACCES: { char buffer[256]; sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName); rp_fatal(buffer); } break; case EBUSY: case ENOENT: if (i == 0) { rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)"); } else { rp_fatal("All /dev/bpf* devices are in use"); } break; } fatalSys(bpfName); } if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) { fatalSys("socket"); } strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) { fatalSys("ioctl(SIOCGIFFLAGS)"); } if ((ifr.ifr_flags & IFF_UP) == 0) { char buffer[256]; sprintf(buffer, "Interface %.16s is not up", ifname); rp_fatal(buffer); } if (hwaddr == NULL) { rp_fatal("openInterface: no hwaddr arg."); } getHWaddr(sock, ifname, hwaddr); initFilter(fd, type, hwaddr); #if !defined(__OpenBSD__) strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) { fatalSys("ioctl(SIOCGIFMTU)"); } if (ifr.ifr_mtu < ETH_DATA_LEN) { char buffer[256]; sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.", ifname, ifr.ifr_mtu, ETH_DATA_LEN); printErr(buffer); } #endif if (close(sock) < 0) { fatalSys("close"); } if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) { fatalSys("ioctl(BIOCVERSION)"); } if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) || (bpf_ver.bv_minor < BPF_MINOR_VERSION)) { char buffer[256]; sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)", BPF_MAJOR_VERSION, BPF_MINOR_VERSION, bpf_ver.bv_major, bpf_ver.bv_minor); rp_fatal(buffer); } if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) { fatalSys("ioctl(BIOCGBLEN)"); } if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) { rp_fatal("malloc"); } optval = 1; if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) { fatalSys("ioctl(BIOCIMMEDIATE)"); } strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, &ifr) < 0) { char buffer[256]; sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s", ifname); rp_fatal(buffer); } syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d", ifname, hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5], bpfName, bpfLength); return fd; }
/********************************************************************** *%FUNCTION: discovery *%ARGUMENTS: * conn -- PPPoE connection info structure *%RETURNS: * Nothing *%DESCRIPTION: * Performs the PPPoE discovery phase ***********************************************************************/ void discovery(PPPoEConnection *conn) { int padiAttempts = 0; int padrAttempts = 0; int timeout = conn->discoveryTimeout; /* Skip discovery? */ if (conn->skipDiscovery) { conn->discoveryState = STATE_SESSION; if (conn->killSession) { sendPADT(conn, "RP-PPPoE: Session killed manually"); exit(0); } return; } do { padiAttempts++; if (padiAttempts > MAX_PADI_ATTEMPTS) { if (persist) { padiAttempts = 0; timeout = conn->discoveryTimeout; printErr("Timeout waiting for PADO packets"); } else { rp_fatal("Timeout waiting for PADO packets"); } } sendPADI(conn); conn->discoveryState = STATE_SENT_PADI; waitForPADO(conn, timeout); /* If we're just probing for access concentrators, don't do exponential backoff. This reduces the time for an unsuccessful probe to 15 seconds. */ if (!conn->printACNames) { timeout *= 2; } if (conn->printACNames && conn->numPADOs) { break; } } while (conn->discoveryState == STATE_SENT_PADI); /* If we're only printing access concentrator names, we're done */ if (conn->printACNames) { exit(0); } timeout = conn->discoveryTimeout; do { padrAttempts++; if (padrAttempts > MAX_PADI_ATTEMPTS) { if (persist) { padrAttempts = 0; timeout = conn->discoveryTimeout; printErr("Timeout waiting for PADS packets"); } else { rp_fatal("Timeout waiting for PADS packets"); } } sendPADR(conn); conn->discoveryState = STATE_SENT_PADR; waitForPADS(conn, timeout); timeout *= 2; } while (conn->discoveryState == STATE_SENT_PADR); /* We're done. */ conn->discoveryState = STATE_SESSION; return; }
/********************************************************************** *%FUNCTION: openInterface *%ARGUMENTS: * ifname -- name of interface * type -- Ethernet frame type * hwaddr -- if non-NULL, set to the hardware address *%RETURNS: * A raw socket for talking to the Ethernet card. Exits on error. *%DESCRIPTION: * Opens a raw Ethernet socket ***********************************************************************/ int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr) { int optval=1; int fd; struct ifreq ifr; int domain, stype; #ifdef HAVE_STRUCT_SOCKADDR_LL struct sockaddr_ll sa; #else struct sockaddr sa; #endif memset(&sa, 0, sizeof(sa)); #ifdef HAVE_STRUCT_SOCKADDR_LL domain = PF_PACKET; stype = SOCK_RAW; #else domain = PF_INET; stype = SOCK_PACKET; #endif if ((fd = socket(domain, stype, htons(type))) < 0) { /* Give a more helpful message for the common error case */ if (errno == EPERM) { rp_fatal("Cannot create raw socket -- pppoe must be run as root."); } fatalSys("socket"); } if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) { fatalSys("setsockopt"); } /* Fill in hardware address */ if (hwaddr) { strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { fatalSys("ioctl(SIOCGIFHWADDR)"); } memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); #ifdef ARPHRD_ETHER if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { char buffer[256]; sprintf(buffer, "Interface %.16s is not Ethernet", ifname); rp_fatal(buffer); } #endif if (NOT_UNICAST(hwaddr)) { char buffer[256]; sprintf(buffer, "Interface %.16s has broadcast/multicast MAC address??", ifname); rp_fatal(buffer); } } /* Sanity check on MTU */ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) { fatalSys("ioctl(SIOCGIFMTU)"); } if (ifr.ifr_mtu < ETH_DATA_LEN) { char buffer[256]; sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.", ifname, ifr.ifr_mtu, ETH_DATA_LEN); printErr(buffer); } #ifdef HAVE_STRUCT_SOCKADDR_LL /* Get interface index */ sa.sll_family = AF_PACKET; sa.sll_protocol = htons(type); strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) { fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index"); } sa.sll_ifindex = ifr.ifr_ifindex; #else strcpy(sa.sa_data, ifname); #endif /* We're only interested in packets on specified interface */ if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) { fatalSys("bind"); } return fd; }
/*********************************************************************** *%FUNCTION: sendPacket *%ARGUMENTS: * sock -- socket to send to * pkt -- the packet to transmit * size -- size of packet (in bytes) *%RETURNS: * 0 on success; -1 on failure *%DESCRIPTION: * Transmits a packet ***********************************************************************/ int sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size) { #if defined(USE_BPF) if (write(sock, pkt, size) < 0) { sysErr("write (sendPacket)"); return -1; } #elif defined(HAVE_STRUCT_SOCKADDR_LL) if (send(sock, pkt, size, 0) < 0) { sysErr("send (sendPacket)"); return -1; } #else #ifdef USE_DLPI #define ABS(x) ((x) < 0 ? -(x) : (x)) u_char addr[MAXDLADDR]; u_char phys[MAXDLADDR]; u_char sap[MAXDLADDR]; u_char xmitbuf[MAXDLBUF]; int data_size; short tmp_sap; tmp_sap = htons(pkt->ethHdr.h_proto); data_size = size - sizeof(struct ethhdr); memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL); memcpy((char *)sap, (char *)&tmp_sap, sizeof(ushort_t)); memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size); if (dl_saplen > 0) { /* order is sap+phys */ (void) memcpy((char*)addr, (char*)&sap, dl_abssaplen); (void) memcpy((char*)addr+dl_abssaplen, (char*)phys, ETHERADDRL); } else { /* order is phys+sap */ (void) memcpy((char*)addr, (char*)phys, ETHERADDRL); (void) memcpy((char*)addr+ETHERADDRL, (char*)&sap, dl_abssaplen); } #ifdef DL_DEBUG printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n", addr[0],addr[1],addr[2],addr[3],addr[4],addr[5], addr[6],addr[7]); #endif dlunitdatareq(sock, addr, dl_addrlen, 0, 0, xmitbuf, data_size); #else struct sockaddr sa; if (!conn) { rp_fatal("relay and server not supported on Linux 2.0 kernels"); } strcpy(sa.sa_data, conn->ifName); if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) { sysErr("sendto (sendPacket)"); return -1; } #endif #endif return 0; }
/********************************************************************** *%FUNCTION: openInterface *%ARGUMENTS: * ifname -- name of interface * type -- Ethernet frame type (0 for any frame type) * hwaddr -- if non-NULL, set to the hardware address *%RETURNS: * A file descriptor for talking with the Ethernet card. Exits on error. * Note that the Linux version of this routine returns a socket instead. *%DESCRIPTION: * Opens a BPF on an interface for all PPPoE traffic (discovery and * session). If 'type' is 0, uses promiscuous mode to watch any PPPoE * traffic on this network. ***********************************************************************/ int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr) { static int fd = -1; char bpfName[32]; u_int optval; struct bpf_version bpf_ver; struct ifreq ifr; int sock; int i; /* BSD only opens one socket for both Discovery and Session packets */ if (fd >= 0) { return fd; } /* Find a free BPF device */ for (i = 0; i < 256; i++) { sprintf(bpfName, "/dev/bpf%d", i); if (((fd = open(bpfName, O_RDWR, 0)) >= 0) || (errno != EBUSY)) { break; } } if (fd < 0) { switch (errno) { case EACCES: /* permission denied */ { char buffer[256]; sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName); rp_fatal(buffer); } break; case EBUSY: case ENOENT: /* no such file */ if (i == 0) { rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)"); } else { rp_fatal("All /dev/bpf* devices are in use"); } break; } fatalSys(bpfName); } if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) { fatalSys("socket"); } /* Check that the interface is up */ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) { fatalSys("ioctl(SIOCGIFFLAGS)"); } if ((ifr.ifr_flags & IFF_UP) == 0) { char buffer[256]; sprintf(buffer, "Interface %.16s is not up\n", ifname); rp_fatal(buffer); } /* Fill in hardware address and initialize the packet filter rules */ if (hwaddr == NULL) { rp_fatal("openInterface: no hwaddr arg."); } getHWaddr(sock, ifname, hwaddr); initFilter(fd, type, hwaddr); /* Sanity check on MTU -- apparently does not work on OpenBSD */ #if !defined(__OpenBSD__) strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) { fatalSys("ioctl(SIOCGIFMTU)"); } if (ifr.ifr_mtu < ETH_DATA_LEN) { char buffer[256]; sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d. You may have serious connection problems.", ifname, ifr.ifr_mtu, ETH_DATA_LEN); printErr(buffer); } #endif /* done with the socket */ if (close(sock) < 0) { fatalSys("close"); } /* Check the BPF version number */ if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) { fatalSys("ioctl(BIOCVERSION)"); } if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) || (bpf_ver.bv_minor < BPF_MINOR_VERSION)) { char buffer[256]; sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)", BPF_MAJOR_VERSION, BPF_MINOR_VERSION, bpf_ver.bv_major, bpf_ver.bv_minor); rp_fatal(buffer); } /* allocate a receive packet buffer */ if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) { fatalSys("ioctl(BIOCGBLEN)"); } if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) { rp_fatal("malloc"); } /* reads should return as soon as there is a packet available */ optval = 1; if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) { fatalSys("ioctl(BIOCIMMEDIATE)"); } /* Bind the interface to the filter */ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, &ifr) < 0) { char buffer[256]; sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s", ifname); rp_fatal(buffer); } syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d", ifname, hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5], bpfName, bpfLength); return fd; }
int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr) { int fd; long buf[MAXDLBUF]; union DL_primitives *dlp; char base_dev[PATH_MAX]; int ppa; if(strlen(ifname) > PATH_MAX) { rp_fatal("socket: Interface name too long"); } if (strlen(ifname) < 2) { rp_fatal("socket: Interface name too short"); } ppa = atoi(&ifname[strlen(ifname)-1]); strncpy(base_dev, ifname, PATH_MAX); base_dev[strlen(base_dev)-1] = '\0'; dlp = (union DL_primitives*) buf; if ( (fd = open(base_dev, O_RDWR)) < 0) { if (errno == EPERM) { rp_fatal("Cannot create raw socket -- pppoe must be run as root."); } if (errno == ENOENT) { char ifname[512]; snprintf(ifname, sizeof(ifname), "/dev/%s", base_dev); if ((fd = open(ifname, O_RDWR)) < 0) { if (errno == EPERM) { rp_fatal("Cannot create raw socket -- pppoe must be run as root."); } } } } if (fd < 0) { fatalSys("socket"); } dlattachreq(fd, ppa); dlokack(fd, (char *)buf); dlbindreq(fd, type, 0, DL_CLDLS, 0, 0); dlbindack(fd, (char *)buf); dlinforeq(fd); dlinfoack(fd, (char *)buf); dl_abssaplen = ABS(dlp->info_ack.dl_sap_length); dl_saplen = dlp->info_ack.dl_sap_length; if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen)) fatalSys("invalid destination physical address length"); dl_addrlen = dl_abssaplen + ETHERADDRL; memcpy(hwaddr, (u_char*)((char*)(dlp) + (int)(dlp->info_ack.dl_addr_offset)), ETHERADDRL); if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) { fatalSys("DLIOCRAW"); } if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH"); return fd; }
/********************************************************************** *%FUNCTION: discovery *%ARGUMENTS: * conn -- PPPoE connection info structure *%RETURNS: * Nothing *%DESCRIPTION: * Performs the PPPoE discovery phase ***********************************************************************/ void discovery(PPPoEConnection *conn) { int padiAttempts = 0; int padrAttempts = 0; int timeout = PADI_TIMEOUT; /* Skip discovery and don't open discovery socket? */ if (conn->skipDiscovery && conn->noDiscoverySocket) { conn->discoveryState = STATE_SESSION; PPPD_DEBUG(printf("%s %d\n",__FILE__,__LINE__)); return; } conn->discoverySocket = openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth); /* Skip discovery? */ if (conn->skipDiscovery) { conn->discoveryState = STATE_SESSION; if (conn->killSession) { sendPADT(conn, "RP-PPPoE: Session killed manually"); exit(0); } PPPD_DEBUG(printf("%s %d\n",__FILE__,__LINE__)); return; } do { PPPD_DEBUG(printf("%s %d\n",__FILE__,__LINE__)); padiAttempts++; if (padiAttempts > MAX_PADI_ATTEMPTS) { rp_fatal("Timeout waiting for PADO packets"); } sendPADI(conn); conn->discoveryState = STATE_SENT_PADI; waitForPADO(conn, timeout); /* If we're just probing for access concentrators, don't do exponential backoff. This reduces the time for an unsuccessful probe to 15 seconds. */ if (!conn->printACNames) { timeout *= 2; } if (conn->printACNames && conn->numPADOs) { break; } } while (conn->discoveryState == STATE_SENT_PADI); /* If we're only printing access concentrator names, we're done */ if (conn->printACNames) { printf("--------------------------------------------------\n"); exit(0); } PPPD_DEBUG(printf("%s %d\n",__FILE__,__LINE__)); timeout = PADI_TIMEOUT; do { PPPD_DEBUG(printf("%s %d\n",__FILE__,__LINE__)); padrAttempts++; if (padrAttempts > MAX_PADI_ATTEMPTS) { rp_fatal("Timeout waiting for PADS packets"); } sendPADR(conn); conn->discoveryState = STATE_SENT_PADR; waitForPADS(conn, timeout); timeout *= 2; } while (conn->discoveryState == STATE_SENT_PADR); /* We're done. */ free(conn->serviceName);//mcli conn->serviceName=NULL;//mcli conn->discoveryState = STATE_SESSION; PPPD_DEBUG(printf("%s %d\n",__FILE__,__LINE__)); return; }
void sigalrm(int sig) { (void) rp_fatal("sigalrm: TIMEOUT"); }
void sysErr(char const *str) { rp_fatal(str); }