Exemple #1
0
/**********************************************************************
*%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;
}
Exemple #2
0
void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen)
{
        long    buf[MAXDLBUF];
        union   DL_primitives   *dlp;
        struct  strbuf  data, ctl;

        dlp = (union DL_primitives*) buf;

        dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
        dlp->unitdata_req.dl_dest_addr_length = addrlen;
        dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
        dlp->unitdata_req.dl_priority.dl_min = minpri;
        dlp->unitdata_req.dl_priority.dl_max = maxpri;

        (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);

        ctl.maxlen = 0;
        ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
        ctl.buf = (char *) buf;

        data.maxlen = 0;
        data.len = datalen;
        data.buf = (char *) datap;

        if (putmsg(fd, &ctl, &data, 0) < 0)
                fatalSys("dlunitdatareq:  putmsg");
}
Exemple #3
0
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);
	}
}
Exemple #4
0
int main(int argc, char *argv[])
{
    int opt;
    PPPoEConnection *conn;

    conn = malloc(sizeof(PPPoEConnection));
    if (!conn)
	fatalSys("malloc");

    memset(conn, 0, sizeof(PPPoEConnection));

    while ((opt = getopt(argc, argv, "I:D:VUAS:C:h")) > 0) {
	switch(opt) {
	case 'S':
	    conn->serviceName = xstrdup(optarg);
	    break;
	case 'C':
	    conn->acName = xstrdup(optarg);
	    break;
	case 'U':
	    conn->useHostUniq = 1;
	    break;
	case 'D':
	    conn->debugFile = fopen(optarg, "w");
	    if (!conn->debugFile) {
		fprintf(stderr, "Could not open %s: %s\n",
			optarg, strerror(errno));
		exit(1);
	    }
	    fprintf(conn->debugFile, "pppoe-discovery %s\n", RP_VERSION);
	    break;
	case 'I':
	    conn->ifName = xstrdup(optarg);
	    break;
	case 'A':
	    /* this is the default */
	    break;
	case 'V':
	case 'h':
	    usage();
	    exit(0);
	default:
	    usage();
	    exit(1);
	}
    }

    /* default interface name */
    if (!conn->ifName)
	conn->ifName = strdup("eth0");

    conn->discoverySocket = -1;
    conn->sessionSocket = -1;
    conn->printACNames = 1;

    discovery(conn);
    exit(0);
}
Exemple #5
0
/**********************************************************************
*%FUNCTION: initFilter
*%ARGUMENTS:
* fd -- file descriptor of BSD device
* type -- Ethernet frame type (0 for watch mode)
* hwaddr -- buffer with ehthernet address
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Initializes the packet filter rules.
***********************************************************************/
void
initFilter(int fd, UINT16_t type, unsigned char *hwaddr)
{
    /* Packet Filter Instructions:
     * Note that the ethernet type names come from "pppoe.h" and are
     * used here to maintain consistency with the rest of this file. */
    static struct bpf_insn bpfRun[] = {         /* run PPPoE */
        BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),     /* ethernet type */
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0),
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9),
        BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0),      /* first word of dest. addr */
#define PPPOE_BCAST_CMPW 4                     /* offset of word compare */
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2),
        BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4),      /* next 1/2 word of dest. */
#define PPPOE_BCAST_CMPH 6                     /* offset of 1/2 word compare */
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0),
        BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0),      /* first word of dest. addr */
#define PPPOE_FILTER_CMPW 8                     /* offset of word compare */
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),
        BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4),      /* next 1/2 word of dest. */
