/********************************************************************** *%FUNCTION: relayHandlePADI *%ARGUMENTS: * iface -- interface on which packet was received * packet -- the PADI packet *%RETURNS: * Nothing *%DESCRIPTION: * Receives and processes a PADI packet. ***********************************************************************/ void relayHandlePADI(PPPoEInterface const *iface, PPPoEPacket *packet, int size) { PPPoETag tag; unsigned char *loc; int i, r; int ifIndex; /* Can a client legally be behind this interface? */ if (!iface->clientOK) { syslog(LOG_ERR, "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } /* Source address must be unicast */ if (NOT_UNICAST(packet->ethHdr.h_source)) { syslog(LOG_ERR, "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } /* Destination address must be broadcast */ if (NOT_BROADCAST(packet->ethHdr.h_dest)) { syslog(LOG_ERR, "PADI packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not to a broadcast address", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } /* Get array index of interface */ ifIndex = iface - Interfaces; loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag); if (!loc) { tag.type = htons(TAG_RELAY_SESSION_ID); tag.length = htons(MY_RELAY_TAG_LEN); memcpy(tag.payload, &ifIndex, sizeof(ifIndex)); memcpy(tag.payload+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN); /* Add a relay tag if there's room */ r = addTag(packet, &tag); if (r < 0) return; size += r; } else { /* We do not re-use relay-id tags. Drop the frame. The RFC says the relay agent SHOULD return a Generic-Error tag, but this does not make sense for PADI packets. */ return; } /* Broadcast the PADI on all AC-capable interfaces except the interface on which it came */ for (i=0; i < NumInterfaces; i++) { if (iface == &Interfaces[i]) continue; if (!Interfaces[i].acOK) continue; memcpy(packet->ethHdr.h_source, Interfaces[i].mac, ETH_ALEN); sendPacket(NULL, Interfaces[i].discoverySock, packet, size); } }
/********************************************************************** *%FUNCTION: relayHandlePADR *%ARGUMENTS: * iface -- interface on which packet was received * packet -- the PADR packet *%RETURNS: * Nothing *%DESCRIPTION: * Receives and processes a PADR packet. ***********************************************************************/ void relayHandlePADR(PPPoEInterface const *iface, PPPoEPacket *packet, int size) { PPPoETag tag; unsigned char *loc; int ifIndex; int cliIndex; /* Can a client legally be behind this interface? */ if (!iface->clientOK) { syslog(LOG_ERR, "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } cliIndex = iface - Interfaces; /* Source address must be unicast */ if (NOT_UNICAST(packet->ethHdr.h_source)) { syslog(LOG_ERR, "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } /* Destination address must be interface's MAC address */ if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) { return; } /* Find relay tag */ loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag); if (!loc) { syslog(LOG_ERR, "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } /* If it's the wrong length, ignore it */ if (ntohs(tag.length) != MY_RELAY_TAG_LEN) { syslog(LOG_ERR, "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } /* Extract interface index */ memcpy(&ifIndex, tag.payload, sizeof(ifIndex)); if (ifIndex < 0 || ifIndex >= NumInterfaces || !Interfaces[ifIndex].acOK || iface == &Interfaces[ifIndex]) { syslog(LOG_ERR, "PADR packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } /* Replace Relay-ID tag with opposite-direction tag */ memcpy(loc+TAG_HDR_SIZE, &cliIndex, sizeof(cliIndex)); memcpy(loc+TAG_HDR_SIZE+sizeof(ifIndex), packet->ethHdr.h_source, ETH_ALEN); /* Set destination address to MAC address in relay ID */ memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN); /* Set source address to MAC address of interface */ memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN); /* Send the PADR to the proper access concentrator */ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size); }
/********************************************************************** *%FUNCTION: relayHandlePADS *%ARGUMENTS: * iface -- interface on which packet was received * packet -- the PADS packet *%RETURNS: * Nothing *%DESCRIPTION: * Receives and processes a PADS packet. ***********************************************************************/ void relayHandlePADS(PPPoEInterface const *iface, PPPoEPacket *packet, int size) { PPPoETag tag; unsigned char *loc; int ifIndex; int acIndex; PPPoESession *ses = NULL; SessionHash *sh; /* Can a server legally be behind this interface? */ if (!iface->acOK) { syslog(LOG_ERR, "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not permitted", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } acIndex = iface - Interfaces; /* Source address must be unicast */ if (NOT_UNICAST(packet->ethHdr.h_source)) { syslog(LOG_ERR, "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s not from a unicast address", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } /* Destination address must be interface's MAC address */ if (memcmp(packet->ethHdr.h_dest, iface->mac, ETH_ALEN)) { return; } /* Find relay tag */ loc = findTag(packet, TAG_RELAY_SESSION_ID, &tag); if (!loc) { syslog(LOG_ERR, "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have Relay-Session-Id tag", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } /* If it's the wrong length, ignore it */ if (ntohs(tag.length) != MY_RELAY_TAG_LEN) { syslog(LOG_ERR, "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s does not have correct length Relay-Session-Id tag", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } /* Extract interface index */ memcpy(&ifIndex, tag.payload, sizeof(ifIndex)); if (ifIndex < 0 || ifIndex >= NumInterfaces || !Interfaces[ifIndex].clientOK || iface == &Interfaces[ifIndex]) { syslog(LOG_ERR, "PADS packet from %02x:%02x:%02x:%02x:%02x:%02x on interface %s has invalid interface in Relay-Session-Id tag", packet->ethHdr.h_source[0], packet->ethHdr.h_source[1], packet->ethHdr.h_source[2], packet->ethHdr.h_source[3], packet->ethHdr.h_source[4], packet->ethHdr.h_source[5], iface->name); return; } /* If session ID is zero, it's the AC respoding with an error. Just relay it; do not create a session */ if (packet->session != htons(0)) { /* Check for existing session */ sh = findSession(packet->ethHdr.h_source, packet->session); if (sh) ses = sh->ses; /* If already an existing session, assume it's a duplicate PADS. Send the frame, but do not create a new session. Is this the right thing to do? Arguably, should send an error to the client and a PADT to the server, because this could happen due to a server crash and reboot. */ if (!ses) { /* Create a new session */ ses = createSession(iface, &Interfaces[ifIndex], packet->ethHdr.h_source, loc + TAG_HDR_SIZE + sizeof(ifIndex), packet->session); if (!ses) { /* Can't allocate session -- send error PADS to client and PADT to server */ PPPoETag hostUniq, *hu; if (findTag(packet, TAG_HOST_UNIQ, &hostUniq)) { hu = &hostUniq; } else { hu = NULL; } relaySendError(CODE_PADS, htons(0), &Interfaces[ifIndex], loc + TAG_HDR_SIZE + sizeof(ifIndex), hu, "RP-PPPoE: Relay: Unable to allocate session"); relaySendError(CODE_PADT, packet->session, iface, packet->ethHdr.h_source, NULL, "RP-PPPoE: Relay: Unable to allocate session"); return; } } /* Replace session number */ packet->session = ses->sesNum; } /* Remove relay-ID tag */ removeBytes(packet, loc, MY_RELAY_TAG_LEN + TAG_HDR_SIZE); size -= (MY_RELAY_TAG_LEN + TAG_HDR_SIZE); /* Set destination address to MAC address in relay ID */ memcpy(packet->ethHdr.h_dest, tag.payload + sizeof(ifIndex), ETH_ALEN); /* Set source address to MAC address of interface */ memcpy(packet->ethHdr.h_source, Interfaces[ifIndex].mac, ETH_ALEN); /* Send the PADS to the proper client */ sendPacket(NULL, Interfaces[ifIndex].discoverySock, packet, size); }
/********************************************************************** *%FUNCTION: waitForPADO *%ARGUMENTS: * conn -- PPPoEConnection structure * timeout -- how long to wait (in seconds) *%RETURNS: * Nothing *%DESCRIPTION: * Waits for a PADO packet and copies useful information ***********************************************************************/ void waitForPADO(PPPoEConnection *conn, int timeout) { fd_set readable; int r; struct timeval tv; struct timeval expire_at; PPPoEPacket packet; int len; struct PacketCriteria pc; pc.conn = conn; pc.acNameOK = (conn->acName) ? 0 : 1; pc.serviceNameOK = (conn->serviceName) ? 0 : 1; pc.seenACName = 0; pc.seenServiceName = 0; conn->seenMaxPayload = 0; conn->error = 0; if (gettimeofday(&expire_at, NULL) < 0) { error("gettimeofday (waitForPADO): %m"); return; } expire_at.tv_sec += timeout; do { if (BPF_BUFFER_IS_EMPTY) { if (!time_left(&tv, &expire_at)) return; /* Timed out */ FD_ZERO(&readable); FD_SET(conn->discoverySocket, &readable); while(1) { r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv); if (r >= 0 || errno != EINTR) break; } if (r < 0) { error("select (waitForPADO): %m"); return; } if (r == 0) return; /* Timed out */ } /* Get the packet */ receivePacket(conn->discoverySocket, &packet, &len); /* Check length */ if (ntohs(packet.length) + HDR_SIZE > len) { error("Bogus PPPoE length field (%u)", (unsigned int) ntohs(packet.length)); continue; } #ifdef USE_BPF /* If it's not a Discovery packet, loop again */ if (etherType(&packet) != Eth_PPPOE_Discovery) continue; #endif /* If it's not for us, loop again */ if (!packetIsForMe(conn, &packet)) continue; if (packet.code == CODE_PADO) { if (NOT_UNICAST(packet.ethHdr.h_source)) { error("Ignoring PADO packet from non-unicast MAC address"); continue; } if (conn->req_peer && memcmp(packet.ethHdr.h_source, conn->req_peer_mac, ETH_ALEN) != 0) { warn("Ignoring PADO packet from wrong MAC address"); continue; } if (parsePacket(&packet, parsePADOTags, &pc) < 0) return; if (conn->error) return; if (!pc.seenACName) { error("Ignoring PADO packet with no AC-Name tag"); continue; } if (!pc.seenServiceName) { error("Ignoring PADO packet with no Service-Name tag"); continue; } conn->numPADOs++; if (pc.acNameOK && pc.serviceNameOK) { memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN); conn->discoveryState = STATE_RECEIVED_PADO; break; } } } while (conn->discoveryState != STATE_RECEIVED_PADO); }
/********************************************************************** *%FUNCTION: waitForPADO *%ARGUMENTS: * conn -- PPPoEConnection structure * timeout -- how long to wait (in seconds) *%RETURNS: * Nothing *%DESCRIPTION: * Waits for a PADO packet and copies useful information ***********************************************************************/ void waitForPADO(PPPoEConnection *conn, int timeout) { fd_set readable; int r; struct timeval tv; PPPoEPacket packet; int len; struct PacketCriteria pc; pc.conn = conn; pc.acNameOK = (conn->acName) ? 0 : 1; pc.serviceNameOK = (conn->serviceName) ? 0 : 1; pc.seenACName = 0; pc.seenServiceName = 0; do { if (BPF_BUFFER_IS_EMPTY) { tv.tv_sec = timeout; tv.tv_usec = 0; FD_ZERO(&readable); FD_SET(conn->discoverySocket, &readable); while(1) { r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv); if (r >= 0 || errno != EINTR) break; } if (r < 0) { fatalSys("select (waitForPADO)"); } if (r == 0) return; /* Timed out */ } /* Get the packet */ receivePacket(conn->discoverySocket, &packet, &len); /* Check length */ if (ntohs(packet.length) + HDR_SIZE > len) { syslog(LOG_ERR, "Bogus PPPoE length field (%u)", (unsigned int) ntohs(packet.length)); continue; } #ifdef USE_BPF /* If it's not a Discovery packet, loop again */ if (etherType(&packet) != Eth_PPPOE_Discovery) continue; #endif if (conn->debugFile) { dumpPacket(conn->debugFile, &packet, "RCVD"); fprintf(conn->debugFile, "\n"); fflush(conn->debugFile); } /* If it's not for us, loop again */ if (!packetIsForMe(conn, &packet)) continue; if (packet.code == CODE_PADO) { if (NOT_UNICAST(packet.ethHdr.h_source)) { printErr("Ignoring PADO packet from non-unicast MAC address"); continue; } parsePacket(&packet, parsePADOTags, &pc); if (!pc.seenACName) { printErr("Ignoring PADO packet with no AC-Name tag"); continue; } if (!pc.seenServiceName) { printErr("Ignoring PADO packet with no Service-Name tag"); continue; } conn->numPADOs++; if (conn->printACNames) { printf("--------------------------------------------------\n"); } if (pc.acNameOK && pc.serviceNameOK) { memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN); if (conn->printACNames) { printf("AC-Ethernet-Address: %02x:%02x:%02x:%02x:%02x:%02x\n", (unsigned) conn->peerEth[0], (unsigned) conn->peerEth[1], (unsigned) conn->peerEth[2], (unsigned) conn->peerEth[3], (unsigned) conn->peerEth[4], (unsigned) conn->peerEth[5]); continue; } conn->discoveryState = STATE_RECEIVED_PADO; break; } } } while (conn->discoveryState != STATE_RECEIVED_PADO); }
/********************************************************************** *%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: 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) { fatal("Cannot create raw socket -- pppoe must be run as root."); } error("Can't open socket for pppoe: %m"); return -1; } if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) { error("Can't set socket options for pppoe: %m"); close(fd); return -1; } /* Fill in hardware address */ if (hwaddr) { strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { error("Can't get hardware address for %s: %m", ifname); close(fd); return -1; } memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); #ifdef ARPHRD_ETHER if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { warn("Interface %.16s is not Ethernet", ifname); } #endif if (NOT_UNICAST(hwaddr)) { fatal("Can't use interface %.16s: it has broadcast/multicast MAC address", ifname); } } /* Sanity check on MTU */ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) { error("Can't get MTU for %s: %m", ifname); } else if (ifr.ifr_mtu < ETH_DATA_LEN) { error("Interface %.16s has MTU of %d -- should be at least %d.", ifname, ifr.ifr_mtu, ETH_DATA_LEN); error("This may cause serious connection problems."); } #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) { error("Could not get interface index for %s: %m", ifname); close(fd); return -1; } 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) { error("Failed to bind to interface %s: %m", ifname); close(fd); return -1; } return fd; }
static int wait_for_pado (int n, PPPoEConnection* conns) { int r, i, all; size_t len; fd_set readable; PPPoEPacket packet; PacketCriteria pc; struct timeval tv; tv.tv_sec = PADO_TIMEOUT; tv.tv_usec = 0; while (1) { FD_ZERO (&readable); for (i = 0; i < n; i++) if (conns[i].fd != -1) FD_SET (conns[i].fd, &readable); do { r = select (FD_SETSIZE, &readable, NULL, NULL, &tv); } while (r == -1 && errno == EINTR); if (r < 0) { ADD2LOG ("select: %m\n"); return 0; } if (r == 0) { ADD2LOG ("Timeout waiting for PADO packets\n"); return 0; } for (i = 0; i < n; i++) { PPPoEConnection* conn = &conns[i]; if (conn->fd == -1 || !FD_ISSET (conn->fd, &readable)) continue; pc.conn = conn; pc.acname_ok = 0; pc.servicename_ok = 0; pc.error = 0; /* Get the packet */ if (!receive_packet (conn->fd, &packet, &len)) continue; /* Check length */ if (ntohs (packet.length) + HDR_SIZE > len) { ADD2LOG ("%s: Bogus PPPoE length field (%u)\n", conn->ifname, (unsigned int) ntohs (packet.length)); continue; } /* If it's not for us, loop again */ if (!packet_for_me (conn, &packet)) continue; if (packet.code != CODE_PADO) continue; if (NOT_UNICAST (packet.ethHdr.h_source)) { ADD2LOG ("%s: Ignoring PADO packet from non-unicast MAC " "address\n", conn->ifname); continue; } parse_packet (conn, &packet, parse_pado_tags, &pc); if (!pc.acname_ok) { ADD2LOG ("%s: Wrong or missing AC-Name tag\n", conn->ifname); continue; } if (!pc.servicename_ok) { ADD2LOG ("%s: Wrong or missing Service-Name tag\n", conn->ifname); continue; } if (pc.error) { ADD2LOG ("%s: Ignoring PADO packet with some Error tag\n", conn->ifname); continue; } memcpy (conn->peer_mac, packet.ethHdr.h_source, ETH_ALEN); ADD2LOG ("%s: Received correct PADO packet\n", conn->ifname); conn->received_pado = 1; } all = 1; for (i = 0; i < n; i++) if (conns[i].fd != -1 && !conns[i].received_pado) all = 0; if (all) return 1; } }
static int open_interfaces (int n, PPPoEConnection* conns) { int ret = 0, i; for (i = 0; i < n; i++) { PPPoEConnection* conn = &conns[i]; conn->fd = socket (PF_PACKET, SOCK_RAW, htons (ETH_PPPOE_DISCOVERY)); if (conn->fd < 0) { ADD2LOG ("%s: socket failed: %m\n", conn->ifname); continue; } int one = 1; if (setsockopt (conn->fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof (one)) < 0) { ADD2LOG ("%s: setsockopt failed: %m\n", conn->ifname); goto error; } /* Fill in hardware address */ struct ifreq ifr; struct sockaddr_ll sa; memset (&sa, 0, sizeof (sa)); strncpy (ifr.ifr_name, conn->ifname, sizeof (ifr.ifr_name)); if (ioctl (conn->fd, SIOCGIFHWADDR, &ifr) < 0) { ADD2LOG ("%s: ioctl (SIOCGIFHWADDR) failed: %m\n", conn->ifname); goto error; } memcpy (conn->my_mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN); if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { ADD2LOG ("%s: Interface is not ethernet\n", conn->ifname); goto error; } if (NOT_UNICAST (conn->my_mac)) { ADD2LOG ("%s: Interface has broadcast/multicast MAC address?\n", conn->ifname); goto error; } /* Sanity check on MTU */ strncpy (ifr.ifr_name, conn->ifname, sizeof (ifr.ifr_name)); if (ioctl (conn->fd, SIOCGIFMTU, &ifr) < 0) { ADD2LOG ("%s: ioctl (SIOCGIFMTU) failed: %m\n", conn->ifname); goto error; } if (ifr.ifr_mtu < ETH_DATA_LEN) { ADD2LOG ("%s: Interface has too low MTU\n", conn->ifname); goto error; } /* Skip interfaces that have the SLAVE flag set */ strncpy (ifr.ifr_name, conn->ifname, sizeof (ifr.ifr_name)); if (ioctl (conn->fd, SIOCGIFFLAGS, &ifr) < 0) { ADD2LOG ("%s: ioctl (SIOCGIFFLAGS) failed: %m\n", conn->ifname); goto error; } if (ifr.ifr_ifru.ifru_flags & IFF_SLAVE) { ADD2LOG ("%s: Interface has SLAVE flag set\n", conn->ifname); goto error; } /* Get interface index */ sa.sll_family = AF_PACKET; sa.sll_protocol = htons (ETH_PPPOE_DISCOVERY); strncpy (ifr.ifr_name, conn->ifname, sizeof (ifr.ifr_name)); if (ioctl (conn->fd, SIOCGIFINDEX, &ifr) < 0) { ADD2LOG ("%s: ioctl (SIOCFIGINDEX) failed: Could not get interface " "index\n", conn->ifname); goto error; } sa.sll_ifindex = ifr.ifr_ifindex; /* We're only interested in packets on specified interface */ if (bind (conn->fd, (struct sockaddr*) &sa, sizeof (sa)) < 0) { ADD2LOG ("%s: bind failed: %m\n", conn->ifname); goto error; } ret = 1; continue; error: close (conn->fd); conn->fd = -1; } return ret; }
static void waitForPADO(PPPoEConnection * conn, int timeout) { fd_set readable; int r = -1; struct timeval tv; PPPoEPacket packet; int len; struct PacketCriteria pc; pc.conn = conn; pc.acNameOK = (conn->acName) ? 0 : 1; pc.serviceNameOK = (conn->serviceName) ? 0 : 1; pc.seenACName = 0; pc.seenServiceName = 0; do { tv.tv_sec = timeout; tv.tv_usec = 0; FD_ZERO(&readable); FD_SET(conn->discoverySocket, &readable); while (!got_sigterm) /* Modified by Kwest Wan 20080919 to terminate pppd immediately if PPPoE server don't reponse */ { d_dbg("[%d]: waitPADO select >>>>\n", getpid()); r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv); d_dbg("[%d]: waitPADO select (%d) <<<<\n", getpid(), r); if (r >= 0 || errno != EINTR) break; } if (r < 0) { d_error("[%d]: select (waitForPADS)\n", getpid()); return; } if (r == 0) return; /* Get the packet */ d_dbg("[%d]: receivePacket >>>\n", getpid()); receivePacket(conn->discoverySocket, &packet, &len); d_dbg("[%d]: receivePacket <<<\n", getpid()); /* Check length */ if (ntohs(packet.length) + HDR_SIZE > len) { d_error("[%d]: Bogus PPPoE length field (%u)\n", getpid(), (unsigned int)ntohs(packet.length)); continue; } /* If it's not for us, loop again */ if (!packetIsForMe(conn, &packet)) { d_dbg("[%d]: packet is not for me!\n", getpid()); continue; } /* Is it PADS ? */ if (packet.code == CODE_PADO) { if (NOT_UNICAST(packet.ethHdr.h_source)) { d_info("[%d]: Ignoring PADO packet from non-unicast MAC address\n", getpid()); #ifndef LOGNUM #ifdef ELBOX_PROGS_GPL_SYSLOGD_AP syslog(ALOG_NOTICE|LOG_NOTICE, "[Notice]PPPoE: Ignore PADO packet from non-unicast MAC address. (%s)", linkname); #else syslog(ALOG_NOTICE|LOG_NOTICE, "PPPoE: Ignore PADO packet from non-unicast MAC address. (%s)", linkname); #endif #else syslog(ALOG_NOTICE|LOG_NOTICE, "NTC:029[%s]", linkname); #endif continue; } kpppoe_parsePacket(&packet, parsePADOTags, &pc); if (!pc.seenACName) { d_info("[%d]: Ignoring PADO packet with no AC-Name tag\n", getpid()); #ifndef LOGNUM #ifdef ELBOX_PROGS_GPL_SYSLOGD_AP syslog(ALOG_NOTICE|LOG_NOTICE, "[Notice]PPPoE: Ignore PADO packet with no AC-Name tag. (%s)", linkname); #else syslog(ALOG_NOTICE|LOG_NOTICE, "PPPoE: Ignore PADO packet with no AC-Name tag. (%s)", linkname); #endif #else syslog(ALOG_NOTICE|LOG_NOTICE, "NTC:030[%s]", linkname); #endif continue; } if (!pc.seenServiceName) { d_info("[%d]: Ignoring PADO packet with no Service-Name tag\n", getpid()); #ifndef LOGNUM #ifdef ELBOX_PROGS_GPL_SYSLOGD_AP syslog(ALOG_NOTICE|LOG_NOTICE, "[Notice]PPPoE: Ignore PADO packet with no Service-Name tag. (%s)", linkname); #else syslog(ALOG_NOTICE|LOG_NOTICE, "PPPoE: Ignore PADO packet with no Service-Name tag. (%s)", linkname); #endif #else syslog(ALOG_NOTICE|LOG_NOTICE, "NTC:031[%s]", linkname); #endif continue; } conn->numPADOs++; if (conn->printACNames) printf("------------------------------------------------------\n"); update_statusfile("PPPoE:PADO"); d_dbg("[%d]: acNameOK:%d, serviceNameOK:%d\n", getpid(), pc.acNameOK, pc.serviceNameOK); if (pc.acNameOK && pc.serviceNameOK) { memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN); if (conn->printACNames) { printf("AC-Ethernet-Address: %02x:%02x:%02x:%02x:%02x:%02x\n", (unsigned)conn->peerEth[0], (unsigned)conn->peerEth[1], (unsigned)conn->peerEth[2], (unsigned)conn->peerEth[3], (unsigned)conn->peerEth[4], (unsigned)conn->peerEth[5]); continue; } conn->discoveryState = STATE_RECEIVED_PADO; #ifndef LOGNUM #ifdef ELBOX_PROGS_GPL_SYSLOGD_AP syslog(ALOG_NOTICE|LOG_NOTICE, "[Notice]PPPoE: Received PADO for %s, from: %02x:%02x:%02x:%02x:%02x:%02x", linkname, (unsigned)conn->peerEth[0], (unsigned)conn->peerEth[1], (unsigned)conn->peerEth[2], (unsigned)conn->peerEth[3], (unsigned)conn->peerEth[4], (unsigned)conn->peerEth[5]); #else syslog(ALOG_NOTICE|LOG_NOTICE, "PPPoE: Received PADO for %s, from: %02x:%02x:%02x:%02x:%02x:%02x", linkname, (unsigned)conn->peerEth[0], (unsigned)conn->peerEth[1], (unsigned)conn->peerEth[2], (unsigned)conn->peerEth[3], (unsigned)conn->peerEth[4], (unsigned)conn->peerEth[5]); #endif #else syslog(ALOG_NOTICE|LOG_NOTICE, "NTC:026[%s][%02x:%02x:%02x:%02x:%02x:%02x]", linkname, (unsigned)conn->peerEth[0], (unsigned)conn->peerEth[1], (unsigned)conn->peerEth[2], (unsigned)conn->peerEth[3], (unsigned)conn->peerEth[4], (unsigned)conn->peerEth[5]); #endif break; } } else { d_dbg("[%d]: this is not PADO!\n", getpid()); } } while (conn->discoveryState != STATE_RECEIVED_PADO); }