18ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project/*
28ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project * Perform PPPoE discovery
38ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project *
48ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project * Copyright (C) 2000-2001 by Roaring Penguin Software Inc.
58ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project * Copyright (C) 2004 Marco d'Itri <md@linux.it>
68ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project *
78ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project * This program may be distributed according to the terms of the GNU
88ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project * General Public License, version 2 or (at your option) any later version.
98ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project *
108ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project */
118ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
128ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include <stdio.h>
138ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include <stdlib.h>
148ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include <unistd.h>
158ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include <errno.h>
168ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include <string.h>
178ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
188ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include "pppoe.h"
198ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
201286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#ifdef HAVE_UNISTD_H
211286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#include <unistd.h>
221286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#endif
231286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
241286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#ifdef HAVE_NETPACKET_PACKET_H
251286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#include <netpacket/packet.h>
261286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#elif defined(HAVE_LINUX_IF_PACKET_H)
271286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#include <linux/if_packet.h>
281286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#endif
291286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
301286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#ifdef HAVE_NET_ETHERNET_H
311286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#include <net/ethernet.h>
321286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#endif
331286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
341286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#ifdef HAVE_ASM_TYPES_H
351286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#include <asm/types.h>
361286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#endif
371286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
381286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#ifdef HAVE_SYS_IOCTL_H
391286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#include <sys/ioctl.h>
401286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#endif
411286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
421286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#include <errno.h>
431286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#include <stdlib.h>
441286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#include <string.h>
451286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
461286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#ifdef HAVE_NET_IF_ARP_H
471286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#include <net/if_arp.h>
481286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#endif
491286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
508ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectchar *xstrdup(const char *s);
518ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectvoid usage(void);
528ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
538ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectvoid die(int status)
548ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project{
558ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	exit(status);
568ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project}
578ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
581286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley/* Initialize frame types to RFC 2516 values.  Some broken peers apparently
591286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley   use different frame types... sigh... */
601286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
611286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleyUINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY;
621286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleyUINT16_t Eth_PPPOE_Session   = ETH_PPPOE_SESSION;
631286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
641286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley/**********************************************************************
651286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%FUNCTION: etherType
661286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%ARGUMENTS:
671286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* packet -- a received PPPoE packet
681286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%RETURNS:
691286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* ethernet packet type (see /usr/include/net/ethertypes.h)
701286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%DESCRIPTION:
711286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Checks the ethernet packet header to determine its type.
721286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* We should only be receveing DISCOVERY and SESSION types if the BPF
731286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* is set up correctly.  Logs an error if an unexpected type is received.
741286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Note that the ethernet type names come from "pppoe.h" and the packet
751286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* packet structure names use the LINUX dialect to maintain consistency
761286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* with the rest of this file.  See the BSD section of "pppoe.h" for
771286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* translations of the data structure names.
781286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley***********************************************************************/
791286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleyUINT16_t
801286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleyetherType(PPPoEPacket *packet)
811286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley{
821286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);
831286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {
841286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fprintf(stderr, "Invalid ether type 0x%x\n", type);
851286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
861286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    return type;
871286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley}
881286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
891286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley/**********************************************************************
901286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%FUNCTION: openInterface
911286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%ARGUMENTS:
921286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* ifname -- name of interface
931286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* type -- Ethernet frame type
941286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* hwaddr -- if non-NULL, set to the hardware address
951286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%RETURNS:
961286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* A raw socket for talking to the Ethernet card.  Exits on error.
971286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%DESCRIPTION:
981286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Opens a raw Ethernet socket
991286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley***********************************************************************/
1001286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langleyint
1011286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleyopenInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
1021286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley{
1031286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    int optval=1;
1041286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    int fd;
1051286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    struct ifreq ifr;
1061286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    int domain, stype;
1071286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1081286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#ifdef HAVE_STRUCT_SOCKADDR_LL
1091286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    struct sockaddr_ll sa;
1101286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#else
1111286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    struct sockaddr sa;
1121286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#endif
1131286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1141286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    memset(&sa, 0, sizeof(sa));
1151286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1161286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#ifdef HAVE_STRUCT_SOCKADDR_LL
1171286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    domain = PF_PACKET;
1181286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    stype = SOCK_RAW;
1191286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#else
1201286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    domain = PF_INET;
1211286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    stype = SOCK_PACKET;
1221286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#endif
1231286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1241286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if ((fd = socket(domain, stype, htons(type))) < 0) {
1251286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	/* Give a more helpful message for the common error case */
1261286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (errno == EPERM) {
1271286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
1281286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
1291286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fatalSys("socket");
1301286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
1311286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1321286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
1331286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fatalSys("setsockopt");
1341286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
1351286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1361286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    /* Fill in hardware address */
1371286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (hwaddr) {
1381286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1391286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
1401286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    fatalSys("ioctl(SIOCGIFHWADDR)");
1411286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
1421286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
1431286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#ifdef ARPHRD_ETHER
1441286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
1451286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    char buffer[256];
1461286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    sprintf(buffer, "Interface %.16s is not Ethernet", ifname);
1471286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    rp_fatal(buffer);
1481286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
1491286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#endif
1501286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (NOT_UNICAST(hwaddr)) {
1511286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    char buffer[256];
1521286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    sprintf(buffer,
1531286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		    "Interface %.16s has broadcast/multicast MAC address??",
1541286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		    ifname);
1551286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    rp_fatal(buffer);
1561286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
1571286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
1581286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1591286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    /* Sanity check on MTU */
1601286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1611286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
1621286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fatalSys("ioctl(SIOCGIFMTU)");
1631286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
1641286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (ifr.ifr_mtu < ETH_DATA_LEN) {
1651286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fprintf(stderr, "Interface %.16s has MTU of %d -- should be %d.\n",
1661286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	      ifname, ifr.ifr_mtu, ETH_DATA_LEN);
1671286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fprintf(stderr, "You may have serious connection problems.\n");
1681286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
1691286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1701286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#ifdef HAVE_STRUCT_SOCKADDR_LL
1711286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    /* Get interface index */
1721286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    sa.sll_family = AF_PACKET;
1731286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    sa.sll_protocol = htons(type);
1741286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1751286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1761286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
1771286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
1781286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
1791286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    sa.sll_ifindex = ifr.ifr_ifindex;
1801286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1811286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#else
1821286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    strcpy(sa.sa_data, ifname);
1831286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#endif
1841286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1851286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    /* We're only interested in packets on specified interface */
1861286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
1871286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fatalSys("bind");
1881286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
1891286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1901286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    return fd;
1911286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley}
1921286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1931286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
1941286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley/***********************************************************************
1951286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%FUNCTION: sendPacket
1961286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%ARGUMENTS:
1971286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* sock -- socket to send to
1981286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* pkt -- the packet to transmit
1991286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* size -- size of packet (in bytes)
2001286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%RETURNS:
2011286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* 0 on success; -1 on failure
2021286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%DESCRIPTION:
2031286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Transmits a packet
2041286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley***********************************************************************/
2051286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langleyint
2061286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleysendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
2071286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley{
2081286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#if defined(HAVE_STRUCT_SOCKADDR_LL)
2091286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (send(sock, pkt, size, 0) < 0) {
2101286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	sysErr("send (sendPacket)");
2111286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	return -1;
2121286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
2131286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#else
2141286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    struct sockaddr sa;
2151286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
2161286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (!conn) {
2171286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	rp_fatal("relay and server not supported on Linux 2.0 kernels");
2181286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
2191286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    strcpy(sa.sa_data, conn->ifName);
2201286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
2211286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	sysErr("sendto (sendPacket)");
2221286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	return -1;
2231286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
2241286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#endif
2251286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    return 0;
2261286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley}
2271286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
2281286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley/***********************************************************************
2291286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%FUNCTION: receivePacket
2301286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%ARGUMENTS:
2311286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* sock -- socket to read from
2321286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* pkt -- place to store the received packet
2331286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* size -- set to size of packet in bytes
2341286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%RETURNS:
2351286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* >= 0 if all OK; < 0 if error
2361286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%DESCRIPTION:
2371286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Receives a packet
2381286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley***********************************************************************/
2391286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langleyint
2401286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleyreceivePacket(int sock, PPPoEPacket *pkt, int *size)
2411286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley{
2421286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
2431286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	sysErr("recv (receivePacket)");
2441286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	return -1;
2451286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
2461286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    return 0;
2471286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley}
2481286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
2491286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley/**********************************************************************
2501286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%FUNCTION: parsePacket
2511286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%ARGUMENTS:
2521286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* packet -- the PPPoE discovery packet to parse
2531286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* func -- function called for each tag in the packet
2541286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* extra -- an opaque data pointer supplied to parsing function
2551286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%RETURNS:
2561286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* 0 if everything went well; -1 if there was an error
2571286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%DESCRIPTION:
2581286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Parses a PPPoE discovery packet, calling "func" for each tag in the packet.
2591286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* "func" is passed the additional argument "extra".
2601286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley***********************************************************************/
2611286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langleyint
2621286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleyparsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra)
2631286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley{
2641286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    UINT16_t len = ntohs(packet->length);
2651286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    unsigned char *curTag;
2661286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    UINT16_t tagType, tagLen;
2671286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
2681286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (PPPOE_VER(packet->vertype) != 1) {
2691286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fprintf(stderr, "Invalid PPPoE version (%d)\n",
2701286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		PPPOE_VER(packet->vertype));
2711286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	return -1;
2721286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
2731286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (PPPOE_TYPE(packet->vertype) != 1) {
2741286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fprintf(stderr, "Invalid PPPoE type (%d)\n",
2751286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		PPPOE_TYPE(packet->vertype));
2761286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	return -1;
2771286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
2781286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
2791286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    /* Do some sanity checks on packet */
2801286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (len > ETH_JUMBO_LEN - PPPOE_OVERHEAD) { /* 6-byte overhead for PPPoE header */
2811286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fprintf(stderr, "Invalid PPPoE packet length (%u)\n", len);
2821286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	return -1;
2831286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
2841286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
2851286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    /* Step through the tags */
2861286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    curTag = packet->payload;
2871286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    while(curTag - packet->payload < len) {
2881286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	/* Alignment is not guaranteed, so do this by hand... */
2891286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	tagType = (curTag[0] << 8) + curTag[1];
2901286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	tagLen = (curTag[2] << 8) + curTag[3];
2911286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (tagType == TAG_END_OF_LIST) {
2921286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    return 0;
2931286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
2941286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
2951286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    fprintf(stderr, "Invalid PPPoE tag length (%u)\n", tagLen);
2961286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    return -1;
2971286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
2981286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra);
2991286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	curTag = curTag + TAG_HDR_SIZE + tagLen;
3001286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
3011286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    return 0;
3021286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley}
3031286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
3041286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley/**********************************************************************
3051286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%FUNCTION: parseForHostUniq
3061286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%ARGUMENTS:
3071286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* type -- tag type
3081286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* len -- tag length
3091286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* data -- tag data.
3101286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* extra -- user-supplied pointer.  This is assumed to be a pointer to int.
3111286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%RETURNS:
3121286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Nothing
3131286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%DESCRIPTION:
3141286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* If a HostUnique tag is found which matches our PID, sets *extra to 1.
3151286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley***********************************************************************/
3161286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langleyvoid
3171286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleyparseForHostUniq(UINT16_t type, UINT16_t len, unsigned char *data,
3181286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		 void *extra)
3191286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley{
3201286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    int *val = (int *) extra;
3211286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (type == TAG_HOST_UNIQ && len == sizeof(pid_t)) {
3221286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	pid_t tmp;
3231286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	memcpy(&tmp, data, len);
3241286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (tmp == getpid()) {
3251286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    *val = 1;
3261286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
3271286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
3281286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley}
3291286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
3301286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley/**********************************************************************
3311286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%FUNCTION: packetIsForMe
3321286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%ARGUMENTS:
3331286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* conn -- PPPoE connection info
3341286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* packet -- a received PPPoE packet
3351286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%RETURNS:
3361286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* 1 if packet is for this PPPoE daemon; 0 otherwise.
3371286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%DESCRIPTION:
3381286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* If we are using the Host-Unique tag, verifies that packet contains
3391286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* our unique identifier.
3401286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley***********************************************************************/
3411286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langleyint
3421286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleypacketIsForMe(PPPoEConnection *conn, PPPoEPacket *packet)
3431286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley{
3441286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    int forMe = 0;
3451286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
3461286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    /* If packet is not directed to our MAC address, forget it */
3471286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (memcmp(packet->ethHdr.h_dest, conn->myEth, ETH_ALEN)) return 0;
3481286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
3491286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    /* If we're not using the Host-Unique tag, then accept the packet */
3501286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (!conn->useHostUniq) return 1;
3511286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
3521286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    parsePacket(packet, parseForHostUniq, &forMe);
3531286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    return forMe;
3541286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley}
3551286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
3561286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley/**********************************************************************
3571286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%FUNCTION: parsePADOTags
3581286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%ARGUMENTS:
3591286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* type -- tag type
3601286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* len -- tag length
3611286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* data -- tag data
3621286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* extra -- extra user data.  Should point to a PacketCriteria structure
3631286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*          which gets filled in according to selected AC name and service
3641286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*          name.
3651286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%RETURNS:
3661286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Nothing
3671286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%DESCRIPTION:
3681286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Picks interesting tags out of a PADO packet
3691286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley***********************************************************************/
3701286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langleyvoid
3711286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleyparsePADOTags(UINT16_t type, UINT16_t len, unsigned char *data,
3721286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	      void *extra)
3731286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley{
3741286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    struct PacketCriteria *pc = (struct PacketCriteria *) extra;
3751286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    PPPoEConnection *conn = pc->conn;
3761286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    int i;
3771286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
3781286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    switch(type) {
3791286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    case TAG_AC_NAME:
3801286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	pc->seenACName = 1;
3811286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	printf("Access-Concentrator: %.*s\n", (int) len, data);
3821286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (conn->acName && len == strlen(conn->acName) &&
3831286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    !strncmp((char *) data, conn->acName, len)) {
3841286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    pc->acNameOK = 1;
3851286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
3861286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	break;
3871286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    case TAG_SERVICE_NAME:
3881286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	pc->seenServiceName = 1;
3891286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (len > 0) {
3901286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    printf("       Service-Name: %.*s\n", (int) len, data);
3911286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
3921286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (conn->serviceName && len == strlen(conn->serviceName) &&
3931286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    !strncmp((char *) data, conn->serviceName, len)) {
3941286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    pc->serviceNameOK = 1;
3951286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
3961286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	break;
3971286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    case TAG_AC_COOKIE:
3981286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	printf("Got a cookie:");
3991286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	/* Print first 20 bytes of cookie */
4001286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	for (i=0; i<len && i < 20; i++) {
4011286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    printf(" %02x", (unsigned) data[i]);
4021286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
4031286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (i < len) printf("...");
4041286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	printf("\n");
4051286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	conn->cookie.type = htons(type);
4061286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	conn->cookie.length = htons(len);
4071286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	memcpy(conn->cookie.payload, data, len);
4081286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	break;
4091286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    case TAG_RELAY_SESSION_ID:
4101286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	printf("Got a Relay-ID:");
4111286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	/* Print first 20 bytes of relay ID */
4121286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	for (i=0; i<len && i < 20; i++) {
4131286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    printf(" %02x", (unsigned) data[i]);
4141286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
4151286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (i < len) printf("...");
4161286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	printf("\n");
4171286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	conn->relayId.type = htons(type);
4181286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	conn->relayId.length = htons(len);
4191286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	memcpy(conn->relayId.payload, data, len);
4201286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	break;
4211286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    case TAG_SERVICE_NAME_ERROR:
4221286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	printf("Got a Service-Name-Error tag: %.*s\n", (int) len, data);
4231286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	break;
4241286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    case TAG_AC_SYSTEM_ERROR:
4251286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	printf("Got a System-Error tag: %.*s\n", (int) len, data);
4261286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	break;
4271286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    case TAG_GENERIC_ERROR:
4281286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	printf("Got a Generic-Error tag: %.*s\n", (int) len, data);
4291286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	break;
4301286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
4311286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley}
4321286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
4331286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley/***********************************************************************
4341286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%FUNCTION: sendPADI
4351286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%ARGUMENTS:
4361286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* conn -- PPPoEConnection structure
4371286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%RETURNS:
4381286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Nothing
4391286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%DESCRIPTION:
4401286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Sends a PADI packet
4411286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley***********************************************************************/
4421286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langleyvoid
4431286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleysendPADI(PPPoEConnection *conn)
4441286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley{
4451286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    PPPoEPacket packet;
4461286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    unsigned char *cursor = packet.payload;
4471286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    PPPoETag *svc = (PPPoETag *) (&packet.payload);
4481286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    UINT16_t namelen = 0;
4491286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    UINT16_t plen;
4501286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
4511286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (conn->serviceName) {
4521286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	namelen = (UINT16_t) strlen(conn->serviceName);
4531286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
4541286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    plen = TAG_HDR_SIZE + namelen;
4551286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    CHECK_ROOM(cursor, packet.payload, plen);
4561286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
4571286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    /* Set destination to Ethernet broadcast address */
4581286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    memset(packet.ethHdr.h_dest, 0xFF, ETH_ALEN);
4591286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
4601286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
4611286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
4621286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    packet.vertype = PPPOE_VER_TYPE(1, 1);
4631286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    packet.code = CODE_PADI;
4641286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    packet.session = 0;
4651286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
4661286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    svc->type = TAG_SERVICE_NAME;
4671286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    svc->length = htons(namelen);
4681286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    CHECK_ROOM(cursor, packet.payload, namelen+TAG_HDR_SIZE);
4691286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
4701286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (conn->serviceName) {
4711286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	memcpy(svc->payload, conn->serviceName, strlen(conn->serviceName));
4721286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
4731286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    cursor += namelen + TAG_HDR_SIZE;
4741286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
4751286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    /* If we're using Host-Uniq, copy it over */
4761286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (conn->useHostUniq) {
4771286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	PPPoETag hostUniq;
4781286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	pid_t pid = getpid();
4791286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	hostUniq.type = htons(TAG_HOST_UNIQ);
4801286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	hostUniq.length = htons(sizeof(pid));
4811286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	memcpy(hostUniq.payload, &pid, sizeof(pid));
4821286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	CHECK_ROOM(cursor, packet.payload, sizeof(pid) + TAG_HDR_SIZE);
4831286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	memcpy(cursor, &hostUniq, sizeof(pid) + TAG_HDR_SIZE);
4841286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	cursor += sizeof(pid) + TAG_HDR_SIZE;
4851286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	plen += sizeof(pid) + TAG_HDR_SIZE;
4861286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
4871286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
4881286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    packet.length = htons(plen);
4891286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
4901286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
4911286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    if (conn->debugFile) {
4921286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	dumpPacket(conn->debugFile, &packet, "SENT");
4931286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fprintf(conn->debugFile, "\n");
4941286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	fflush(conn->debugFile);
4951286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    }
4961286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley}
4971286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
4981286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley/**********************************************************************
4991286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%FUNCTION: waitForPADO
5001286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%ARGUMENTS:
5011286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* conn -- PPPoEConnection structure
5021286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* timeout -- how long to wait (in seconds)
5031286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%RETURNS:
5041286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Nothing
5051286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%DESCRIPTION:
5061286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Waits for a PADO packet and copies useful information
5071286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley***********************************************************************/
5081286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langleyvoid
5091286c078a4b93695b3812e8c7fe7918c28ea18b4Adam LangleywaitForPADO(PPPoEConnection *conn, int timeout)
5101286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley{
5111286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    fd_set readable;
5121286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    int r;
5131286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    struct timeval tv;
5141286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    PPPoEPacket packet;
5151286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    int len;
5161286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
5171286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    struct PacketCriteria pc;
5181286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    pc.conn          = conn;
5191286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    pc.acNameOK      = (conn->acName)      ? 0 : 1;
5201286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    pc.serviceNameOK = (conn->serviceName) ? 0 : 1;
5211286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    pc.seenACName    = 0;
5221286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    pc.seenServiceName = 0;
5231286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    conn->error = 0;
5241286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
5251286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    do {
5261286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (BPF_BUFFER_IS_EMPTY) {
5271286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    tv.tv_sec = timeout;
5281286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    tv.tv_usec = 0;
5291286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
5301286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    FD_ZERO(&readable);
5311286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    FD_SET(conn->discoverySocket, &readable);
5321286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
5331286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    while(1) {
5341286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		r = select(conn->discoverySocket+1, &readable, NULL, NULL, &tv);
5351286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		if (r >= 0 || errno != EINTR) break;
5361286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    }
5371286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    if (r < 0) {
5381286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		perror("select (waitForPADO)");
5391286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		return;
5401286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    }
5411286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    if (r == 0) return;        /* Timed out */
5421286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
5431286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
5441286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	/* Get the packet */
5451286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	receivePacket(conn->discoverySocket, &packet, &len);
5461286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
5471286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	/* Check length */
5481286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (ntohs(packet.length) + HDR_SIZE > len) {
5491286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    fprintf(stderr, "Bogus PPPoE length field (%u)\n",
5501286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		   (unsigned int) ntohs(packet.length));
5511286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    continue;
5521286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
5531286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
5541286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#ifdef USE_BPF
5551286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	/* If it's not a Discovery packet, loop again */
5561286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (etherType(&packet) != Eth_PPPOE_Discovery) continue;
5571286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley#endif
5581286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
5591286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (conn->debugFile) {
5601286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    dumpPacket(conn->debugFile, &packet, "RCVD");
5611286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    fprintf(conn->debugFile, "\n");
5621286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    fflush(conn->debugFile);
5631286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
5641286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	/* If it's not for us, loop again */
5651286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (!packetIsForMe(conn, &packet)) continue;
5661286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
5671286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (packet.code == CODE_PADO) {
5681286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    if (BROADCAST(packet.ethHdr.h_source)) {
5691286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		fprintf(stderr, "Ignoring PADO packet from broadcast MAC address\n");
5701286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		continue;
5711286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    }
5721286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    parsePacket(&packet, parsePADOTags, &pc);
5731286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    if (conn->error)
5741286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		return;
5751286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    if (!pc.seenACName) {
5761286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		fprintf(stderr, "Ignoring PADO packet with no AC-Name tag\n");
5771286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		continue;
5781286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    }
5791286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    if (!pc.seenServiceName) {
5801286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		fprintf(stderr, "Ignoring PADO packet with no Service-Name tag\n");
5811286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		continue;
5821286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    }
5831286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    conn->numPADOs++;
5841286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    printf("--------------------------------------------------\n");
5851286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    if (pc.acNameOK && pc.serviceNameOK) {
5861286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		memcpy(conn->peerEth, packet.ethHdr.h_source, ETH_ALEN);
5871286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		if (conn->printACNames) {
5881286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		    printf("AC-Ethernet-Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
5891286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley			   (unsigned) conn->peerEth[0],
5901286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley			   (unsigned) conn->peerEth[1],
5911286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley			   (unsigned) conn->peerEth[2],
5921286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley			   (unsigned) conn->peerEth[3],
5931286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley			   (unsigned) conn->peerEth[4],
5941286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley			   (unsigned) conn->peerEth[5]);
5951286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		    continue;
5961286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		}
5971286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		conn->discoveryState = STATE_RECEIVED_PADO;
5981286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley		break;
5991286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    }
6001286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
6011286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    } while (conn->discoveryState != STATE_RECEIVED_PADO);
6021286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley}
6031286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
6041286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley/**********************************************************************
6051286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%FUNCTION: discovery
6061286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%ARGUMENTS:
6071286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* conn -- PPPoE connection info structure
6081286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%RETURNS:
6091286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Nothing
6101286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley*%DESCRIPTION:
6111286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley* Performs the PPPoE discovery phase
6121286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley***********************************************************************/
6131286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langleyvoid
6141286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langleydiscovery(PPPoEConnection *conn)
6151286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley{
6161286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    int padiAttempts = 0;
6171286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    int timeout = PADI_TIMEOUT;
6181286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
6191286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    conn->discoverySocket =
6201286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	openInterface(conn->ifName, Eth_PPPOE_Discovery, conn->myEth);
6211286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
6221286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    do {
6231286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	padiAttempts++;
6241286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	if (padiAttempts > MAX_PADI_ATTEMPTS) {
6251286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    fprintf(stderr, "Timeout waiting for PADO packets\n");
6261286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    close(conn->discoverySocket);
6271286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    conn->discoverySocket = -1;
6281286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    return;
6291286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	}
6301286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	sendPADI(conn);
6311286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	conn->discoveryState = STATE_SENT_PADI;
6321286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	waitForPADO(conn, timeout);
6331286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    } while (!conn->numPADOs);
6341286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley}
6351286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley
6368ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectint main(int argc, char *argv[])
6378ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project{
6388ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    int opt;
6398ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    PPPoEConnection *conn;
6408ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
6418ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    conn = malloc(sizeof(PPPoEConnection));
6428ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    if (!conn)
6438ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	fatalSys("malloc");
6448ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
6458ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    memset(conn, 0, sizeof(PPPoEConnection));
6468ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
6478ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    while ((opt = getopt(argc, argv, "I:D:VUAS:C:h")) > 0) {
6488ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	switch(opt) {
6498ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	case 'S':
6508ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    conn->serviceName = xstrdup(optarg);
6518ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    break;
6528ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	case 'C':
6538ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    conn->acName = xstrdup(optarg);
6548ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    break;
6558ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	case 'U':
6568ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    conn->useHostUniq = 1;
6578ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    break;
6588ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	case 'D':
6598ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    conn->debugFile = fopen(optarg, "w");
6608ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    if (!conn->debugFile) {
6618ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		fprintf(stderr, "Could not open %s: %s\n",
6628ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			optarg, strerror(errno));
6638ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		exit(1);
6648ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    }
6651286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley	    fprintf(conn->debugFile, "pppoe-discovery %s\n", RP_VERSION);
6668ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    break;
6678ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	case 'I':
6688ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    conn->ifName = xstrdup(optarg);
6698ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    break;
6708ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	case 'A':
6718ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    /* this is the default */
6728ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    break;
6738ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	case 'V':
6748ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	case 'h':
6758ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    usage();
6768ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    exit(0);
6778ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	default:
6788ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    usage();
6798ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    exit(1);
6808ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	}
6818ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    }
6828ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
6838ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    /* default interface name */
6848ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    if (!conn->ifName)
6858ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	conn->ifName = strdup("eth0");
6868ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
6878ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    conn->discoverySocket = -1;
6888ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    conn->sessionSocket = -1;
6898ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    conn->printACNames = 1;
6908ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
6918ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    discovery(conn);
6928ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    exit(0);
6938ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project}
6948ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
6958ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectvoid rp_fatal(char const *str)
6968ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project{
6971286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    fprintf(stderr, "%s\n", str);
6988ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    exit(1);
6998ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project}
7008ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
7018ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectvoid fatalSys(char const *str)
7028ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project{
7031286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    perror(str);
7048ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    exit(1);
7058ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project}
7068ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
7078ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectvoid sysErr(char const *str)
7088ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project{
7098ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    rp_fatal(str);
7108ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project}
7118ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
7128ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectchar *xstrdup(const char *s)
7138ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project{
7148ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    register char *ret = strdup(s);
7158ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    if (!ret)
7168ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	sysErr("strdup");
7178ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    return ret;
7188ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project}
7198ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
7208ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectvoid usage(void)
7218ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project{
7228ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project    fprintf(stderr, "Usage: pppoe-discovery [options]\n");
7231286c078a4b93695b3812e8c7fe7918c28ea18b4Adam Langley    fprintf(stderr, "\nVersion " RP_VERSION "\n");
7248ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project}
725