#define PPPOE_FILTER_CMPH 10                    /* offset of 1/rd compare */
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
        BPF_STMT(BPF_RET+BPF_K, (u_int) -1),    /* keep packet */
        BPF_STMT(BPF_RET+BPF_K, 0),             /* drop packet */
    };

    /* Fix the potentially varying parts */
    bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
    bpfRun[1].jt   = 5;
    bpfRun[1].jf   = 0;
    bpfRun[1].k    = Eth_PPPOE_Session;

    bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
    bpfRun[2].jt   = 0;
    bpfRun[2].jf   = 9;
    bpfRun[2].k    = Eth_PPPOE_Discovery;

    {
      struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])];
      struct bpf_program bpfProgram;
      memcpy(bpfInsn, bpfRun, sizeof(bpfRun));
      bpfInsn[PPPOE_BCAST_CMPW].k = ((0xff << 24) | (0xff << 16) |
                                     (0xff << 8) | 0xff);
      bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff << 8) | 0xff);
      bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) |
				      (hwaddr[2] << 8) | hwaddr[3]);
      bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]);
      bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));
      bpfProgram.bf_insns = &bpfInsn[0];
      
      /* Apply the filter */
      if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {
	fatalSys("ioctl(BIOCSETF)");
      }
    }
}
Exemple #6
0
void
initFilter(int fd, UINT16_t type, unsigned char *hwaddr)
{
    static struct bpf_insn bpfRun[] = {         
	BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),     
	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0),
	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9),
	BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0),      
#define PPPOE_BCAST_CMPW 4                     
	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2),
	BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4),      
#define PPPOE_BCAST_CMPH 6                     
	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0),
	BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0),      
#define PPPOE_FILTER_CMPW 8                     
	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),
	BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4),      
