1 /* pppoe, a PPP-over-Ethernet redirector
2 * Copyright (C) 1999 Luke Stras <stras@ecf.toronto.edu>
3 *
4 *    This program is free software; you can redistribute it and/or modify
5 *    it under the terms of the GNU General Public License as published by
6 *    the Free Software Foundation; either version 2 of the License, or
7 *    (at your option) any later version.
8 *
9 *    This program is distributed in the hope that it will be useful,
10 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *    GNU General Public License for more details.
13 *
14 *    You should have received a copy of the GNU General Public License
15 *    along with this program; if not, write to the Free Software
16 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 * Revision History
19 * 1999/09/22 stras Initial version
20 * 1999/09/24 stras Changed header files for greater portability
21 * 1999/10/02 stras Added more logging, bug fixes
22 * 1999/10/02 mr    Port to bpf/OpenBSD; starvation fixed; efficiency fixes
23 * 1999/10/18 stras added BUGGY_AC code, partial forwarding
24 */
25
26#include <sys/types.h>
27/* foxconn wklin added start, 07/26/2007 */
28#include <sys/stat.h>
29/* foxconn wklin added end, 07/26/2007 */
30#include <sys/socket.h>
31#include <netinet/in.h>
32#include <sys/time.h> /* wklin added, 01/10/2007 */
33/* Foxconn modified start Winster Chan 11/25/2005 */
34/* #include <net/if.h> */
35#include "pppoe.h"
36/* Foxconn modified end Winster Chan 11/25/2005 */
37#include <sys/sysinfo.h> /*added by EricHuang, 01/11/2007*/
38
39#ifdef __linux__
40#include <net/if_arp.h>
41#endif /* __linux__ */
42#if defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ < 6
43#include <linux/if_ether>
44#else
45#include <netinet/if_ether.h>
46#endif
47
48#include <assert.h>
49#ifdef __linux__
50#include <getopt.h>
51#endif
52#include <signal.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57
58/* #include <sys/time.h> */
59#include <time.h>
60#include <sys/ioctl.h>
61#include <sys/wait.h>
62
63
64#ifdef USE_BPF
65#ifndef ETH_ALEN
66#define ETH_ALEN 6
67#endif /* ETH_ALEN */
68/* set this to desired size - you may not get this */
69int bpf_buf_size = 65536;
70#include <net/bpf.h>
71#include <fcntl.h>
72#include <nlist.h>
73#include <kvm.h>
74unsigned char local_ether[ETH_ALEN]; /* need to this filter packets */
75#endif /* USE_BPF */
76
77#include <errno.h>
78#ifdef __linux__
79extern int errno;
80#endif
81
82/* used as the size for a packet buffer */
83/* should be > 2 * size of max packet size */
84#define PACKETBUF (4096 + 30)
85/* Foxconn added start Winster Chan 11/25/2005 */
86#define TAGBUF 128
87/* Foxconn added end Winster Chan 11/25/2005 */
88
89/* Foxconn added start, Winster Chan, 06/26/2006 */
90static int poxfd = -1;
91static int pppfd = -1;
92unsigned short sessId = 0;
93char dstMac[ETH_ALEN];
94/* Foxconn added start, Winster Chan, 06/26/2006 */
95
96char *service_name = NULL; /* foxconn wklin added, 03/27/2007 */
97
98#define VERSION_MAJOR 0
99#define VERSION_MINOR 3
100
101/* references: RFC 2516 */
102/* ETHER_TYPE fields for PPPoE */
103
104#define ETH_P_PPPOE_DISC 0x8863 /* discovery stage */
105#define ETH_P_PPPOE_SESS 0x8864 /* session stage */
106
107/* ethernet broadcast address */
108#define MAC_BCAST_ADDR "\xff\xff\xff\xff\xff\xff"
109
110/* PPPoE packet; includes Ethernet headers and such */
111struct pppoe_packet {
112#ifdef __linux__
113    struct ethhdr ethhdr; /* ethernet header */
114#else
115    struct ether_header ethhdr; /* ethernet header */
116#endif
117    unsigned int ver:4; /* pppoe version */
118    unsigned int type:4; /* pppoe type */
119    unsigned int code:8; /* pppoe code CODE_* */
120    unsigned int session:16; /* session id */
121    unsigned short length; /* payload length */
122    /* payload follows */
123};
124
125/* maximum payload length */
126#define MAX_PAYLOAD (1484 - sizeof(struct pppoe_packet))
127
128/* PPPoE codes */
129#define CODE_SESS 0x00 /* PPPoE session */
130#define CODE_PADI 0x09 /* PPPoE Active Discovery Initiation */
131#define CODE_PADO 0x07 /* PPPoE Active Discovery Offer */
132#define CODE_PADR 0x19 /* PPPoE Active Discovery Request */
133#define CODE_PADS 0x65 /* PPPoE Active Discovery Session-confirmation */
134#define CODE_PADT 0xa7 /* PPPoE Active Discovery Terminate */
135
136/* also need */
137#define STATE_RUN (-1)
138
139/* PPPoE tag; the payload is a sequence of these */
140struct pppoe_tag {
141    unsigned short type; /* tag type TAG_* */
142    unsigned short length; /* tag length */
143    /* payload follows */
144} __attribute__ ((packed)); /*added by EricHuang, 07/23/2007*/
145
146/* Foxconn added start Winster Chan 11/25/2005 */
147#define TAG_STRUCT_SIZE  sizeof(struct pppoe_tag)
148#define PPP_PPPOE_SESSION   "/tmp/ppp/pppoe_session"
149/*#define PPP_PPPOE_IFNAME    "/tmp/ppp/pppoe_ifname"*/
150/* Foxconn added end Winster Chan 11/25/2005 */
151
152/* PPPoE tag types */
153#define TAG_END_OF_LIST        0x0000
154#define TAG_SERVICE_NAME       0x0101
155#define TAG_AC_NAME            0x0102
156#define TAG_HOST_UNIQ          0x0103
157#define TAG_AC_COOKIE          0x0104
158#define TAG_VENDOR_SPECIFIC    0x0105
159#define TAG_RELAY_SESSION_ID   0x0110
160#define TAG_SERVICE_NAME_ERROR 0x0201
161#define TAG_AC_SYSTEM_ERROR    0x0202
162#define TAG_GENERIC_ERROR      0x0203
163
164/* globals */
165int opt_verbose = 0;   /* logging */
166int opt_fwd = 0;       /* forward invalid packets */
167int opt_fwd_search = 0; /* search for next packet when forwarding */
168FILE *log_file = NULL;
169FILE *error_file = NULL;
170
171pid_t sess_listen = 0, pppd_listen = 0; /* child processes */
172int disc_sock = 0, sess_sock = 0; /* PPPoE sockets */
173char src_addr[ETH_ALEN]; /* source hardware address */
174char dst_addr[ETH_ALEN]; /* destination hardware address */
175char *if_name = NULL; /* interface to use */
176int session = 0; /* identifier for our session */
177int clean_child = 0; /* flag set when SIGCHLD received */
178/* Foxconn added start Winster Chan 11/25/2005 */
179char pado_tags[TAGBUF]; /* TAGs of PADO */
180int pado_tag_size = 0;
181typedef struct {
182    unsigned short  usPadLen;   /* Tag length in type of unsigned short */
183    int             nPadLen;    /* Tag length in type of integer */
184    char            *pPadStart; /* Start point of tag payload */
185} sPadxTag, *pPadxTag;
186/* Foxconn added end Winster Chan 11/25/2005 */
187
188/* Winster Chan debugtest */
189#define DEBUG_PRINT_PACKET  0
190#define DEBUG_SEND_PACKET   0
191#define BUFRING             40
192#define DEBUG_PRINT         0
193#define PPPOE_DEBUG_FILE    "/tmp/ppp/pppoeDbg"
194FILE *fp0;
195pid_t main_pid, sess_pid, pppd_pid;
196
197
198typedef struct {
199    /* unsigned char *pBufAddr; */
200    unsigned char packetBuf[PACKETBUF];
201} sPktBuf, *pPktBuf;
202
203void
204print_hex(unsigned char *buf, int len)
205{
206    int i;
207
208    if (opt_verbose == 0)
209      return;
210
211    for (i = 0; i < len; i++)
212      fprintf(log_file, "%02x ", (unsigned char)*(buf+i));
213
214    fprintf(log_file, "\n");
215}
216
217void
218print_packet(struct pppoe_packet *p)
219{
220    int i;
221    struct pppoe_tag *t = (struct pppoe_tag*)(p + 1);
222    struct pppoe_tag tag; /* needed to avoid alignment problems */
223    char *buf;
224    time_t tm;
225
226    if (opt_verbose == 0)
227	return;
228
229    time(&tm);
230
231    fprintf(log_file, "Ethernet header:\n");
232    fprintf(log_file, "h_dest: ");
233#ifdef __linux__
234    for (i = 0; i < 6; i++)
235	fprintf(log_file, "%02x:", (unsigned)p->ethhdr.h_dest[i]);
236#else
237    for (i = 0; i < 6; i++)
238	fprintf(log_file, "%02x:", (unsigned)p->ethhdr.ether_dhost[i]);
239#endif
240    fprintf(log_file, "\nh_source: ");
241#ifdef __linux__
242    for (i = 0; i < 6; i++)
243	fprintf(log_file, "%02x:", (unsigned)p->ethhdr.h_source[i]);
244#else
245    for (i = 0; i < 6; i++)
246	fprintf(log_file, "%02x:", (unsigned)p->ethhdr.ether_shost[i]);
247#endif
248
249#ifdef __linux__
250    fprintf(log_file, "\nh_proto: 0x%04x ",
251	    (unsigned)ntohs(p->ethhdr.h_proto));
252#else
253    fprintf(log_file, "\nh_proto: 0x%04x ",
254	    (unsigned)ntohs(p->ethhdr.ether_type));
255#endif
256
257#ifdef __linux__
258    switch((unsigned)ntohs(p->ethhdr.h_proto))
259#else
260    switch((unsigned)ntohs(p->ethhdr.ether_type))
261#endif
262    {
263    case ETH_P_PPPOE_DISC:
264	fprintf(log_file, "(PPPOE Discovery)\n");
265	break;
266    case ETH_P_PPPOE_SESS:
267	fprintf(log_file, "(PPPOE Session)\n");
268	break;
269    default:
270	fprintf(log_file, "(Unknown)\n");
271    }
272
273    fprintf(log_file, "PPPoE header: \nver: 0x%01x type: 0x%01x code: 0x%02x "
274	   "session: 0x%04x length: 0x%04x ", (unsigned)p->ver,
275	   (unsigned)p->type, (unsigned)p->code, (unsigned)p->session,
276	   (unsigned)ntohs(p->length));
277
278    switch(p->code)
279    {
280    case CODE_PADI:
281	fprintf(log_file, "(PADI)\n");
282	break;
283    case CODE_PADO:
284	fprintf(log_file, "(PADO)\n");
285	break;
286    case CODE_PADR:
287	fprintf(log_file, "(PADR)\n");
288	break;
289    case CODE_PADS:
290	fprintf(log_file, "(PADS)\n");
291	break;
292    case CODE_PADT:
293	fprintf(log_file, "(PADT)\n");
294	break;
295    default:
296	fprintf(log_file, "(Unknown)\n");
297    }
298
299#ifdef __linux__
300    if (ntohs(p->ethhdr.h_proto) != ETH_P_PPPOE_DISC)
301#else
302    if (ntohs(p->ethhdr.ether_type) != ETH_P_PPPOE_DISC)
303#endif
304    {
305	print_hex((unsigned char *)(p+1), ntohs(p->length));
306	return;
307    }
308
309
310    while (t < (struct pppoe_tag *)((char *)(p+1) + ntohs(p->length)))
311    {
312	/* no guarantee in PPPoE spec that t is aligned at all... */
313	memcpy(&tag,t,sizeof(tag));
314	fprintf(log_file, "PPPoE tag:\ntype: %04x length: %04x ",
315		ntohs(tag.type), ntohs(tag.length));
316	switch(ntohs(tag.type))
317	{
318	case TAG_END_OF_LIST:
319	    fprintf(log_file, "(End of list)\n");
320	    break;
321	case TAG_SERVICE_NAME:
322	    fprintf(log_file, "(Service name)\n");
323	    break;
324	case TAG_AC_NAME:
325	    fprintf(log_file, "(AC Name)\n");
326	    break;
327	case TAG_HOST_UNIQ:
328	    fprintf(log_file, "(Host Uniq)\n");
329	    break;
330	case TAG_AC_COOKIE:
331	    fprintf(log_file, "(AC Cookie)\n");
332	    break;
333	case TAG_VENDOR_SPECIFIC:
334	    fprintf(log_file, "(Vendor Specific)\n");
335	    break;
336	case TAG_RELAY_SESSION_ID:
337	    fprintf(log_file, "(Relay Session ID)\n");
338	    break;
339	case TAG_SERVICE_NAME_ERROR:
340	    fprintf(log_file, "(Service Name Error)\n");
341	    break;
342	case TAG_AC_SYSTEM_ERROR:
343	    fprintf(log_file, "(AC System Error)\n");
344	    break;
345	case TAG_GENERIC_ERROR:
346	    fprintf(log_file, "(Generic Error)\n");
347	    break;
348	default:
349	    fprintf(log_file, "(Unknown)\n");
350	}
351	if (ntohs(tag.length) > 0)
352	    switch (ntohs(tag.type))
353	    {
354	    case TAG_SERVICE_NAME:
355	    case TAG_AC_NAME:
356	    case TAG_SERVICE_NAME_ERROR:
357	    case TAG_AC_SYSTEM_ERROR:
358	    case TAG_GENERIC_ERROR: /* ascii data */
359		buf = malloc(ntohs(tag.length) + 1);
360		memset(buf, 0, ntohs(tag.length)+1);
361		strncpy(buf, (char *)(t+1), ntohs(tag.length));
362		buf[ntohs(tag.length)] = '\0';
363		fprintf(log_file, "data (UTF-8): %s\n", buf);
364		free(buf);
365		break;
366
367	    case TAG_HOST_UNIQ:
368	    case TAG_AC_COOKIE:
369	    case TAG_RELAY_SESSION_ID:
370		fprintf(log_file, "data (bin): ");
371		for (i = 0; i < ntohs(tag.length); i++)
372		    fprintf(log_file, "%02x", (unsigned)*((char *)(t+1) + i));
373		fprintf(log_file, "\n");
374		break;
375
376	    default:
377		fprintf(log_file, "unrecognized data\n");
378	    }
379	t = (struct pppoe_tag *)((char *)(t+1)+ntohs(tag.length));
380    }
381}
382
383/* Foxconn added start, Winster Chan, 06/26/2006 */
384/**************************************************************************
385** Function:    addr_itox()
386** Description: Convert the <int> address value getting from file to
387**                  <unsigned char> address type.
388** Parameters:  (unsigned char *) daddr -- destination address value
389**              (int *) saddr -- source address value
390**              (int) convlen -- convert length
391** Return:      none.
392**************************************************************************/
393static void addr_itox(unsigned char *daddr, int *saddr, int convlen)
394{
395    int i;
396
397    for (i = 0; i < convlen; i++)
398        daddr[i] = (unsigned char)saddr[i];
399}
400
401/**************************************************************************
402** Function:    pptp_pppox_open()
403** Description: Open socket to kernel pppox driver, and open ppp device
404** Parameters:  (int *) poxfd -- pointer of file descriptor for pppox
405**              (int *) pppfd -- pointer of file descriptor for ppp device
406** Return:      none.
407**************************************************************************/
408void pptp_pppox_open(int *poxfd, int *pppfd)
409{
410    /* Open socket to pppox kernel module */
411    *poxfd = socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_OE);
412    if (*poxfd >= 0) {
413        /* Open ppp device */
414        *pppfd = open("/dev/ppp", O_RDWR);
415    }
416    else {
417        *poxfd = -1;
418        *pppfd = -1;
419    }
420}
421
422/**************************************************************************
423** Function:    pptp_pppox_get_info()
424** Description: Get the essential information for connecting pptp kernel
425**                  module. Such as Source IP, Destination IP, Remote MAC
426**                  address, Device name, call_id, and peer_call_id, etc.
427** Parameters:  none.
428** Return:      (struct sockaddr_pppox)sp_info -- structure of information.
429**************************************************************************/
430struct sockaddr_pppox pptp_pppox_get_info(void)
431{
432    struct sockaddr_pppox sp_info;
433    /* Foxconn modified start pling 01/17/2007 */
434    /* char devName[] = "eth0"; */
435    char devName[16];
436    strcpy(devName, if_name);
437    /* Foxconn modified end pling 01/17/2007 */
438
439    memset(&sp_info, 0, sizeof(struct sockaddr_pppox));
440
441    sp_info.sa_family = AF_PPPOX;
442    sp_info.sa_protocol = PX_PROTO_OE;
443    sp_info.sa_addr.pppoe.sid = sessId;   /* PPPoE session ID */
444    memcpy(sp_info.sa_addr.pppoe.remote, dstMac, ETH_ALEN); /* Remote MAC address */
445    memcpy(sp_info.sa_addr.pppoe.dev, devName, strlen(devName)); /* Remote MAC address */
446
447    return (struct sockaddr_pppox)sp_info;
448}
449
450/**************************************************************************
451** Function:    pptp_pppox_connect()
452** Description: Actually connect to pppox kernel module with the structure
453**                  got by pptp_pppox_get_info().
454** Parameters:  (int *) poxfd -- pointer of file descriptor for pppox
455**              (int *) pppfd -- pointer of file descriptor for ppp device
456** Return:      (int)err -- Fail = -1
457**                          Success = 0.
458**************************************************************************/
459/* foxconn wklin modified start, 07/31/2007 */
460int  pptp_pppox_connect(int *poxfd, int *pppfd)
461{
462    struct sockaddr_pppox lsp;
463    int err = -1;
464    int chindex;
465	int flags;
466
467    memset(&lsp, 0, sizeof(struct sockaddr_pppox));
468    lsp = pptp_pppox_get_info();
469
470    if (*poxfd >= 0) {
471        /* Connect pptp kernel connection */
472        err = connect(*poxfd, (struct sockaddr*)&lsp,
473            sizeof(struct sockaddr_pppox));
474        if (err == 0) {
475            /* Get PPP channel */
476            if (ioctl(*poxfd, PPPIOCGCHAN, &chindex) == -1) {
477                fprintf(stderr, "Couldn't get channel number");
478                return -1;
479            }
480
481            if (*pppfd >= 0) {
482                /* Attach to PPP channel */
483                if ((err = ioctl(*pppfd, PPPIOCATTCHAN, &chindex)) < 0) {
484                    fprintf(stderr, "Couldn't attach to channel");
485                    return -1;
486                }
487                flags = fcntl(*pppfd, F_GETFL);
488                if (flags == -1 || fcntl(*pppfd, F_SETFL, flags | O_NONBLOCK) == -1) {
489                    fprintf(stderr, "Couldn't set /dev/ppp (channel) to nonblock");
490                    return -1;
491                }
492            }
493            else {
494                fprintf(stderr, "Couldn't reopen /dev/ppp");
495                return -1;
496            }
497        }
498        else {
499            fprintf(stderr, "Couldn't connect pppox, err: %d, %s", err, strerror(errno));
500            return -1;
501        }
502    }
503    return 0;
504}
505/* foxconn wklin modified end, 07/31/2007 */
506
507/**************************************************************************
508** Function:    pptp_pppox_release()
509** Description: Release the connection between user program and pppox kernel
510**                  driver with ioctl() and connect(), and clear the
511**                  essential information in kernel.
512** Parameters:  (int *) poxfd -- pointer of file descriptor for pppox
513**              (int *) pppfd -- pointer of file descriptor for ppp device
514** Return:      (int)err -- Fail = -1
515**                          Success = 0.
516**************************************************************************/
517void pptp_pppox_release(int *poxfd, int *pppfd)
518{
519    struct sockaddr_pppox lsp;
520    int err = -1;
521
522    if (*poxfd >= 0) {
523        memset(&lsp, 0, sizeof(struct sockaddr_pppox));
524        lsp = pptp_pppox_get_info();
525        if (*pppfd >= 0) {
526            /* Detach from PPP */
527    	    if (ioctl(*pppfd, PPPIOCDETACH) < 0)
528                ; /* fprintf(stderr, "pptp_pppox_release ioctl(PPPIOCDETACH)
529                     failed\n"); */ /* foxconn wklin removed, 07/26/2007 */
530	    }
531
532        /* Release pptp kernel connection */
533        lsp.sa_addr.pppoe.sid = 0;
534        err = connect(*poxfd, (struct sockaddr*)&lsp,
535            sizeof(struct sockaddr_pppox));
536        if (err != 0)
537            fprintf(stderr, "Couldn't connect to pptp kernel module\n");
538    }
539    else
540        fprintf(stderr, "Couldn't connect socket to pppox\n");
541}
542/* Foxconn added end, Winster Chan, 06/26/2006 */
543
544int
545open_interface(char *if_name, unsigned short type, char *hw_addr)
546{
547/* BSD stuff by mr */
548#ifdef USE_BPF
549  int fd;
550  struct ifreq ifr;
551  char bpf[16];
552  int i, opt;
553#ifdef SIMPLE_BPF
554  /* a simple BPF program which just grabs the packets of the given type */
555  /* by default use the clever BPF program - it works on my SPARC which
556     has the same endian as network order.  If someone can confirm that
557     the ordering also works on the opposite ending (e.g. ix86) I'll
558     remove the simple filter BPF program for good */
559  struct bpf_insn filt[] = {
560    BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
561    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0 /* fill-in */, 0, 1), /* check type */
562    BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
563    BPF_STMT(BPF_RET+BPF_K, 0)
564  };
565#else
566  /* by default use the clever BPF program which filters out packets
567     originating from us in the kernel */
568  /* note that we split the 6-byte ethernet address into a 4-byte word
569     and 2-byte half-word to minimize the number of comparisons */
570  struct bpf_insn filt[] = {
571    BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
572    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0 /* fill-in */, 0, 5), /* check type */
573    /* check src address != our hw address */
574    BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 6),
575    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0 /* fill-in */, 0, 2), /* 4 bytes */
576    BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 10),
577    BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0 /* fill-in */, 1, 0), /* 2 bytes */
578    BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
579    BPF_STMT(BPF_RET+BPF_K, 0)
580  };
581#endif /* SIMPLE_BPF */
582  struct bpf_program prog;
583
584  /* hunt for an open bpf */
585  for(i = 0; i < 10; i++) {  /* this max is arbitrary */
586    sprintf(bpf,"/dev/bpf%d",i);
587    if ((fd = open(bpf, O_RDWR)) >= 0)
588      break;
589  }
590  if (fd < 0) {
591    perror("pppoe: open(bpf)");
592    return -1;
593  }
594
595   /* try to increase BPF size if possible */
596   (void) ioctl(fd, BIOCSBLEN, &bpf_buf_size); /* try to set buffer size */
597   if (ioctl(fd, BIOCGBLEN, &bpf_buf_size) < 0) { /* but find out for sure */
598     perror("pppoe: bpf(BIOCGBLEN)");
599     return -1;
600   }
601
602
603  /* attach to given interface */
604  strncpy(ifr.ifr_name,if_name,sizeof(ifr.ifr_name));
605  if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
606    perror("pppoe: bpf(BIOCSETIF)");
607    return -1;
608  }
609
610  /* setup BPF */
611  opt = 1;
612  if (ioctl(fd, BIOCIMMEDIATE, &opt) < 0) {
613    perror("pppoe: bpf(BIOCIMMEDIATE)");
614    return -1;
615  }
616  if (ioctl(fd, BIOCGDLT, &opt) < 0) {
617    perror("pppoe: bpf(BIOCGDLT)");
618    return -1;
619  }
620  if (opt != DLT_EN10MB) {
621    fprintf(stderr, "pppoe: interface %s is not Ethernet!\n", if_name);
622    return -1;
623  }
624
625  /*************************************************************************
626   *
627   * WARNING - Really non-portable stuff follows.  This works on OpenBSD 2.5
628   * and may not work anywhere else.
629   *
630   * What's going on - there's no obvious user-level interface to determine
631   * the MAC address of a network interface in BSD that I know of.  (If
632   * anyone has an idea, please let me know.)  What happens here is that we
633   * dig around in the kernel symbol list to find its list of interfaces,
634   * walk through the list to find the interface we are interested in and
635   * then we can (inobviously) get the ethernet info from that.
636   * I don't like this solution, but it's the best I've got at this point.
637   *
638   *************************************************************************/
639
640  {
641    kvm_t *k;
642    struct nlist n[2];
643    struct ifnet_head ifhead;
644    struct ifnet intf;
645    unsigned long v;
646    char ifn[IFNAMSIZ+1];
647    struct arpcom arp;
648
649    k = kvm_open(NULL,NULL,NULL,O_RDONLY,"pppoe");
650    if (k == NULL) {
651      fprintf(stderr, "pppoe: failed to open kvm\n");
652      return -1;
653    }
654    n[0].n_name = "_ifnet";
655    n[1].n_name = NULL;
656    if (kvm_nlist(k,n) != 0) {
657      fprintf(stderr, "pppoe: could not find interface list\n");
658      kvm_close(k);
659      return -1;
660    }
661    if (kvm_read(k,n[0].n_value,(void *)&ifhead,sizeof(ifhead)) !=
662	sizeof(ifhead)) {
663      fprintf(stderr, "pppoe: could not read ifnet_head structure\n");
664      kvm_close(k);
665      return -1;
666    }
667    v = (unsigned long)(ifhead.tqh_first);
668    while(v != 0) {
669      if (kvm_read(k,v,(void *)&intf,sizeof(intf)) != sizeof(intf)) {
670	fprintf(stderr, "pppoe: could not read ifnet structure\n");
671	kvm_close(k);
672	return -1;
673      }
674      strncpy(ifn,intf.if_xname,IFNAMSIZ);
675      ifn[IFNAMSIZ] = '\0';
676      if (strcmp(ifn,if_name) == 0)
677	/* found our interface */
678	break;
679      else
680	/* walk the chain */
681	v = (unsigned long)(intf.if_list.tqe_next);
682    }
683    if (v == 0) {
684      fprintf(stderr, "pppoe: cannot find interface %s in kernel\n",if_name);
685      kvm_close(k);
686      return -1;
687    }
688    /* since we have the right interface, and we determined previously
689       that it is an ethernet interface, reread from the same address into
690       a "struct arpcom" structure (which begins with a struct ifnet).
691       The ethernet address is located past the end of the ifnet structure */
692    if (kvm_read(k,v,(void *)&arp,sizeof(arp)) != sizeof(arp)) {
693      fprintf(stderr, "could not read arpcom structure\n");
694      kvm_close(k);
695      return -1;
696    }
697    /* whew! */
698    /* save a copy of this for ourselves */
699    memcpy(local_ether,arp.ac_enaddr,ETH_ALEN);
700    if (hw_addr)
701      memcpy(hw_addr,arp.ac_enaddr,ETH_ALEN); /* also copy if requested */
702    kvm_close(k);
703  }
704
705  /* setup BPF filter */
706  {
707    union { unsigned int i; unsigned char b[4]; } x;
708    union { unsigned short i; unsigned char b[2]; } y;
709
710    filt[1].k = type; /* set type of packet we are looking for */
711#ifndef SIMPLE_BPF
712    /* now setup our source address so it gets filtered out */
713    for(i = 0; i < 4; i++)
714      x.b[i] = local_ether[i];
715    for(i = 0; i < 2; i++)
716      y.b[i] = local_ether[i+4];
717    filt[3].k = x.i;
718    filt[5].k = y.i;
719#endif /* SIMPLE_BPF */
720  }
721  prog.bf_insns = filt;
722  prog.bf_len = sizeof(filt)/sizeof(struct bpf_insn);
723  if (ioctl(fd, BIOCSETF, &prog) < 0) {
724    perror("pppoe: bpf(BIOCSETF)");
725    return -1;
726  }
727
728  return fd;
729#else /* do regular linux stuff */
730  int optval = 1, rv;
731  struct ifreq ifr;
732
733  if ((rv = socket(PF_INET, SOCK_PACKET, htons(type))) < 0)
734  {
735      perror("pppoe: socket");
736      return -1;
737  }
738
739  if (setsockopt(rv, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0)
740  {
741      perror("pppoe: setsockopt");
742      return -1;
743  }
744
745  if (hw_addr != NULL) {
746      strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
747
748      if (ioctl(rv, SIOCGIFHWADDR, &ifr) < 0)
749      {
750	  perror("pppoe: ioctl(SIOCGIFHWADDR)");
751	  return -1;
752      }
753
754      if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
755      {
756	  fprintf(error_file, "pppoe: interface %s is not Ethernet!\n", if_name);
757	  return -1;
758      }
759
760      memcpy(hw_addr, ifr.ifr_hwaddr.sa_data, sizeof(ifr.ifr_hwaddr.sa_data));
761
762  }
763  return rv;
764#endif /* USE_BPF / linux */
765}
766
767/* Foxconn added start Winster Chan 12/02/2005 */
768int
769get_padx_tag(struct pppoe_tag *pTag, int nLen, pPadxTag pTagStruc, const unsigned short tagType)
770{
771    int bExitLoop = 0, nSearchLen = 0, bTagFound = 0;
772    struct pppoe_tag *pNextTag;
773
774    pTagStruc->usPadLen = 0;
775    pTagStruc->nPadLen = 0;
776    pTagStruc->pPadStart = NULL;
777
778    while (!bExitLoop && (nSearchLen < nLen)) {
779        if (htons(pTag->type) == tagType) {
780            pTagStruc->usPadLen = pTag->length;
781            pTagStruc->nPadLen = (int)(htons(pTag->length));
782            pTagStruc->pPadStart = (char *)pTag + TAG_STRUCT_SIZE;
783            bExitLoop = 1;
784            bTagFound = 1;
785        }
786        else {
787            pNextTag = (struct pppoe_tag *)((char *)pTag +
788                (TAG_STRUCT_SIZE + (int)(htons(pTag->length))));
789            nSearchLen += (int)((TAG_STRUCT_SIZE + (int)(htons(pTag->length))));
790            pTag = pNextTag;
791        }
792    }
793
794    return bTagFound;
795}
796/* Foxconn added end Winster Chan 12/02/2005 */
797
798int
799create_padi(struct pppoe_packet *packet, const char *src, const char *name)
800{
801    int size;
802
803    if (packet == NULL)
804	return 0;
805
806    /* printf("Winster: create_padi\n"); */
807
808    size = sizeof(struct pppoe_packet) + sizeof(struct pppoe_tag);
809    if (name != NULL)
810	size += strlen(name);
811
812#ifdef __linux__
813    memcpy(packet->ethhdr.h_dest, MAC_BCAST_ADDR, 6);
814    memcpy(packet->ethhdr.h_source, src, 6);
815    packet->ethhdr.h_proto = htons(ETH_P_PPPOE_DISC);
816#else
817    memcpy(packet->ethhdr.ether_dhost, MAC_BCAST_ADDR, 6);
818    memcpy(packet->ethhdr.ether_shost, src, 6);
819    packet->ethhdr.ether_type = htons(ETH_P_PPPOE_DISC);
820#endif
821    packet->ver = 1;
822    packet->type = 1;
823    packet->code = CODE_PADI;
824    packet->session = 0;
825    packet->length = htons(size - sizeof(struct pppoe_packet));
826
827    /* fill out a blank service-name tag */
828    (*(struct pppoe_tag *)(packet+1)).type = htons(TAG_SERVICE_NAME);
829    (*(struct pppoe_tag *)(packet+1)).length = name ? htons(strlen(name)) : 0;
830    if (name != NULL)
831	memcpy((char *)(packet + 1) + sizeof(struct pppoe_tag), name,
832	       strlen(name));
833
834    return size;
835}
836
837int
838create_padr(struct pppoe_packet *packet, const char *src, const char *dst,
839	    char *name)
840{
841    int size;
842    /* Foxconn added start Winster Chan 11/25/2005 */
843    char *pCookieStart = NULL;
844    int nCookieSize = 0;
845    int nNameSize = 0;
846    unsigned short usCookieSize = 0;
847    sPadxTag sTag;
848    /* Foxconn added end Winster Chan 11/25/2005 */
849    /* Foxconn add start, Max Ding, 09/22/2008 for @add TAG_RELAY_SESSION_ID */
850    char *pRelaySessionIdStart = NULL;
851    int nRelaySessionIdSize = 0;
852    unsigned short usRelaySessionIdSize = 0;
853    char *pPacketPoint = packet;
854    /* Foxconn add end, Max Ding, 09/22/2008 */
855
856    if (packet == NULL)
857	return 0;
858
859    size = sizeof(struct pppoe_packet) + TAG_STRUCT_SIZE;
860    if (name != NULL) {
861    	size += strlen(name);
862        /* Foxconn added start Winster Chan 11/25/2005 */
863        nNameSize = strlen(name);
864        /* Foxconn added end Winster Chan 11/25/2005 */
865    }
866
867    /* Foxconn added start Winster Chan 12/02/2005 */
868    /* Add length of AC cookie to packet size */
869    if (get_padx_tag((struct pppoe_tag *)pado_tags, pado_tag_size, &sTag, TAG_AC_COOKIE)) {
870        nCookieSize = sTag.nPadLen;
871        usCookieSize = sTag.usPadLen;
872        pCookieStart = sTag.pPadStart;
873        size += (int)(TAG_STRUCT_SIZE + sTag.nPadLen);
874    }
875    /* Foxconn added end Winster Chan 12/02/2005 */
876    /* Foxconn add start, Max Ding, 09/22/2008 for @add TAG_RELAY_SESSION_ID */
877    if (get_padx_tag((struct pppoe_tag *)pado_tags, pado_tag_size, &sTag, TAG_RELAY_SESSION_ID)) {
878        nRelaySessionIdSize = sTag.nPadLen;
879        usRelaySessionIdSize = sTag.usPadLen;
880        pRelaySessionIdStart = sTag.pPadStart;
881        size += (int)(TAG_STRUCT_SIZE + sTag.nPadLen);
882    }
883    /* Foxconn add end, Max Ding, 09/22/2008 */
884
885#ifdef __linux__
886    memcpy(packet->ethhdr.h_dest, dst, 6);
887    memcpy(packet->ethhdr.h_source, src, 6);
888    packet->ethhdr.h_proto = htons(ETH_P_PPPOE_DISC);
889#else
890    memcpy(packet->ethhdr.ether_dhost, dst, 6);
891    memcpy(packet->ethhdr.ether_shost, src, 6);
892    packet->ethhdr.ether_type = htons(ETH_P_PPPOE_DISC);
893#endif
894    packet->ver = 1;
895    packet->type = 1;
896    packet->code = CODE_PADR;
897    packet->session = 0;
898    packet->length = htons(size - sizeof(struct pppoe_packet));
899
900    /* fill out a blank service-name tag */
901    (*(struct pppoe_tag *)(packet+1)).type = htons(TAG_SERVICE_NAME);
902    (*(struct pppoe_tag *)(packet+1)).length = name ? htons(strlen(name)) : 0;
903    if (name != NULL)
904	memcpy((char *)(packet + 1) + TAG_STRUCT_SIZE, name,
905	       strlen(name));
906
907    pPacketPoint = (char *)(packet+1)+TAG_STRUCT_SIZE+nNameSize;/* Foxconn added by Max Ding, 09/23/2008 @add TAG_RELAY_SESSION_ID */
908    /* foxconn modified start, wklin, 03/27/2007, winster doesn't count name len */
909    /* Foxconn added start Winster Chan 11/25/2005 */
910    /* fill out the AC cookie tag from PADO */
911    if (nCookieSize > 0) {
912        (*(struct pppoe_tag *)((char *)(packet+1)+TAG_STRUCT_SIZE+
913                               nNameSize)).type = htons(TAG_AC_COOKIE);
914        (*(struct pppoe_tag *)((char *)(packet+1)+TAG_STRUCT_SIZE+
915                               nNameSize)).length = usCookieSize;
916        memcpy((char *)(packet+1)+(2*TAG_STRUCT_SIZE)+nNameSize,
917            (char *)pCookieStart, nCookieSize);
918        pPacketPoint = (char *)(packet+1)+(2*TAG_STRUCT_SIZE)+nNameSize+nCookieSize;/* Foxconn added by Max Ding, 09/23/2008 @add TAG_RELAY_SESSION_ID */
919    }
920    /* Foxconn added end Winster Chan 11/25/2005 */
921    /* foxconn modified end, wklin, 03/27/2007 */
922    /* Foxconn add start, Max Ding, 09/22/2008 for @add TAG_RELAY_SESSION_ID */
923    if (nRelaySessionIdSize > 0) {
924        (*(struct pppoe_tag *)(pPacketPoint)).type = htons(TAG_RELAY_SESSION_ID);
925        (*(struct pppoe_tag *)(pPacketPoint)).length = usRelaySessionIdSize;
926        memcpy((pPacketPoint+TAG_STRUCT_SIZE),
927            (char *)pRelaySessionIdStart, nRelaySessionIdSize);
928        pPacketPoint += TAG_STRUCT_SIZE + nRelaySessionIdSize;
929    }
930    /* Foxconn add end, Max Ding, 09/22/2008 */
931
932    memset(((char *)packet) + size, 0, 14);
933    return size;
934}
935
936/* Foxconn added end Winster Chan 12/02/2005 */
937int
938create_padt(struct pppoe_packet *packet, const char *src, const char *dst, unsigned short nSessId)
939{
940    int size;
941    char *pCookieStart = NULL;
942    int nCookieSize = 0;
943    unsigned short usCookieSize = 0;
944    sPadxTag sTag;
945
946    if (packet == NULL)
947	return 0;
948
949    size = sizeof(struct pppoe_packet) + TAG_STRUCT_SIZE;
950
951    if (get_padx_tag((struct pppoe_tag *)pado_tags, pado_tag_size, &sTag, TAG_AC_COOKIE)) {
952        nCookieSize = sTag.nPadLen;
953        usCookieSize = sTag.usPadLen;
954        pCookieStart = sTag.pPadStart;
955        size += (int)(TAG_STRUCT_SIZE + sTag.nPadLen);
956    }
957
958#ifdef __linux__
959    memcpy(packet->ethhdr.h_dest, dst, 6);
960    memcpy(packet->ethhdr.h_source, src, 6);
961    packet->ethhdr.h_proto = htons(ETH_P_PPPOE_DISC);
962#else
963    memcpy(packet->ethhdr.ether_dhost, dst, 6);
964    memcpy(packet->ethhdr.ether_shost, src, 6);
965    packet->ethhdr.ether_type = htons(ETH_P_PPPOE_DISC);
966#endif
967    packet->ver = 1;
968    packet->type = 1;
969    packet->code = CODE_PADT;
970    /*packet->session = session;*/
971    packet->session = nSessId;
972    packet->length = htons(size - sizeof(struct pppoe_packet));
973
974    /* fill out a blank generic-error tag */
975    (*(struct pppoe_tag *)(packet+1)).type = htons(TAG_GENERIC_ERROR);
976    (*(struct pppoe_tag *)(packet+1)).length = 0;
977
978    /* fill out the AC cookie tag from PADO */
979    if (nCookieSize > 0) {
980        (*(struct pppoe_tag *)((char *)(packet+1)+TAG_STRUCT_SIZE)).type
981            = htons(TAG_AC_COOKIE);
982        (*(struct pppoe_tag *)((char *)(packet+1)+TAG_STRUCT_SIZE)).length
983            = usCookieSize;
984        memcpy((char *)(packet+1)+(2*TAG_STRUCT_SIZE),
985            (char *)pCookieStart, nCookieSize);
986    }
987
988    memset(((char *)packet) + size, 0, 14);
989    return size;
990}
991/* Foxconn added end Winster Chan 12/02/2005 */
992
993unsigned short fcstab[256] = {
994    0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
995    0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
996    0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
997    0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
998    0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
999    0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1000    0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1001    0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1002    0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1003    0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1004    0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1005    0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1006    0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1007    0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1008    0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1009    0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1010    0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1011    0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1012    0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1013    0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1014    0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1015    0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1016    0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1017    0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1018    0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1019    0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1020    0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1021    0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1022    0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1023    0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1024    0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1025    0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1026};
1027
1028#define PPPINITFCS16    0xffff  /* Initial FCS value */
1029#define PPPGOODFCS16    0xf0b8  /* Good final FCS value */
1030/*
1031 * Calculate a new fcs given the current fcs and the new data.
1032 */
1033unsigned short pppfcs16(register unsigned short fcs,
1034			register unsigned char * cp,
1035			register int len)
1036{
1037/*    assert(sizeof (unsigned short) == 2);
1038    assert(((unsigned short) -1) > 0); */
1039
1040    while (len--)
1041	fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];
1042
1043    return (fcs);
1044}
1045
1046#define FRAME_ESC 0x7d
1047#define FRAME_FLAG 0x7e
1048#define FRAME_ADDR 0xff
1049#define FRAME_CTL 0x03
1050#define FRAME_ENC 0x20
1051
1052#define ADD_OUT(c) { *out++ = (c); n++; if (opt_verbose) fprintf(log_file, "%x ", (c)); }
1053
1054void encode_ppp(int fd, unsigned char *buf, int len)
1055{
1056    static int first = 0;
1057    unsigned char out_buf[PACKETBUF];
1058    unsigned char *out = out_buf;
1059    unsigned char header[2], tail[2];
1060    int i,n;
1061    unsigned short fcs;
1062    time_t tm;
1063
1064    header[0] = FRAME_ADDR;
1065    header[1] = FRAME_CTL;
1066    fcs = pppfcs16(PPPINITFCS16, header, 2);
1067    fcs = pppfcs16(fcs, buf, len) ^ 0xffff;
1068    tail[0] = fcs & 0x00ff;
1069    tail[1] = (fcs >> 8) & 0x00ff;
1070
1071    if (opt_verbose)
1072    {
1073	time(&tm);
1074	fprintf(log_file, "%sWriting to pppd: \n", ctime(&tm));
1075    }
1076
1077    n = 0;
1078    if (!first) {
1079	ADD_OUT(FRAME_FLAG);
1080	first = 1;
1081    }
1082    ADD_OUT(FRAME_ADDR); /* the header - which is constant */
1083    ADD_OUT(FRAME_ESC);
1084    ADD_OUT(FRAME_CTL ^ FRAME_ENC);
1085
1086    for (i = 0; i < len; i++)
1087	if (buf[i] == FRAME_FLAG || buf[i] == FRAME_ESC || buf[i] < 0x20)
1088	{
1089	    ADD_OUT(FRAME_ESC);
1090	    ADD_OUT(buf[i] ^ FRAME_ENC);
1091	}
1092	else
1093	    ADD_OUT(buf[i]);
1094
1095    for (i = 0; i < 2; i++) {
1096	if (tail[i] == FRAME_FLAG || tail[i] == FRAME_ESC || tail[i] < 0x20) {
1097	    ADD_OUT(FRAME_ESC);
1098	    ADD_OUT(tail[i] ^ FRAME_ENC);
1099	} else
1100	    ADD_OUT(tail[i]);
1101    }
1102    ADD_OUT(FRAME_FLAG);
1103
1104    write(fd, out_buf, n);
1105
1106    if (opt_verbose)
1107	fprintf(log_file, "\n");
1108}
1109
1110int
1111create_sess(struct pppoe_packet *packet, const char *src, const char *dst,
1112	    unsigned char *buf, int bufsize, int sess, int *bufRemain)
1113{
1114    int size;
1115    int i, o = 0;
1116    int nBufLen = 0;
1117    int nTotalLen = 0, nAllLen = 0;
1118    int nTemp = 0;
1119    unsigned short usTotalLen = 0x0;
1120    unsigned char bufLen[2];
1121
1122    /* Clear the length of remain buffer */
1123    *bufRemain = 0;
1124
1125    if (opt_fwd || !((buf[0] == FRAME_FLAG) || (buf[0] == FRAME_ADDR)))
1126    {
1127    	if (opt_fwd_search) /* search for a valid packet */
1128    	{
1129    	    while (*buf++ != FRAME_FLAG && bufsize != 0)
1130    		bufsize--;
1131            if (bufsize == 0) {
1132                fprintf(error_file, "create_sess: bufsize == 0\n");
1133                return 0;
1134            }
1135    	}
1136    	else
1137    	{
1138    	    /* fprintf(error_file, "create_sess: invalid data\n"); */ /* foxconn wklin
1139                                                                         removed,
1140                                                                         07/26/2007
1141                                                                         */
1142    	    return 0;
1143    	}
1144    }
1145
1146    bufLen[0] = 0x0;
1147    bufLen[1] = 0x0;
1148    if (bufsize <= 4) {
1149        *bufRemain = bufsize;
1150        return 0;
1151    }
1152    else {
1153        nTemp = (buf[0] == FRAME_FLAG) ? 4 : 3;
1154        for (i = nTemp; i < bufsize; i++) {
1155            if (buf[i] == FRAME_ESC) {
1156                if ((o == 4) || (o == 5))
1157                    bufLen[o-4] = buf[++i] ^ FRAME_ENC;
1158                else
1159                    ++i;
1160            }
1161            else {
1162                if ((o == 4) || (o == 5))
1163                    bufLen[o-4] = buf[i];
1164            }
1165            o++;
1166
1167            /* Get the total length from IP packet header */
1168            if (o == 6) {
1169                usTotalLen = ntohs(*(unsigned short *)bufLen);
1170                nTotalLen = (int)usTotalLen;
1171                nAllLen = nTotalLen + 5;
1172            }
1173
1174            /* Get the total buffer length of packet */
1175            if ((o >= 6) && (o == nAllLen)) {
1176                nBufLen = i + 1;
1177                break;
1178            }
1179        }
1180
1181        if ((o < nAllLen) || (o < 6)) {
1182            *bufRemain = bufsize;
1183            return 0;
1184        }
1185        o = 0;
1186    }
1187
1188    /* for (i = (buf[0] == FRAME_FLAG ? 4 : 3); i < bufsize; i++) { */
1189    for (i = nTemp; i < bufsize; i++) {
1190        if (buf[i] == FRAME_ESC) {
1191            buf[o++] = buf[++i] ^ FRAME_ENC;
1192        }
1193        else {
1194            buf[o++] = buf[i];
1195        }
1196
1197        if (o == nAllLen)
1198            break;
1199    }   /* End for() */
1200
1201    /* Compute the length of remain buffer */
1202    *bufRemain = bufsize - nBufLen;
1203
1204    bufsize = nTotalLen + 2;
1205
1206    if (packet == NULL) {
1207        return 0;
1208    }
1209
1210    size = sizeof(struct pppoe_packet) + bufsize;
1211
1212#ifdef __linux__
1213    memcpy(packet->ethhdr.h_dest, dst, 6);
1214    memcpy(packet->ethhdr.h_source, src, 6);
1215    packet->ethhdr.h_proto = htons(ETH_P_PPPOE_SESS);
1216#else
1217    memcpy(packet->ethhdr.ether_dhost, dst, 6);
1218    memcpy(packet->ethhdr.ether_shost, src, 6);
1219    packet->ethhdr.ether_type = htons(ETH_P_PPPOE_SESS);
1220#endif
1221    packet->ver = 1;
1222    packet->type = 1;
1223    packet->code = CODE_SESS;
1224    packet->session = sess;
1225    packet->length = htons(size - sizeof(struct pppoe_packet));
1226
1227    return size;
1228}
1229
1230int
1231send_packet(int sock, struct pppoe_packet *packet, int len, const char *ifn)
1232{
1233#ifdef USE_BPF
1234  int c;
1235  if ((c = write(sock,packet,len)) != len)
1236    perror("pppoe: write (send_packet)");
1237  return c;
1238#else /* regular linux stuff */
1239    struct sockaddr addr;
1240    int c;
1241    time_t tm;
1242
1243    memset(&addr, 0, sizeof(addr));
1244    strcpy(addr.sa_data, ifn);
1245
1246    if (opt_verbose == 1)
1247    {
1248	time(&tm);
1249	fprintf(log_file, "%sSending ", ctime(&tm));
1250	print_packet(packet);
1251	fputc('\n', log_file);
1252    }
1253
1254
1255    if ((c = sendto(sock, packet, len, 0, &addr, sizeof(addr))) < 0) {
1256	/* fprintf(error_file, "send_packet c[%d] = sendto(len = %d)\n", c, len); */
1257	perror("pppoe: sendto (send_packet)");
1258    }
1259
1260    return c;
1261#endif /* USE_BPF */
1262}
1263
1264#ifdef USE_BPF
1265/* return:  -1 == error, 0 == okay, 1 == ignore this packet */
1266int read_bpf_packet(int fd, struct pppoe_packet *packet) {
1267    /* Nastiness - BPF may return multiple packets in one fell swoop */
1268    /* This makes select() difficult to use - you need to be ready to
1269       clear out packets as they arrive */
1270    static char *buf = NULL;
1271    static int lastdrop = 0;
1272    static int n = 0, off = 0;
1273    struct bpf_hdr *h;
1274
1275    if (buf == NULL) {
1276	if ((buf = malloc(bpf_buf_size)) == NULL) {
1277	    perror("pppoe:malloc");
1278	    return -1;
1279	}
1280    }
1281
1282    if (off < n) {
1283	/* read out of previously grabbed buffer */
1284	if (n-off < sizeof(struct bpf_hdr)) {
1285	    fprintf(stderr, "BPF: not enough left for header:  %d\n", n-off);
1286	    /* fprintf(error_file, "BPF: not enough left for header:  %d\n", n-off); */
1287	    off = n = 0; /* force reread from BPF next time */
1288	    return 1; /* try again */
1289	}
1290	h = (struct bpf_hdr *)&(buf[off]);
1291	memcpy(packet,&(buf[off + h->bh_hdrlen]),h->bh_caplen);
1292	off += BPF_WORDALIGN(h->bh_hdrlen + h->bh_caplen);
1293	if (h->bh_caplen != h->bh_datalen) {
1294	    fprintf(stderr, "pppoe: truncated packet: %d -> %d\n",
1295		    h->bh_datalen, h->bh_caplen);
1296	    /* fprintf(error_file, "BPF: truncated packet: %d -> %d\n",
1297		    h->bh_datalen, h->bh_caplen); */
1298	    return 1; /* try again */
1299	}
1300    } else {
1301	struct bpf_stat s;
1302	if (ioctl(fd,BIOCGSTATS,&s)) {
1303	    perror("pppoe: BIOCGSTATS");
1304	} else {
1305	    if (s.bs_drop > lastdrop) {
1306		fprintf(stderr, "BPF: dropped %d packets\n", s.bs_drop - lastdrop);
1307		/* fprintf(error_file, "BPF: dropped %d packets\n", s.bs_drop - lastdrop); */
1308		lastdrop = s.bs_drop;
1309	    }
1310	}
1311	if ((n = read(fd,buf,bpf_buf_size)) < 0) {
1312	    perror("pppoe: read (read_bpf_packet)");
1313	    return -1;
1314	}
1315	if (n == 0)
1316	    return 0; /* timeout on bpf - try again */
1317	h = (struct bpf_hdr *)(buf);
1318	memcpy(packet,&(buf[h->bh_hdrlen]),h->bh_caplen);
1319	off = BPF_WORDALIGN(h->bh_hdrlen + h->bh_caplen);
1320    }
1321    /* need to filter packets here - interface could be in promiscuous
1322       mode - we shouldn't see packets that we sent out thanks to BPF, but
1323       a quick double-check here is unlikely to seriously impact performance
1324       Once you know BPF is working, you can pop this out */
1325    if (memcmp(packet->ethhdr.ether_shost,local_ether,6) == 0) {
1326#ifdef SIMPLE_BPF
1327	return 1; /* ignore this packet */
1328#else
1329	/* with the bigger BPF program, we should never get here */
1330	fprintf(stderr, "BPF program is broken\n");
1331	exit(1);
1332#endif /* SIMPLE_BPF */
1333    }
1334
1335    if (memcmp(packet->ethhdr.ether_dhost,MAC_BCAST_ADDR,6) == 0 ||
1336	memcmp(packet->ethhdr.ether_dhost,local_ether,6) == 0)
1337	return 0; /* I should look at this packet */
1338    else {
1339	print_packet(packet);
1340	return 1; /* ignore this packet */
1341    }
1342}
1343
1344int is_bpf(int fd) {
1345    /* is this socket tied to bpf? */
1346    /* quick hack() - try a trivial bpf ioctl */
1347    struct bpf_version v;
1348    return (ioctl(fd,BIOCVERSION,&v) == 0);
1349}
1350#endif /* USE_BPF */
1351
1352int
1353read_packet(int sock, struct pppoe_packet *packet, int *len)
1354{
1355/*    struct sockaddr_in from; */
1356#if defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ < 6
1357    int fromlen = PACKETBUF;
1358#else
1359    socklen_t fromlen = PACKETBUF;
1360#endif
1361    time_t tm;
1362
1363    time(&tm);
1364
1365    while(1) {
1366#ifdef USE_BPF
1367	{
1368	    int j;
1369	    if ((j = read_bpf_packet(sock, packet)) < 0)
1370		return -1; /* read_bpf_packet() will report error */
1371	    else if (j > 0)
1372		continue; /* read a packet,  but not what we wanted */
1373	}
1374#else
1375	/* wklin modified start, 01/10/2007 */
1376        fd_set fdset;
1377        struct timeval tm;
1378
1379	FD_ZERO(&fdset);
1380	FD_SET(sock, &fdset);
1381    	tm.tv_usec = 0;
1382	tm.tv_sec = 3; /* wait for 3 seconds */
1383	if (select(sock + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm) <= 0) {
1384            return -1; /* timeout or error */
1385	} else if (FD_ISSET(sock, &fdset)) {
1386	    if (recvfrom(sock, packet, PACKETBUF, 0,
1387		 NULL /*(struct sockaddr *)&from*/, &fromlen) < 0) {
1388	        perror("pppoe: recv (read_packet)");
1389	        return -1;
1390	    }
1391	}
1392#if 0
1393	if (recvfrom(sock, packet, PACKETBUF, 0,
1394		     NULL /*(struct sockaddr *)&from*/, &fromlen) < 0) {
1395	    perror("pppoe: recv (read_packet)");
1396	    return -1;
1397	}
1398#endif /* 0 */
1399	/* wklin modified end, 01/10/2007 */
1400#endif /* USE_BPF */
1401	if (opt_verbose)
1402	{
1403	    fprintf(log_file, "Received packet at %s", ctime(&tm));
1404	    print_packet(packet);
1405	    fputc('\n', log_file);
1406	}
1407
1408	return sock;
1409    }
1410}
1411
1412void sigchild(int src) {
1413    clean_child = 1;
1414}
1415
1416void cleanup_and_exit(int status) {
1417    /* Foxconn modified start, Winster Chan, 06/26/2006 */
1418    pptp_pppox_release(&poxfd, &pppfd);
1419    close(pppfd); pppfd = -1;
1420    close(poxfd); poxfd = -1;
1421    /* Foxconn modified end, Winster Chan, 06/26/2006 */
1422
1423    close(disc_sock);
1424    close(sess_sock);
1425    close(1);
1426
1427    if (pppd_listen > 0)
1428    /*if (pppd_pid > 0)*/
1429    {
1430#ifdef __linux__
1431        kill(pppd_listen, SIGTERM);
1432#else
1433        kill(SIGTERM, pppd_listen);
1434#endif
1435    }
1436    if (sess_listen > 0)
1437    /*if (sess_pid > 0)*/
1438    {
1439#ifdef __linux__
1440        kill(sess_listen, SIGTERM);
1441#else
1442        kill(SIGTERM, sess_listen);
1443#endif
1444    }
1445    /* system("killall pppoecd"); */ /* Foxconn added, Winster Chan, 06/26/2006
1446                                      */ /* foxconn wklin removed, 07/26/2007 */
1447    exit(status);
1448}
1449
1450void sigint(int src)
1451{
1452    /* Foxconn added start Winster Chan 12/02/2005 */
1453    struct pppoe_packet *packet = NULL;
1454    int pkt_size;
1455    FILE *fp;
1456
1457    if (disc_sock && (pppd_listen > 0)) {
1458        /* allocate packet once */
1459        packet = malloc(PACKETBUF);
1460        assert(packet != NULL);
1461
1462        /* send PADT */
1463        if ((pkt_size = create_padt(packet, src_addr, dst_addr, session)) == 0) {
1464  	        fprintf(stderr, "pppoe: unable to create PADT packet\n");
1465            /* exit(1); */
1466        }
1467        if (send_packet(disc_sock, packet, pkt_size+14, if_name) < 0) {
1468            fprintf(stderr, "pppoe: unable to send PADT packet\n");
1469            /* exit(1); */
1470        }  else {
1471            fprintf(stderr, "PPPOE: PADT sent*\n"); /* foxconn wklin added, 07/26/2007 */
1472        }
1473    }
1474    /* Foxconn added end Winster Chan 12/02/2005 */
1475
1476    /* Foxconn added start Winster Chan 12/05/2005 */
1477    if (!(fp = fopen(PPP_PPPOE_SESSION, "w"))) {
1478        perror(PPP_PPPOE_SESSION);
1479    }
1480    else {
1481        /* Clear the PPPoE server MAC address and Session ID */
1482        fprintf(fp, "%02x:%02x:%02x:%02x:%02x:%02x %d\n",
1483            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0);
1484        fclose(fp);
1485    }
1486    /* Foxconn added end Winster Chan 12/05/2005 */
1487    cleanup_and_exit(1);
1488}
1489
1490#ifdef NEW_WANDETECT
1491/*Foxconn added start James 11/12/2008 @new_internet_detection*/
1492void sigint2(int src)
1493{
1494    struct pppoe_packet *packet = NULL;
1495    int pkt_size;
1496    FILE *fp;
1497    time_t tm;
1498
1499    /* allocate packet once */
1500    packet = malloc(PACKETBUF);
1501    assert(packet != NULL);
1502    /* send PADT */
1503    if ((pkt_size = create_padt(packet, src_addr, dst_addr, session)) == 0) {
1504            fprintf(stderr, "pppoe: unable to create PADT packet\n");
1505        /* exit(1); */
1506    }
1507    if (send_packet(disc_sock, packet, pkt_size+14, if_name) < 0) {
1508        fprintf(stderr, "pppoe: unable to send PADT packet\n");
1509        /* exit(1); */
1510    }  else {
1511        time(&tm);
1512        fprintf(stderr, "PPPOE: PADT sent* %s\n",ctime(&tm)); /* foxconn wklin added, 07/26/2007 */
1513    }
1514
1515    /* Foxconn added end Winster Chan 12/02/2005 */
1516
1517    /* Foxconn added start Winster Chan 12/05/2005 */
1518    if (!(fp = fopen(PPP_PPPOE_SESSION, "w"))) {
1519        perror(PPP_PPPOE_SESSION);
1520    }
1521    else {
1522        /* Clear the PPPoE server MAC address and Session ID */
1523        fprintf(fp, "%02x:%02x:%02x:%02x:%02x:%02x %d\n",
1524            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0);
1525        fclose(fp);
1526    }
1527    /* Foxconn added end Winster Chan 12/05/2005 */
1528    cleanup_and_exit(1);
1529
1530}
1531/* Foxconn added end James 11/12/2008 @new_internet_detection */
1532#endif
1533
1534void sess_handler(void) {
1535    /* pull packets of sess_sock and feed to pppd */
1536    struct pppoe_packet *packet = NULL;
1537    int pkt_size;
1538
1539#ifdef BUGGY_AC
1540/* the following code deals with buggy AC software which sometimes sends
1541   duplicate packets */
1542#define DUP_COUNT 10
1543#define DUP_LENGTH 20
1544    unsigned char dup_check[DUP_COUNT][DUP_LENGTH];
1545    int i, ptr = 0;
1546#endif /* BUGGY_AC */
1547
1548#ifdef BUGGY_AC
1549    memset(dup_check, 0, sizeof(dup_check));
1550#endif
1551
1552    /* allocate packet once */
1553    packet = malloc(PACKETBUF);
1554    assert(packet != NULL);
1555
1556    /* fprintf(error_file, "sess_handler %d\n", getpid()); */ /* foxconn wklin
1557                                                                 removed,
1558                                                                 07/27/2007 */
1559    while(1)
1560    {
1561	while(read_packet(sess_sock,packet,&pkt_size) != sess_sock)
1562	    ;
1563#ifdef __linux__
1564	if (memcmp(packet->ethhdr.h_source, dst_addr, sizeof(dst_addr)) != 0)
1565#else
1566	if (memcmp(packet->ethhdr.ether_shost, dst_addr, sizeof(dst_addr))
1567	    != 0)
1568#endif
1569	    continue; /* packet not from AC */
1570	if (packet->session != session)
1571	    continue; /* discard other sessions */
1572#ifdef __linux__
1573	if (packet->ethhdr.h_proto != htons(ETH_P_PPPOE_SESS))
1574	{
1575	    fprintf(log_file, "pppoe: invalid session proto %x detected\n",
1576		    ntohs(packet->ethhdr.h_proto));
1577	    continue;
1578	}
1579#else
1580	if (packet->ethhdr.ether_type != htons(ETH_P_PPPOE_SESS))
1581	{
1582	    fprintf(log_file, "pppoe: invalid session proto %x detected\n",
1583		    ntohs(packet->ethhdr.ether_type));
1584	    continue;
1585	}
1586#endif
1587	if (packet->code != CODE_SESS) {
1588	    fprintf(log_file, "pppoe: invalid session code %x\n", packet->code);
1589	    continue;
1590	}
1591#if BUGGY_AC
1592	/* we need to go through a list of recently-received packets to
1593	   make sure the AC hasn't sent us a duplicate */
1594	for (i = 0; i < DUP_COUNT; i++)
1595	    if (memcmp(packet, dup_check[i], sizeof(dup_check[0])) == 0)
1596		return; /* we've received a dup packet */
1597#define min(a,b) ((a) < (b) ? (a) : (b))
1598	memcpy(dup_check[ptr], packet, min(ntohs(packet->length),
1599						 sizeof(dup_check[0])));
1600	ptr = ++ptr % DUP_COUNT;
1601#endif /* BUGGY_AC */
1602
1603	encode_ppp(1, (unsigned char *)(packet+1), ntohs(packet->length));
1604    }
1605}
1606
1607void pppd_handler(void) {
1608  /* take packets from pppd and feed them to sess_sock */
1609  struct pppoe_packet *packet = NULL;
1610  time_t tm;
1611  sPktBuf pktBuf[BUFRING];
1612  int nPkt = 0;
1613  /* unsigned char buf[PACKETBUF]; */
1614  int len, pkt_size;
1615  int i, bufRemain = 0, bufPos;
1616  unsigned char *currBufStart;
1617
1618  /* fprintf(error_file, "pppd_handler %d\n", getpid()); */ /* foxconn wklin
1619                                                               removed,
1620                                                               07/27/2007 */
1621
1622  /* Clear data buffer */
1623  for (i=0; i<BUFRING; i++) {
1624    memset(pktBuf[i].packetBuf, 0x0, sizeof(pktBuf[i].packetBuf));
1625  }
1626
1627  while(1) {
1628    /* Read in data buffer, Maximum size is 4095 bytes for evey one read() */
1629    if ((len = read(0, &(pktBuf[nPkt].packetBuf[(20+bufRemain)]), (4095-bufRemain))) < 0) {
1630      perror("pppoe");
1631      fprintf(error_file, "pppd_handler: read packet error len < 0\n");
1632      exit(1);
1633    }
1634    if (len == 0) {
1635      /* foxconn wklin modified start, 07/27/2007 */
1636      /* fprintf(error_file, "pppd_handler: read packet len = 0 bytes\n"); */
1637      usleep(10000); /* sleep 10ms */
1638      /* foxconn wklin modified end, 07/27/2007 */
1639      continue;
1640    }
1641    /* Append the length of previous remained data */
1642    len += bufRemain;
1643
1644    if (opt_verbose == 1) {
1645        time(&tm);
1646        fprintf(log_file, "\n%sInput of %d bytes:\n", ctime(&tm), len);
1647        /*print_hex(buf, len);*/
1648        print_hex(pktBuf[nPkt].packetBuf, len);
1649        fputc('\n', log_file);
1650    }
1651
1652    bufPos = 0;
1653    packet = &(pktBuf[nPkt].packetBuf[0]);
1654    currBufStart = &(pktBuf[nPkt].packetBuf[20]);
1655    do {
1656        /* Segment and compose packet from buffer */
1657        if ((pkt_size = create_sess(packet, src_addr, dst_addr, currBufStart, len,
1658                                    session, &bufRemain)) == 0) {
1659          /* Copy incomplete content to next buffer */
1660          if (bufRemain > 0) {
1661            if ((nPkt+1) < BUFRING) {
1662                memcpy(&(pktBuf[nPkt+1].packetBuf[20]),
1663                       &(pktBuf[nPkt].packetBuf[(4115-bufRemain)]),         /* 4115 = 4095 + 20 */
1664                       bufRemain);
1665            }
1666            else {
1667                memcpy(&(pktBuf[0].packetBuf[20]),
1668                       &(pktBuf[(BUFRING-1)].packetBuf[(4115-bufRemain)]),  /* 4115 = 4095 + 20 */
1669                       bufRemain);
1670            }
1671          }
1672          break;
1673        }
1674
1675        len -= bufRemain;
1676
1677        /* Send the completely composed packet */
1678        if (send_packet(sess_sock, packet, pkt_size, if_name) < 0) {
1679          fprintf(error_file, "pppd_handler: unable to send PPPoE packet\n");
1680          exit(1);
1681        }
1682
1683        /* Check if all the contents of buffer were processed */
1684        if (bufRemain <= 0) {
1685            break;
1686        }
1687        else {
1688            /* Renew the positions of packet header and data buffer */
1689            bufPos += len;
1690            currBufStart = &(pktBuf[nPkt].packetBuf[bufPos+20]);
1691            packet = &(pktBuf[nPkt].packetBuf[bufPos]);
1692            len = bufRemain;
1693        }
1694    } while (bufRemain > 0);
1695
1696    /* Process next read buffer */
1697    nPkt++;
1698    if (nPkt >= BUFRING)
1699        nPkt = 0;
1700
1701  }
1702}
1703
1704
1705int main(int argc, char **argv)
1706{
1707    struct pppoe_packet *packet = NULL;
1708    int pkt_size;
1709    /* Foxconn added start Winster Chan 12/05/2005 */
1710    FILE *fp;
1711    char buf[64];
1712    /* Foxconn added end Winster Chan 12/05/2005 */
1713    int fd; /* wklin added, 07/26/2007 */
1714
1715    int opt;
1716    int ret_sock; /* foxconn wklin added, 12/27/2007 */
1717    time_t tm; /* foxconn wklin added, 12/27/2007 */
1718
1719    /* initialize error_file here to avoid glibc2.1 issues */
1720     error_file = stderr;
1721
1722    /* foxconn wklin added start, 07/26/2007 */
1723    fd = open("/dev/console", O_WRONLY);
1724    if (fd != -1)
1725        dup2(fd, 2);
1726    /* foxconn wklin added end, 07/26/2007 */
1727
1728    /* parse options */
1729    /* foxconn wklin modified, 03/27/2007, add service name option S */
1730    while ((opt = getopt(argc, argv, "I:L:VE:F:S:")) != -1)
1731	switch(opt)
1732	{
1733	case 'F': /* sets invalid forwarding */
1734	    if (*optarg == 'a') /* always forward */
1735		opt_fwd = 1;
1736	    else if (*optarg == 's') /* search for flag */
1737		opt_fwd_search = 1;
1738	    else
1739		fprintf(stderr, "Invalid forward option %c\n", *optarg);
1740	    break;
1741
1742	case 'I': /* sets interface */
1743	    if (if_name != NULL)
1744		free(if_name);
1745        /* foxconn wklin modified, 03/27/2007 */
1746	    if ((if_name=malloc(strlen(optarg)+1)) == NULL)
1747	    {
1748		fprintf(stderr, "malloc\n");
1749		exit(1);
1750	    }
1751	    strcpy(if_name, optarg);
1752            /* wklin added start, 01/15/2007 */
1753            if (log_file != NULL)
1754                fclose(log_file);
1755            if ((log_file=fopen("/dev/null", "w")) == NULL) {
1756                fprintf(stderr, "fopen\n");
1757                exit(1);
1758            }
1759            /* wklin added end, 01/15/2007 */
1760	    break;
1761
1762	case 'L': /* log file */
1763	    opt_verbose = 1;
1764	    if (log_file != NULL)
1765		fclose(log_file);
1766	    if ((log_file=fopen(optarg, "w")) == NULL)
1767	    {
1768		fprintf(stderr, "fopen\n");
1769		exit(1);
1770	    }
1771	    if (setvbuf(log_file, NULL, _IONBF, 0) != 0)
1772	    {
1773		fprintf(stderr, "setvbuf\n");
1774		exit(1);
1775	    }
1776	    break;
1777	case 'V': /* version */
1778	    printf("pppoe version %d.%d\n", VERSION_MAJOR, VERSION_MINOR);
1779	    exit(0);
1780	    break;
1781	case 'E': /* error file */
1782	    if ((error_file = fopen(optarg, "w")) == NULL)
1783	    {
1784		fprintf(stderr, "fopen\n");
1785		exit(1);
1786	    }
1787	    if (setvbuf(error_file, NULL, _IONBF, 0) != 0)
1788	    {
1789		fprintf(stderr, "setvbuf\n");
1790		exit(1);
1791	    }
1792	    break;
1793        /* foxconn wklin added start, 03/27/2007, service name */
1794	case 'S': /* set service name*/
1795	    if (service_name != NULL)
1796		    free(service_name);
1797	    if ((service_name=malloc(strlen(optarg)+1)) == NULL) {
1798		    fprintf(stderr, "malloc\n");
1799		    exit(1);
1800	    }
1801	    strcpy(service_name, optarg);
1802	    break;
1803        /* foxconn wklin added end, 03/27/2007 */
1804	default:
1805	    fprintf(stderr, "Unknown option %c\n", optopt);
1806	    exit(1);
1807	}
1808
1809    /* Foxconn added start, Winster Chan, 06/26/2006 */
1810    /* Foxconn removed start pling 01/17/2007, not necessary */
1811#if 0
1812    char poeIfName[32];
1813    if (!(fp = fopen(PPP_PPPOE_IFNAME, "r"))) {
1814        perror(PPP_PPPOE_IFNAME);
1815    }
1816    else {
1817        if(fgets(buf, sizeof(buf), fp)) {
1818            sscanf(buf, "%s", poeIfName);
1819        }
1820    }
1821
1822    if (if_name == 0)
1823    {
1824        /* if_name = "eth0"; */
1825        if ((if_name=malloc(strlen(poeIfName+1))) == NULL) {
1826            fprintf(stderr, "malloc\n");
1827            exit(1);
1828        }
1829        strcpy(if_name, poeIfName);
1830    }
1831#endif
1832    /* Foxconn removed end pling 01/17/2007, not necessary */
1833    /* Foxconn added end, Winster Chan, 06/26/2006 */
1834    /* allocate packet once */
1835    packet = malloc(PACKETBUF);
1836    assert(packet != NULL);
1837
1838    /* create the raw socket we need */
1839
1840    signal(SIGINT, sigint);
1841    signal(SIGTERM, sigint);
1842#ifdef NEW_WANDETECT
1843    signal(SIGUSR1, sigint2);/*Foxconn added James 11/11/2008 @new_internet_detection*/
1844#endif
1845
1846    /* Foxconn added start, Winster Chan, 06/26/2006 */
1847    pptp_pppox_open(&poxfd, &pppfd);
1848    /* Foxconn added end, Winster Chan, 06/26/2006 */
1849
1850    if ((disc_sock = open_interface(if_name,ETH_P_PPPOE_DISC,src_addr)) < 0)
1851    {
1852	fprintf(error_file, "pppoe: unable to create raw socket\n");
1853	return 1;
1854    }
1855
1856    /* initiate connection */
1857
1858    /* Foxconn added start Winster Chan 12/05/2005 */
1859    if (!(fp = fopen(PPP_PPPOE_SESSION, "r"))) {
1860        ; /* perror(PPP_PPPOE_SESSION);*/ /*foxconn wklin removed, 08/13/2007 */
1861    }
1862    else {
1863        unsigned int nMacAddr[ETH_ALEN];
1864        int nSessId, i;
1865        char cMacAddr[ETH_ALEN];
1866        unsigned short usSessId;
1867
1868        /* Init variables */
1869        for (i=0; i<ETH_ALEN; i++) {
1870            nMacAddr[i] = 0;
1871            cMacAddr[i] = 0x0;
1872        }
1873        nSessId = 0;
1874
1875        /* Get the PPPoE server MAC address and Session ID from file */
1876        if(fgets(buf, sizeof(buf), fp)) {
1877            sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x %d",
1878                &nMacAddr[0], &nMacAddr[1], &nMacAddr[2],
1879                &nMacAddr[3], &nMacAddr[4], &nMacAddr[5],
1880                &nSessId);
1881
1882            /* Transfer types of data */
1883            for (i=0; i<ETH_ALEN; i++) {
1884                cMacAddr[i] = (char)nMacAddr[i];
1885            }
1886            usSessId = (unsigned short)nSessId;
1887
1888            /* Check if the previous MAC address and Session ID exist. */
1889            if (!((cMacAddr[0]==0x0) && (cMacAddr[1]==0x0) && (cMacAddr[2]==0x0) &&
1890                 (cMacAddr[3]==0x0) && (cMacAddr[4]==0x0) && (cMacAddr[5]==0x0)) &&
1891                (htons(usSessId) != 0x0)) {
1892
1893                /* send PADT to server to clear the previous connection */
1894                if ((pkt_size = create_padt(packet, src_addr, cMacAddr,
1895                                    (unsigned short)htons(usSessId))) == 0) {
1896          	        fprintf(stderr, "pppoe: unable to create PADT packet\n");
1897                    fclose(fp);
1898                    /*exit(1);*/
1899                    cleanup_and_exit(1); /* foxconn modified by EricHuang, 05/24/2007 */
1900                }
1901                if (send_packet(disc_sock, packet, pkt_size+14, if_name) < 0) {
1902                    fprintf(stderr, "pppoe: unable to send PADT packet\n");
1903                    fclose(fp);
1904                    /*exit(1);*/
1905                    cleanup_and_exit(1); /* foxconn modified by EricHuang, 05/24/2007 */
1906                } else {
1907                    fprintf(stderr, "PPPOE: PADT sent\n"); /* foxconn wklin added, 07/26/2007 */
1908                }
1909
1910                /* Foxconn modified start, Winster Chan, 06/26/2006 */
1911                /*pptp_pppox_release(&poxfd, &pppfd);*/ /* foxconn removed by EricHuang, 05/24/2007 */
1912                /* Foxconn modified end, Winster Chan, 06/26/2006 */
1913
1914                /* Waiting 3 seconds for server finishing the termination */
1915                sleep(3);
1916            }
1917        }
1918        fclose(fp);
1919    }
1920    /* Foxconn added end Winster Chan 12/05/2005 */
1921
1922    /* start the PPPoE session */
1923    /* foxconn wklin modified, 03/27/2007, add service name */
1924    if ((pkt_size = create_padi(packet, src_addr, service_name)) == 0) {
1925	fprintf(stderr, "pppoe: unable to create PADI packet\n");
1926	exit(1);
1927    }
1928    /* send the PADI packet */
1929    if (send_packet(disc_sock, packet, pkt_size, if_name) < 0) {
1930	fprintf(stderr, "pppoe: unable to send PADI packet\n");
1931	exit(1);
1932    }
1933
1934    time(&tm); /* foxconn wklin added, 12/27/2007, for storing PADI time */
1935    /* wait for PADO */
1936    while ((ret_sock = read_packet(disc_sock, packet, &pkt_size)) != disc_sock ||
1937	   (packet->code != CODE_PADO )) { /* foxconn wklin modified, 12/27/2007 */
1938	fprintf(log_file, "pppoe: unexpected packet %x\n",
1939		packet->code);
1940	/* foxconn wklin added start, 12/27/2007 */
1941	if (ret_sock == disc_sock &&
1942		(packet->code == CODE_PADI || packet->code == CODE_PADR)) {
1943	    if (time(NULL) - tm < 3)
1944	       continue;
1945	}
1946	/* foxconn wklin added end, 12/27/2007 */
1947	/* wklin added start, 01/10/2007 */
1948    	/* fprintf(stderr, "pppoe: resend PADI\n"); */
1949    	/* start the PPPoE session */
1950        /* foxconn wklin modified, 03/27/2007, add service name */
1951    	if ((pkt_size = create_padi(packet, src_addr, service_name)) == 0) {
1952		fprintf(stderr, "pppoe: unable to create PADI packet\n");
1953		exit(1);
1954    	}
1955    	/* send the PADI packet */
1956    	if (send_packet(disc_sock, packet, pkt_size, if_name) < 0) {
1957		fprintf(stderr, "pppoe: unable to send PADI packet\n");
1958		exit(1);
1959    	}
1960	time(&tm); /* foxconn added, 12/27/2007, for storing PADI time */
1961	/* wklin added end, 01/10/2007 */
1962	continue;
1963    }
1964
1965    /* Foxconn added start pling 12/20/2006 */
1966    /* Touch a file on /tmp to indicate PADO is received */
1967    if (1)
1968    {
1969        FILE *fp;
1970        struct sysinfo info;
1971        /* foxconn wklin modified start, 07/26/2007 */
1972        /* system("echo \"DEBUG: PADO received\" > /dev/console"); */
1973        fprintf(stderr, "PPPOE: PADO received\n");
1974        /* foxconn wklin modified end, 07/26/2007 */
1975        if ((fp = fopen("/tmp/PADO", "w")) != NULL) {
1976            sysinfo(&info);  /* save current time in file */
1977            fprintf(fp, "%ld", info.uptime);
1978            fclose(fp);
1979        }
1980    }
1981    /* Foxconn added end ling 12/20/2006 */
1982
1983
1984#ifdef __linux__
1985    memcpy(dst_addr, packet->ethhdr.h_source, sizeof(dst_addr));
1986#else
1987    memcpy(dst_addr, packet->ethhdr.ether_shost, sizeof(dst_addr));
1988#endif
1989    /* Foxconn added start Winster Chan 11/25/2005 */
1990    /* Stored tags of PADO */
1991    memset(pado_tags, 0x0, sizeof(pado_tags));
1992    if ((htons(packet->length) < 0) || (htons(packet->length) > sizeof(pado_tags))) {
1993        pado_tag_size = sizeof(pado_tags);
1994    }
1995    else {
1996        pado_tag_size = (int)(htons(packet->length));
1997    }
1998    memcpy((char *)pado_tags, (char *)(packet + 1), pado_tag_size);
1999    /* Foxconn added end Winster Chan 11/25/2005 */
2000
2001    /* send PADR */
2002    /* foxconn wklin modified, 03/27/2007, add service name */
2003    if ((pkt_size = create_padr(packet, src_addr, dst_addr, service_name)) == 0) {
2004	fprintf(stderr, "pppoe: unable to create PADR packet\n");
2005	exit(1);
2006    }
2007    if (send_packet(disc_sock, packet, pkt_size+14, if_name) < 0) {
2008	fprintf(stderr, "pppoe: unable to send PADR packet\n");
2009	exit(1);
2010    }
2011
2012    /* wait for PADS */
2013#ifdef __linux__
2014    while (read_packet(disc_sock, packet, &pkt_size) != disc_sock ||
2015	   (memcmp(packet->ethhdr.h_source, dst_addr, sizeof(dst_addr)) != 0) ||
2016       (packet->code != CODE_PADS && packet->code != CODE_PADT)) /* foxconn wklin modified, 08/09/2007 */
2017#else
2018    while (read_packet(disc_sock, packet, &pkt_size) != disc_sock ||
2019	   (memcmp(packet->ethhdr.ether_shost,
2020		   dst_addr, sizeof(dst_addr)) != 0))
2021#endif
2022    {
2023        static int retried=0; /* wklin added, 01/26/2007 */
2024        /* foxconn wklin removed start, 08/09/2007 */
2025	    /* if (packet->code != CODE_PADS && packet->code != CODE_PADT)
2026	    fprintf(log_file, "pppoe: unexpected packet %x\n", packet->code);
2027        */
2028        /* foxconn wklin removed end, 08/09/2007 */
2029
2030	    /* wklin modified start, 01/26/2007 */
2031    	/* send PADR */
2032        /* foxconn wklin modified, 03/27/2007, add service name */
2033        if ((pkt_size = create_padr(packet, src_addr, dst_addr, service_name)) == 0) {
2034	    fprintf(stderr, "pppoe: unable to create PADR packet\n");
2035            exit(1);
2036        }
2037        if (send_packet(disc_sock, packet, pkt_size+14, if_name) < 0) {
2038	    fprintf(stderr, "pppoe: unable to send PADR packet\n");
2039            exit(1);
2040        }
2041        if (retried++ == 5) {
2042            retried = 0;
2043            packet->code = CODE_PADT;
2044            break;
2045        }
2046        /* wklin modified end, 01/26/2007 */
2047        continue;
2048    }
2049
2050    /* foxconn James added start, 11/12/2008 @new_internet_detection */
2051#ifdef NEW_WANDETECT
2052    if (packet->code == CODE_PADS)
2053    {
2054        FILE *fp;
2055        struct sysinfo info;
2056
2057        time(&tm);
2058        fprintf(stderr, "PPPOE: PADS received %s\n", ctime(&tm));
2059        if ((fp = fopen("/tmp/PADS", "w")) != NULL) {
2060            sysinfo(&info);  /* save current time in file */
2061            fprintf(fp, "%ld", info.uptime);
2062            fclose(fp);
2063        }
2064    }
2065#endif
2066    /* foxconn James added end, 11/12/2008 @new_internet_detection */
2067
2068
2069    if (packet->code == CODE_PADT) /* early termination */
2070    {
2071	    cleanup_and_exit(0);
2072    }
2073
2074    session = packet->session;
2075
2076    /* foxconn wklin added start, 07/31/2007 */
2077    if (session == 0) { /* PADS generic error */
2078        sleep(3); /* wait for 3 seconds and exit, retry */
2079	    cleanup_and_exit(0);
2080    }
2081
2082    /* fprintf(stderr, "PPPOE: session id = 0x%08x\n", session); */
2083    /* foxconn wklin added end, 07/31/2007 */
2084
2085    if ((sess_sock = open_interface(if_name,ETH_P_PPPOE_SESS,NULL)) < 0) {
2086    	fprintf(log_file, "pppoe: unable to create raw socket\n");
2087    	cleanup_and_exit(1);
2088    }
2089
2090    /* Foxconn added start, Winster Chan, 06/26/2006 */
2091    memcpy(dstMac, dst_addr, ETH_ALEN);
2092    sessId = packet->session;
2093
2094    /* Connect pptp kernel module */
2095    /* foxconn wklin modified start, 07/31/2007 */
2096    if ( 0 > pptp_pppox_connect(&poxfd, &pppfd))
2097        cleanup_and_exit(1);
2098    /* foxconn wklin modified end, 07/31/2007 */
2099    /* Foxconn added end, Winster Chan, 06/26/2006 */
2100
2101    /* Foxconn added start Winster Chan 12/05/2005 */
2102    if (!(fp = fopen(PPP_PPPOE_SESSION, "w"))) {
2103        perror(PPP_PPPOE_SESSION);
2104    }
2105    else {
2106        /* Save the PPPoE server MAC address and Session ID */
2107        fprintf(fp, "%02x:%02x:%02x:%02x:%02x:%02x %d\n",
2108            (unsigned char)(dst_addr[0]), (unsigned char)(dst_addr[1]),
2109            (unsigned char)(dst_addr[2]), (unsigned char)(dst_addr[3]),
2110            (unsigned char)(dst_addr[4]), (unsigned char)(dst_addr[5]),
2111            (int)htons(session));
2112        fclose(fp);
2113    }
2114    /* Foxconn added end Winster Chan 12/05/2005 */
2115
2116    clean_child = 0;
2117    signal(SIGCHLD, sigchild);
2118
2119    /* all sockets are open fork off handlers */
2120    if ((sess_listen = fork()) == 0)
2121    {
2122	    sess_handler(); /* child */
2123    }
2124    if (sess_listen < 0) {
2125    	perror("pppoe: fork");
2126    	cleanup_and_exit(1);
2127    }
2128    if ((pppd_listen = fork()) == 0)
2129    {
2130	    pppd_handler(); /* child */
2131    }
2132    if (pppd_listen < 0) {
2133    	perror("pppoe: fork");
2134    	cleanup_and_exit(1);
2135    }
2136
2137    /* wait for all children to die */
2138    /* this is not perfect - race conditions on dying children are still
2139       possible */
2140    while(1) {
2141	if (waitpid((pid_t)-1,NULL,WNOHANG) < 0 && errno == ECHILD)
2142	    break; /* all children dead */
2143	if (read_packet(disc_sock, packet, &pkt_size) == disc_sock) {
2144        /* foxconn wklin modified, 03/23/2007, check PADT session ID */
2145        /* foxconn wklin added start, 07/26/2007 */
2146        if (packet->code == CODE_PADT)
2147            fprintf(stderr, "PPPOE: PADT received (%08x/%08x)\n",
2148                    packet->session, session);
2149        /* foxconn wklin added end, 07/26/2007 */
2150	    if (packet->code == CODE_PADT && packet->session == session)
2151	    {
2152		    cleanup_and_exit(1);
2153	    }
2154	}
2155	/* clean up any dead children */
2156	while (waitpid((pid_t)-1,NULL,WNOHANG) > 0)
2157	    ;
2158
2159    }
2160    /* Foxconn added start, Winster Chan, 06/26/2006 */
2161    close(pppfd); pppfd = -1;
2162    close(poxfd); poxfd = -1;
2163    /* Foxconn added end, Winster Chan, 06/26/2006 */
2164
2165    return 0;
2166}
2167