/* * * Original Author: Luke Stras * * Revision History * 1999/09/22 stras Initial version * 1999/09/25 JHS re-use for PPPOE discovery * 1999/09/26 JHS retransmission for PADI and PADR * 1999/10/11 ireid@sympatico.ca -I fix * 1999/10/22 AC cookie echo, -F, -R, -P and help extensions * 1999/10/23 small fix by Josef Drexler to create_padr(); * doesnt make sense and doesnt work if removed * (will figure it out later). Looks like alignm issue * Fixed: Stupid mistake on my part (much cleaner now). * * */ #include #include "pppoed.h" /* #define DISC_DEB 1 #define DISC_DEB2 1 */ /* Bigger than the biggest ethernet packet we'll ever see, in bytes */ #define MAX_PACKET 2000 int ctrl_sock; int opt_verbose = 0; /* pointer to packet we have to retransmit */ struct pppoe_packet *ret_pkt; int ret_pkt_size = 0; FILE *log_file = NULL; int state = CODE_PADI; void print_hex (unsigned char *buf, int len) { int i; if (opt_verbose == 0) return; for (i = 0; i < len; i++) printf ("%02x ", (unsigned char) *(buf + i)); printf ("\n"); } void print_packet (struct pppoe_packet *p) { int i; struct pppoe_tag *t = (struct pppoe_tag *) (p + 1); char *buf; printf ("\nEthernet header:\n"); printf ("h_dest: "); for (i = 0; i < 6; i++) printf ("%02x:", (unsigned) p->ethhdr.h_dest[i]); printf ("\nh_source: "); for (i = 0; i < 6; i++) printf ("%02x:", (unsigned) p->ethhdr.h_source[i]); printf ("\nh_proto: 0x%04x ", (unsigned) ntohs (p->ethhdr.h_proto)); switch ((unsigned) ntohs (p->ethhdr.h_proto)) { case ETH_P_PPPOE_DISC: printf ("(PPPOE Discovery)\n"); break; case ETH_P_PPPOE_SESS: printf ("(PPPOE Session)\n"); break; default: printf ("(Unknown)\n"); } printf ("PPPoE header: \nver: 0x%01x type: 0x%01x code: 0x%02x " "session: 0x%04x length: 0x%04x ", (unsigned) p->ver, (unsigned) p->type, (unsigned) p->code, (unsigned) p->session, (unsigned) ntohs (p->length)); switch (p->code) { case CODE_PADI: printf ("(PADI)\n"); break; case CODE_PADO: printf ("(PADO)\n"); break; case CODE_PADR: printf ("(PADR)\n"); break; case CODE_PADS: printf ("(PADS)\n"); break; case CODE_PADT: printf ("(PADT)\n"); break; default: printf ("(Unknown)\n"); } if (ntohs (p->ethhdr.h_proto) != ETH_P_PPPOE_DISC) { print_hex ((unsigned char *) (p + 1), ntohs (p->length)); return; } while (t < (struct pppoe_tag *) ((char *) (p + 1) + ntohs (p->length))) { printf ("PPPoE tag:\ntype: %04x length: %04x ", ntohs (t->type), ntohs (t->length)); switch (ntohs (t->type)) { case TAG_END_OF_LIST: printf ("(End of list)\n"); break; case TAG_SERVICE_NAME: printf ("(Service name)\n"); break; case TAG_AC_NAME: printf ("(AC Name)\n"); break; case TAG_HOST_UNIQ: printf ("(Host Uniq)\n"); break; case TAG_AC_COOKIE: printf ("(AC Cookie)\n"); break; case TAG_VENDOR_SPECIFIC: printf ("(Vendor Specific)\n"); break; case TAG_RELAY_SESSION_ID: printf ("(Relay Session ID)\n"); break; case TAG_SERVICE_NAME_ERROR: printf ("(Service Name Error)\n"); break; case TAG_AC_SYSTEM_ERROR: printf ("(AC System Error)\n"); break; case TAG_GENERIC_ERROR: printf ("(Generic Error)\n"); break; default: printf ("(Unknown)\n"); } if (ntohs (t->length) > 0) switch (ntohs (t->type)) { case TAG_SERVICE_NAME: case TAG_AC_NAME: case TAG_SERVICE_NAME_ERROR: case TAG_AC_SYSTEM_ERROR: case TAG_GENERIC_ERROR: /* ascii data */ buf = malloc (ntohs (t->length) + 1); memset (buf, 0, ntohs (t->length) + 1); strncpy (buf, (char *) (t + 1), ntohs (t->length)); buf[ntohs (t->length)] = '\0'; printf ("data (UTF-8): %s\n", buf); free (buf); break; case TAG_HOST_UNIQ: case TAG_AC_COOKIE: case TAG_RELAY_SESSION_ID: printf ("data (bin): "); for (i = 0; i < ntohs (t->length); i++) printf ("%02x", (unsigned) *((char *) (t + 1) + i)); printf ("\n"); break; default: printf ("unrecognized data\n"); } if (ntohs (t->type) == TAG_END_OF_LIST) break; t = (struct pppoe_tag *) ((char *) (t + 1) + ntohs (t->length)); } } /* just for testing purposes ignore otherwise */ void read_setup () { /* should really populate the table with the params read from some config file; lets stick with one for now */ /* debugging for the 10.0.0.1 machine */ unsigned char dstmac[6] = { 0x0, 0x0, 0xe8, 0x1c, 0x6, 0x9b }; ses_table[0].pid = -1; ses_table[0].state = CONNECTED; ses_table[0].line = 0; ses_table[0].sid = 12; /* session ID */ strcpy (ses_table[0].name, "eth0"); /*name */ memcpy (&ses_table[0].dmac, dstmac, 6); } int create_raw_socket (unsigned short type) { int optval = 1, rv; if ((rv = socket (PF_INET, SOCK_PACKET, htons (type))) < 0) { perror ("pppoe: socket"); return -1; } if (setsockopt (rv, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval)) < 0) { perror ("pppoe: setsockopt"); return -1; } return rv; } int get_hw_addr (int s, char *if_name, char *hw_addr) { struct ifreq ifr; strncpy (ifr.ifr_name, if_name, sizeof (ifr.ifr_name)); if (ioctl (s, SIOCGIFHWADDR, &ifr) < 0) { perror ("pppoe: ioctl(SIOCGIFHWADDR)"); return -1; } if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { fprintf (stderr, "pppoe: interface %s is not Ethernet!\n", if_name); return -1; } memcpy (hw_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); /* printf("<%s> we received hware address %x:%x:%x:%x:%x:%x\n",if_name,hw_addr[0],hw_addr[1], hw_addr[2],hw_addr[3],hw_addr[4],hw_addr[5]); */ return 0; } int create_padi (struct pppoe_packet **packet, const char *src, const char *name) { int size; if (packet == NULL) return 0; if (*packet != NULL) free (*packet); size = sizeof (struct pppoe_packet) + sizeof (struct pppoe_tag); if (name != NULL) size += strlen (name); if ((*packet = malloc (size)) == NULL) { fprintf (stderr, "pppoe: malloc (create_padi)"); return 0; } memcpy ((*packet)->ethhdr.h_dest, MAC_BCAST_ADDR, ETH_ALEN); memcpy ((*packet)->ethhdr.h_source, src, ETH_ALEN); (*packet)->ethhdr.h_proto = htons (ETH_P_PPPOE_DISC); (*packet)->ver = 1; (*packet)->type = 1; (*packet)->code = CODE_PADI; (*packet)->session = 0; (*packet)->length = htons (size - sizeof (struct pppoe_packet)); /* fill out a blank service-name tag */ (*(struct pppoe_tag *) (*packet + 1)).type = htons (TAG_SERVICE_NAME); (*(struct pppoe_tag *) (*packet + 1)).length = name ? htons (strlen (name)) : 0; if (name != NULL) memcpy ((char *) (*packet + 1) + sizeof (struct pppoe_tag), name, strlen (name)); return size; } int create_padr (struct pppoe_packet **packet, const char *src, const char *dst, char *name, struct pppoe_tag *extra_tag) { int size; int size1 = 0, size2 = 0; char *p; struct pppoe_tag *t; if (packet == NULL) return 0; if (*packet != NULL) free (*packet); if (extra_tag) size1 = sizeof (struct pppoe_tag) + ntohs (extra_tag->length); size2 = sizeof (struct pppoe_tag); size = size1 + size2; if (name != NULL) size += strlen (name); if ((*packet = malloc (size + sizeof (struct pppoe_packet))) == NULL) { fprintf (stderr, "pppoe: malloc (create_padr)"); return 0; } memcpy ((*packet)->ethhdr.h_dest, dst, ETH_ALEN); memcpy ((*packet)->ethhdr.h_source, src, ETH_ALEN); (*packet)->ethhdr.h_proto = htons (ETH_P_PPPOE_DISC); (*packet)->ver = 1; (*packet)->type = 1; (*packet)->code = CODE_PADR; (*packet)->session = 0; (*packet)->length = htons (size); if (extra_tag) { memcpy ((char *) (*packet + 1), extra_tag, size1); p = (char *) (*packet + 1); p += size1; t = (struct pppoe_tag *) p; /* fill out a blank service-name tag */ t->type = htons (TAG_SERVICE_NAME); t->length = name ? htons (strlen (name)) : 0; if (name != NULL) memcpy ((char *) (p + sizeof (struct pppoe_tag)), name, strlen (name)); } else { (*(struct pppoe_tag *) (*packet + 1)).type = htons (TAG_SERVICE_NAME); (*(struct pppoe_tag *) (*packet + 1)).length = name ? htons (strlen (name)) : 0; if (name != NULL) memcpy ((char *) (*packet + 1) + sizeof (struct pppoe_tag), name, strlen (name)); } return size + sizeof (struct pppoe_packet); } int send_packet (int sock, struct pppoe_packet *packet, int len, const char *ifn) { struct sockaddr addr; int c; memset (&addr, 0, sizeof (addr)); #ifdef DISC_DEB2 printf ("\nsend_packet: ifn %s\n", ifn); #endif strcpy (addr.sa_data, ifn); #ifdef DISC_DEB1 print_packet (packet); #endif if ((c = sendto (sock, packet, len, 0, &addr, sizeof (addr))) < 0) perror ("pppoe: sendto (send_packet)"); return c; } int wait_for_packet (int *sock, int ns, struct pppoe_packet **packet, int *len, int num_ret) { fd_set fdset; int i, maxs = -1; struct sockaddr_in from; socklen_t fromlen; struct timeval timeout; int retransmits = 0; int reason = -1; /* a num_ret == 0 implies block and wait for the packet */ FD_ZERO (&fdset); while (1) { retransmits++; if (num_ret && retransmits > num_ret) return -1; if (retransmits <= num_ret) { timeout.tv_sec = 1 << retransmits; timeout.tv_usec = 0; } for (i = 0; i < ns; i++) { FD_SET (sock[i], &fdset); if (sock[i] > maxs) maxs = sock[i]; } if (num_ret == 0) reason = select (maxs + 1, &fdset, NULL, NULL, NULL); else reason = select (maxs + 1, &fdset, NULL, NULL, &timeout); if (reason < 0) { perror ("pppoe: select (wait_for_packet)"); return -1; } if (reason == 0) { /* timeout */ if (send_packet (*sock, ret_pkt, ret_pkt_size, if_name) < 0) { fprintf (stderr, "pppoe: unable to send PADI packet\n"); return -1; } continue; /* go back to the top */ } /* reason has the number of ready descriptors */ for (i = 0; i < ns; i++) { if (FD_ISSET (sock[i], &fdset)) { if (sock[i] < 3) /* ie, it's an fd */ return sock[i]; if (*packet != NULL) free (*packet); if ((*packet = malloc (MAX_PACKET)) == NULL) { fprintf (stderr, "pppoe: malloc (wait_for_packet"); return -1; } fromlen = sizeof (from); if (recvfrom (sock[i], *packet, MAX_PACKET, 0, (struct sockaddr *) &from, &fromlen) < 0) { perror ("pppoe: recv (wait_for_packet)"); return -1; } return sock[i]; } } } } struct pppoe_tag * scan_tag (int length, struct pppoe_tag *start_tag, unsigned short type) { struct pppoe_tag *tag, *ret; tag = start_tag; while ((tag < (start_tag + length)) && (ntohs (tag->type) != 0)) { #ifdef DISC_DEB2 printf ("scan_tag: tag %p length %d tag->type %x\n", tag, ntohs (tag->length), ntohs (tag->type)); printf ("scan_tag data (bin): "); for (i = 0; i < ntohs (ret->length); i++) printf ("%02x", (unsigned) *((char *) (ret + 1) + i)); printf ("\n"); printf ("scan_tag data (bin): DONE"); #endif if (ntohs (tag->type) == type) { /* got it */ #ifdef DISC_DEB2 printf ("Found it!"); #endif if ((ret = malloc (sizeof (struct pppoe_tag) + tag->length)) == NULL) { printf ("Error Mallocing for AC tag \n"); exit (-1); } memcpy (ret, tag, sizeof (struct pppoe_tag) + ntohs (tag->length)); return ret; } #ifdef DISC_DEB2 printf ("scan_tag: not matched! \n"); #endif tag = (char *) (tag) + sizeof (struct pppoe_tag) + ntohs (tag->length); } return NULL; } int server_discover (int lineid) { char src_addr[ETH_ALEN]; /* source hardware address */ char dst_addr[ETH_ALEN]; /* destination hardware address */ int pkt_size; struct pppoe_packet *packet = NULL; struct pppoe_tag *tag = NULL; int state = CODE_PADI; /* main discovery loop */ if (get_hw_addr (disc_sock, if_name, src_addr) != 0) { fprintf (stderr, "pppoe: unable to get hardware address\n"); return -1; } #if 0 printf ("state is: %x if_name %s PADR_ret %d PADI_ret %d\n", state, if_name, PADR_ret, PADI_ret); printf ("<%s> src hware address %x:%x:%x:%x:%x:%x\n", if_name, src_addr[0], src_addr[1], src_addr[2], src_addr[3], src_addr[4], src_addr[5]); printf ("0name is: %s\n", ses_table[0].name); printf ("0MAC: %x:%x:%x:%x:%x:%x\n", ses_table[lineid].dmac[0] & 0xff, ses_table[lineid].dmac[1] & 0xff, ses_table[lineid].dmac[2] & 0xff, ses_table[lineid].dmac[3] & 0xff, ses_table[lineid].dmac[4] & 0xff, ses_table[lineid].dmac[5] & 0xff); #endif while (1) { /* printf("\n State %x\n",state); read_setup(); state=STATE_RUN; */ if (state == STATE_RUN) break; switch (state) { case CODE_PADI: /* initiate ppp_connection */ #ifdef DISC_DEB printf ("Sending PADI\n"); #endif /* start the PPPoE session */ if ((pkt_size = create_padi (&packet, src_addr, NULL)) == 0) { fprintf (stderr, "pppoe: unable to create PADI packet\n"); exit (1); } /* send the PADI packet */ if (send_packet (disc_sock, packet, pkt_size, if_name) < 0) { fprintf (stderr, "pppoe: unable to send PADI packet\n"); exit (1); } ret_pkt = packet; ret_pkt_size = pkt_size; state = CODE_PADO; break; case CODE_PADO: /* wait for PADO */ #ifdef DISC_DEB printf ("waiting for PADO\n"); #endif if (wait_for_packet (&disc_sock, 1, &packet, &pkt_size, PADI_ret) != disc_sock || (packet->code != CODE_PADO && packet->code != CODE_PADT)) { if (packet->code == CODE_PADI) /* just an echo */ return -1; fprintf (stderr, "pppoe: unexpected packet %x\n", packet->code); continue; } if (packet->code == CODE_PADT) { /* early termination */ state = CODE_PADT; continue; } #ifdef DISC_DEB2 printf ("PADO received!\n"); print_packet (packet); printf ("PADO printed!\n"); #endif memcpy (dst_addr, packet->ethhdr.h_source, ETH_ALEN); /* some really nasty coding here; try to re-use M Ostrowskis code instead at some point */ if (ntohs (packet->length) > 0) tag = scan_tag (ntohs (packet->length), (struct pppoe_tag *) (packet + 1), TAG_AC_COOKIE); state = CODE_PADR; break; case CODE_PADR: /* send PADR */ #ifdef DISC_DEB printf ("Sending PADR\n"); #endif if ((pkt_size = create_padr (&packet, src_addr, dst_addr, NULL, tag)) == 0) { fprintf (stderr, "pppoe: unable to create PADR packet\n"); exit (1); } if (tag) { free (tag); tag = NULL; } if (send_packet (disc_sock, packet, pkt_size, if_name) < 0) { fprintf (stderr, "pppoe: unable to send PADR packet\n"); exit (1); } state = CODE_PADS; ret_pkt = packet; ret_pkt_size = pkt_size; break; case CODE_PADS: /* wait for PADS */ #ifdef DISC_DEB printf ("Waiting for PADS\n"); #endif if (wait_for_packet (&disc_sock, 1, &packet, &pkt_size, PADR_ret) != disc_sock || (packet->code != CODE_PADS && packet->code != CODE_PADT)) { if (packet->code == CODE_PADR) /* just an echo */ return -1; fprintf (stderr, "pppoe: unexpected packet %x\n", packet->code); continue; } if (memcmp (packet->ethhdr.h_source, dst_addr, sizeof (dst_addr)) != 0) continue; /* discard packets not from AC */ if (packet->code == CODE_PADT) { /* early termination */ state = CODE_PADT; continue; } socks[0] = disc_sock; printf ("OK! Discovery is completed successfully\n"); ses_table[lineid].line = lineid; ses_table[lineid].sid = packet->session; printf ("We got session ID %d %x\n", ntohs (packet->session), ntohs (packet->session)); memcpy (&ses_table[lineid].dmac, dst_addr, ETH_ALEN); printf ("AC MAC: %x:%x:%x:%x:%x:%x\n", ses_table[lineid].dmac[0] & 0xff, ses_table[lineid].dmac[1] & 0xff, ses_table[lineid].dmac[2] & 0xff, ses_table[lineid].dmac[3] & 0xff, ses_table[lineid].dmac[4] & 0xff, ses_table[lineid].dmac[5] & 0xff); state = STATE_RUN; /* should start a thread here which just waits for a PADT packet */ break; case STATE_RUN: /* running */ break; case CODE_PADT: /* received a PADT */ return -1; break; default: fprintf (stderr, "pppoe: invalid state %x", state); exit (1); } } return (0); } void sigproc (int src) { printf ("\n *** Receieved signal %d ***** \n", src); exit (1); } void sigchild (int src) { pid_t pid; int status; int i; pid = waitpid (-1, &status, WNOHANG); printf ("\n *** Child Received signal %d PID %d ***** \n", src, pid); printf ("status is: %d\n", status); if (pid < 1) { return; } /* scan */ for (i = 0; i < 16; i++) { if (ses_table[i].pid == pid) { printf ("Line id which died is: %d\n", i); ses_table[i].state = DISCONNECTED; break; } } } int open_socket () { int sockid; sockid = socket (AF_INET, SOCK_DGRAM, 0); if (sockid < 0) exit (-1); /* could do better than this */ return sockid; } int cntrl (lineid) { struct ifreq ifr; ifr.ifr_addr.sa_family = AF_INET; ifr.ifr_hwaddr.sa_family = lineid; /* double check the endianness here */ ifr.ifr_hwaddr.sa_data[1] = (ses_table[lineid].sid >> 8) & 0xff; ifr.ifr_hwaddr.sa_data[0] = ses_table[lineid].sid & 0xff; printf ("\n cntrl: SessionID (%x%x) \n", (unsigned short) ifr.ifr_hwaddr.sa_data[1], (unsigned short) ifr.ifr_hwaddr.sa_data[0]); if (ioctl (ctrl_sock, PPPOEIOCSID, &ifr) < 0) { perror ("PPPOEIOCSID"); return (-1); } printf ("Setting AC MAC to: "); printf (" %x:%x:%x:%x:%x:%x\n", ses_table[lineid].dmac[0] & 0xff, ses_table[lineid].dmac[1] & 0xff, ses_table[lineid].dmac[2] & 0xff, ses_table[lineid].dmac[3] & 0xff, ses_table[lineid].dmac[4] & 0xff, ses_table[lineid].dmac[5] & 0xff); memcpy (&ifr.ifr_hwaddr.sa_data, ses_table[lineid].dmac, 6); if (ioctl (ctrl_sock, PPPOEIOCDMAC, &ifr) < 0) { perror ("PPPOEIOCDMAC"); return (-1); } strcpy (ifr.ifr_name, ses_table[lineid].name); printf ("Setting device name to %s \n", ifr.ifr_name); if (ioctl (ctrl_sock, PPPOEIODID, &ifr) < 0) { perror ("PPPOEIODID"); return (-1); } return (0); } /* **********************************************88 */ int lineid = 0; char *fname; int num_restart = 1; /* 1 restart means no restart */ char pppox[6]; int ppp_connect (void) { int pid; restart: num_restart--; printf ("\nTotal retries to go %d\n", num_restart); if ((disc_sock = create_raw_socket (ETH_P_PPPOE_DISC)) < 0) { fprintf (stderr, "pppoe: unable to create raw socket\n"); return 1; } /* we block until we extablish a ppp_connection in this version */ if (server_discover (lineid) < 0) { // printf (" sorry we died \n"); printf ("PPPoE connection timeout - aborting...\n"); exit (-1); } close (disc_sock); /* dont need it anymore */ /* at this point we know the destination MAC address, the session ID, the device, */ printf ("MAC: %x:%x:%x:%x:%x:%x\n", ses_table[lineid].dmac[0] & 0xff, ses_table[lineid].dmac[1] & 0xff, ses_table[lineid].dmac[2] & 0xff, ses_table[lineid].dmac[3] & 0xff, ses_table[lineid].dmac[4] & 0xff, ses_table[lineid].dmac[5] & 0xff); #if 0 /* for debugging only, turn this off in the real thing */ /* populate table */ read_setup (); #endif ctrl_sock = open_socket (); /* download the cntrl info for this lineid */ cntrl (lineid); close (ctrl_sock); signal (SIGINT, &sigproc); signal (SIGTERM, &sigproc); signal (SIGCHLD, &sigchild); /* now lets fire the PPP session TODO: use pthreads */ pid = fork (); if (ses_table[lineid].pid < 0) { printf ("pppd: unable to fork(), abandoning!\n"); /* call some cleanup routine */ exit (-1); } ses_table[lineid].pid = pid; if (!pid) { /* the speed is meaningless really, but pppd insists */ printf ("\nstarting pppd using options file: %s to pppox interface %s\n", fname, pppox); if (execl ("/usr/sbin/pppd", "-d", pppox, "38400", "file", fname, NULL) < 0) { perror ("PPP"); exit (-1); } } printf ("\nPPP started pid is: %d\n", ses_table[lineid].pid + 1); /* sit here and asynchronously wait for a PADT or issue a PADT should the user decide to terminate the ppp_connection Hmmmm ... maybe we should have an option to restart the ppp_connection if it dies */ /* move to ppp_connected state only after pppd has been started */ ses_table[lineid].state = CONNECTED; pause (); ses_table[lineid].state = DISCONNECTED; printf ("\n OK we got killed\n"); if (!num_restart) exit (0); goto restart; } int print_help () { printf ("\npppoe version %d.%d build %d\n", VERSION_MAJOR, VERSION_MINOR, VERSION_DATE); printf ("recognized options are: \n"); printf (" -I : overides the default interface of eth0\n"); printf (" -P : overides the default pppox of pppox0. Used to have multiple sessions\n"); printf (" -S : starts pppoed in server mode\n"); printf (" -R : forces pppoed to be restarted num_retries should the other end be detected to be dead. Needs lcp_echo. Read the INSTALL file instructions\n"); printf (" -F : overides the default ppp options file of /etc/ppp/options \n"); printf (" -L : sets a log file where verbose output is sent \n"); printf ("\n"); exit (0); } int main (int argc, char **argv) { int opt; /* only worry about a single ppp_connection (ppp0) in this version */ /* the number of PADI and PADR retransmits. We should be able to use the command line options to pass these instead */ PADR_ret = 5; PADI_ret = 5; if ((if_name = malloc (strlen (("eth0") + 1))) == NULL) { printf ("Error Mallocing for default ifname\n"); exit (-1); } if ((fname = malloc (256)) == NULL) { printf ("Error Mallocing for default ifname\n"); exit (-1); } /* defaults to eth0 */ strcpy (if_name, "eth0"); strcpy (fname, "/etc/ppp/options"); /* parse options */ while ((opt = getopt (argc, argv, "R:I:F:L:V:P:S")) != -1) switch (opt) { case 'R': /* sets number of retries */ num_restart = strtol (optarg, (char **) NULL, 10); num_restart += 1; break; case 'I': /* sets interface */ strcpy (if_name, optarg); opt_verbose = 1; break; case 'F': /* sets the options file */ if (strlen (optarg) > 255) { printf ("filenname cannot exceed 256 characters\n"); exit (-1); } strcpy (fname, optarg); break; case 'L': /* log file */ opt_verbose = 1; if (log_file != NULL) fclose (log_file); if ((log_file = fopen (optarg, "w")) == NULL) { fprintf (stderr, "fopen\n"); exit (1); } break; case 'P': /* lineid */ lineid = strtol (optarg, (char **) NULL, 10); printf ("lineid set to %s %d\n", optarg, lineid); break; case '?': /* version */ case 'V': /* version */ printf ("\npppoe version %d.%d build %d\n", VERSION_MAJOR, VERSION_MINOR, VERSION_DATE); exit (0); break; case 'S': /* server mode */ printf ("pppoe server mode not supported in this version\n"); exit (0); break; default: fprintf (stderr, "Unknown option %c\n", optopt); print_help (); exit (1); } strcpy (ses_table[lineid].name, if_name); /* strcpy (pppox, "pppox"); */ /* careful with overflows here; this runs as root at the moment, so OK */ sprintf (pppox, "pppox%d", lineid); ppp_connect (); exit (0); }