#define PPPOE_FILTER_CMPH 10                    
	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
	BPF_STMT(BPF_RET+BPF_K, (u_int) -1),    
	BPF_STMT(BPF_RET+BPF_K, 0),             
    };

    
    bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
    bpfRun[1].jt   = 5;
    bpfRun[1].jf   = 0;
    bpfRun[1].k    = Eth_PPPOE_Session;

    bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
    bpfRun[2].jt   = 0;
    bpfRun[2].jf   = 9;
    bpfRun[2].k    = Eth_PPPOE_Discovery;

    {
      struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])];
      struct bpf_program bpfProgram;
      memcpy(bpfInsn, bpfRun, sizeof(bpfRun));
      bpfInsn[PPPOE_BCAST_CMPW].k = ((0xff << 24) | (0xff << 16) |
				     (0xff << 8) | 0xff);
      bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff << 8) | 0xff);
      bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) |
				      (hwaddr[2] << 8) | hwaddr[3]);
      bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]);
      bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));
      bpfProgram.bf_insns = &bpfInsn[0];

      
      if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {
	fatalSys("ioctl(BIOCSETF)");
      }
    }
}
Exemple #7
0
void dlinforeq(int fd)
{
        dl_info_req_t   info_req;
        struct  strbuf  ctl;
        int     flags;

        info_req.dl_primitive = DL_INFO_REQ;

        ctl.maxlen = 0;
        ctl.len = sizeof (info_req);
        ctl.buf = (char *) &info_req;

        flags = RS_HIPRI;

        if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
                fatalSys("dlinforeq:  putmsg");
}
Exemple #8
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();
}
Exemple #9
0
void dlattachreq(int fd, u_long ppa)
{
        dl_attach_req_t attach_req;
        struct  strbuf  ctl;
        int     flags;

        attach_req.dl_primitive = DL_ATTACH_REQ;
        attach_req.dl_ppa = ppa;

        ctl.maxlen = 0;
        ctl.len = sizeof (attach_req);
        ctl.buf = (char *) &attach_req;

        flags = 0;

        if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
                fatalSys("dlattachreq:  putmsg");
}
Exemple #10
0
void dlpromisconreq(int fd, u_long level)
{
        dl_promiscon_req_t      promiscon_req;
        struct  strbuf  ctl;
        int     flags;

        promiscon_req.dl_primitive = DL_PROMISCON_REQ;
        promiscon_req.dl_level = level;

        ctl.maxlen = 0;
        ctl.len = sizeof (promiscon_req);
        ctl.buf = (char *) &promiscon_req;

        flags = 0;

        if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
                fatalSys("dlpromiscon:  putmsg");

}
Exemple #11
0
void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest)
{
        dl_bind_req_t   bind_req;
        struct  strbuf  ctl;
        int     flags;

        bind_req.dl_primitive = DL_BIND_REQ;
        bind_req.dl_sap = sap;
        bind_req.dl_max_conind = max_conind;
        bind_req.dl_service_mode = service_mode;
        bind_req.dl_conn_mgmt = conn_mgmt;
        bind_req.dl_xidtest_flg = xidtest;

        ctl.maxlen = 0;
        ctl.len = sizeof (bind_req);
        ctl.buf = (char *) &bind_req;

        flags = 0;

        if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
                fatalSys("dlbindreq:  putmsg");
}
Exemple #12
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;
}
/**********************************************************************
*%FUNCTION: waitForPADS
*%ARGUMENTS:
* conn -- PPPoE connection info
* timeout -- how long to wait (in seconds)
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Waits for a PADS packet and copies useful information
***********************************************************************/
static void
waitForPADS(PPPoEConnection *conn, int timeout)
{
    fd_set readable;
    int r;
    struct timeval tv;
    struct timeval expire_at;
    struct timeval now;

    PPPoEPacket packet;
    int len;

    if (gettimeofday(&expire_at, NULL) < 0) {
	fatalSys("gettimeofday (waitForPADS)");
    }
    expire_at.tv_sec += timeout;

    conn->error = 0;
    do {
	if (BPF_BUFFER_IS_EMPTY) {
	    if (gettimeofday(&now, NULL) < 0) {
		fatalSys("gettimeofday (waitForPADS)");
	    }
	    tv.tv_sec = expire_at.tv_sec - now.tv_sec;
	    tv.tv_usec = expire_at.tv_usec - now.tv_usec;
	    if (tv.tv_usec < 0) {
		tv.tv_usec += 1000000;
		if (tv.tv_sec) {
		    tv.tv_sec--;
		} else {
		    /* Timed out */
		    return;
		}
	    }
	    if (tv.tv_sec <= 0 && tv.tv_usec <= 0) {
		/* Timed out */
		return;
	    }

	    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 (waitForPADS): %m");
		return;
	    }
	    if (r == 0) {
		/* Timed out */
		return;
	    }
	}

	/* 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 from the AC, it's not for me */
	if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue;

	/* If it's not for us, loop again */
	if (!packetIsForMe(conn, &packet)) continue;

	/* Is it PADS?  */
	if (packet.code == CODE_PADS) {
	    /* Parse for goodies */
	    if (parsePacket(&packet, parsePADSTags, conn) < 0)
		return;
	    if (conn->error)
		return;
	    conn->discoveryState = STATE_SESSION;
	    break;
	}
    } while (conn->discoveryState != STATE_SESSION);

    /* Don't bother with ntohs; we'll just end up converting it back... */
    conn->session = packet.session;

    info("PPP session is %d", (int) ntohs(conn->session));

    /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
    if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
	error("Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->session));
    }
}
Exemple #14
0
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;
}
Exemple #15
0
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: 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;
    struct timeval now;

    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) {
	fatalSys("gettimeofday (waitForPADO)");
    }
    expire_at.tv_sec += timeout;

    do {
	if (BPF_BUFFER_IS_EMPTY) {
	    if (gettimeofday(&now, NULL) < 0) {
		fatalSys("gettimeofday (waitForPADO)");
	    }
	    tv.tv_sec = expire_at.tv_sec - now.tv_sec;
	    tv.tv_usec = expire_at.tv_usec - now.tv_usec;
	    if (tv.tv_usec < 0) {
		tv.tv_usec += 1000000;
		if (tv.tv_sec) {
		    tv.tv_sec--;
		} else {
		    /* Timed out */
		    return;
		}
	    }
	    if (tv.tv_sec <= 0 && tv.tv_usec <= 0) {
		/* Timed out */
		return;
	    }

	    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) {
		/* Timed out */
		return;
	    }
	}

	/* 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 (BROADCAST(packet.ethHdr.h_source)) {
		warn("Ignoring PADO packet from broadcast 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) {
		warn("Ignoring PADO packet with no AC-Name tag");
		continue;
	    }
	    if (!pc.seenServiceName) {
		warn("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);
}
Exemple #17
0
/**********************************************************************
*%FUNCTION: waitForPADS
*%ARGUMENTS:
* conn -- PPPoE connection info
* timeout -- how long to wait (in seconds)
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Waits for a PADS packet and copies useful information
***********************************************************************/
void
waitForPADS(PPPoEConnection *conn, int timeout)
{
    fd_set readable;
    int r;
    struct timeval tv;
    PPPoEPacket packet;
    int len;

    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 (waitForPADS)");
	    }
	    if (r == 0) return;
	}

	/* 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 from the AC, it's not for me */
	if (memcmp(packet.ethHdr.h_source, conn->peerEth, ETH_ALEN)) continue;

	/* If it's not for us, loop again */
	if (!packetIsForMe(conn, &packet)) continue;

	/* Is it PADS?  */
	if (packet.code == CODE_PADS) {
	    /* Parse for goodies */
	    parsePacket(&packet, parsePADSTags, conn);
	    conn->discoveryState = STATE_SESSION;
	    break;
	}
    } while (conn->discoveryState != STATE_SESSION);

    /* Don't bother with ntohs; we'll just end up converting it back... */
    conn->session = packet.session;

    syslog(LOG_INFO, "PPP session is %d", (int) ntohs(conn->session));

    /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
    if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
	syslog(LOG_ERR, "Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->session));
    }
}
Exemple #18
0
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); 
	}
}
Exemple #19
0
/**********************************************************************
*%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);
}
Exemple #20
0
/**********************************************************************
*%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;
}
Exemple #21
0
/**********************************************************************
*%FUNCTION: main
*%ARGUMENTS:
* argc, argv -- usual suspects
*%RETURNS:
* EXIT_SUCCESS or EXIT_FAILURE
*%DESCRIPTION:
* Main program.  Options:
* -C ifname           -- Use interface for PPPoE clients
* -S ifname           -- Use interface for PPPoE servers
* -B ifname           -- Use interface for both clients and servers
* -n sessions         -- Maximum of "n" sessions
***********************************************************************/
int
pppoerelay_main(int argc, char *argv[])
{
    int opt;
    int nsess = DEFAULT_SESSIONS;
    struct sigaction sa;
    int beDaemon = 1;

    if (getuid() != geteuid() ||
	getgid() != getegid()) {
	printf( "SECURITY WARNING: pppoe-relay will NOT run suid or sgid.  Fix your installation.\n");
	exit(1);
    }


    openlog("pppoe-relay", LOG_PID, LOG_DAEMON);

    while((opt = getopt(argc, argv, "hC:S:B:n:i:F")) != -1) {
	switch(opt) {
	case 'h':
	    usage(argv[0]);
	    break;
	case 'F':
	    beDaemon = 0;
	    break;
	case 'C':
	    addInterface(optarg, 1, 0);
	    break;
	case 'S':
	    addInterface(optarg, 0, 1);
	    break;
	case 'B':
	    addInterface(optarg, 1, 1);
	    break;
	case 'i':
	    if (sscanf(optarg, "%u", &IdleTimeout) != 1) {
		printf( "Illegal argument to -i: should be -i timeout\n");
		exit(EXIT_FAILURE);
	    }
	    CleanPeriod = IdleTimeout / TIMEOUT_DIVISOR;
	    if (CleanPeriod < MIN_CLEAN_PERIOD) CleanPeriod = MIN_CLEAN_PERIOD;
	    break;
	case 'n':
	    if (sscanf(optarg, "%d", &nsess) != 1) {
		printf( "Illegal argument to -n: should be -n #sessions\n");
		exit(EXIT_FAILURE);
	    }
	    if (nsess < 1 || nsess > 65534) {
		printf( "Illegal argument to -n: must range from 1 to 65534\n");
		exit(EXIT_FAILURE);
	    }
	    break;
	default:
	    usage(argv[0]);
	}
    }

#ifdef USE_LINUX_PACKET
#ifndef HAVE_STRUCT_SOCKADDR_LL
    printf( "The PPPoE relay does not work on Linux 2.0 kernels.\n");
    exit(EXIT_FAILURE);
#endif
#endif

    /* Check that at least two interfaces were defined */
    if (NumInterfaces < 2) {
	printf( "%s: Must define at least two interfaces\n",
		argv[0]);
	exit(EXIT_FAILURE);
    }

    /* Make a pipe for the cleaner */
    if (pipe(CleanPipe) < 0) {
	fatalSys("pipe");
    }

    /* Set up alarm handler */
    sa.sa_handler = alarmHandler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGALRM, &sa, NULL) < 0) {
	fatalSys("sigaction");
    }

    /* Allocate memory for sessions, etc. */
    initRelay(nsess);

    /* Daemonize -- UNIX Network Programming, Vol. 1, Stevens */
    if (beDaemon) {
	int i;
	i = fork();
	if (i < 0) {
	    fatalSys("fork");
	} else if (i != 0) {
	    /* parent */
	    exit(0);
	}
	setsid();
	signal(SIGHUP, SIG_IGN);
	i = fork();
	if (i < 0) {
	    fatalSys("fork");
	} else if (i != 0) {
	    exit(0);
	}

	chdir("/");
	closelog();
	for (i=0; i<CLOSEFD; i++) {
	    if (!keepDescriptor(i)) {
		close(i);
	    }
	}
	/* We nuked our syslog descriptor... */
	openlog("pppoe-relay", LOG_PID, LOG_DAEMON);
    }

    /* Kick off SIGALRM if there is an idle timeout */
    if (IdleTimeout) alarm(1);

    /* Enter the relay loop */
    relayLoop();

    /* Shouldn't ever get here... */
    return EXIT_FAILURE;
}
int main(int argc, char *argv[])
{
    int opt;
    PPPoEConnection *conn;

    conn = malloc(sizeof(PPPoEConnection));
    if (!conn)
	fatalSys("malloc");

    memset(conn, 0, sizeof(PPPoEConnection));

    while ((opt = getopt(argc, argv, "I:D:VUW:AS:C:h")) > 0) {
	switch(opt) {
	case 'S':
	    conn->serviceName = xstrdup(optarg);
	    break;
	case 'C':
	    conn->acName = xstrdup(optarg);
	    break;
	case 'U':
	    if(conn->hostUniq.length) {
		fprintf(stderr, "-U and -W are mutually exclusive\n");
		exit(EXIT_FAILURE);
	    }
            char pidbuf[5];
            snprintf(pidbuf, sizeof(pidbuf), "%04x", getpid());
            parseHostUniq(pidbuf, &conn->hostUniq);
	    break;
	case 'W':
	    if(conn->hostUniq.length) {
		fprintf(stderr, "-U and -W are mutually exclusive\n");
		exit(EXIT_FAILURE);
	    }
	    if (!parseHostUniq(optarg, &conn->hostUniq)) {
                fprintf(stderr, "Invalid host-uniq argument: %s\n", optarg);
                exit(EXIT_FAILURE);
            }
	    break;
	case 'D':
	    conn->debugFile = fopen(optarg, "w");
	    if (!conn->debugFile) {
		fprintf(stderr, "Could not open %s: %s\n",
			optarg, strerror(errno));
		exit(1);
	    }
	    fprintf(conn->debugFile, "pppoe-discovery %s\n", RP_VERSION);
	    break;
	case 'I':
	    conn->ifName = xstrdup(optarg);
	    break;
	case 'A':
	    /* this is the default */
	    break;
	case 'V':
	case 'h':
	    usage();
	    exit(0);
	default:
	    usage();
	    exit(1);
	}
    }

    /* default interface name */
    if (!conn->ifName)
	conn->ifName = strdup("eth0");

    conn->discoverySocket = -1;
    conn->sessionSocket = -1;
    conn->printACNames = 1;

    discovery(conn);
    exit(0);
}