1/* pptp_gre.c  -- encapsulate PPP in PPTP-GRE.
2 *                Handle the IP Protocol 47 portion of PPTP.
3 *                C. Scott Ananian <cananian@alumni.princeton.edu>
4 *
5 * $Id: pptp_gre.c,v 1.39 2005/07/11 03:23:48 quozl Exp $
6 */
7
8#include <sys/types.h>
9#include <netinet/in.h>
10#include <arpa/inet.h>
11#include <sys/socket.h>
12#include <sys/stat.h>
13#include <sys/time.h>
14#include <unistd.h>
15#include <string.h>
16#include <errno.h>
17#include <fcntl.h>
18#include "ppp_fcs.h"
19#include "pptp_msg.h"
20#include "pptp_gre.h"
21#include "util.h"
22#include "pqueue.h"
23/* Foxconn added start, Winster Chan, 06/26/2006 */
24#include "pptpox.h"
25#include <stdio.h>
26#include <linux/types.h>
27#include <linux/ppp_defs.h>
28#include <linux/if_ppp.h>
29#include <fcntl.h>
30#include <sys/file.h>
31#include <sys/ioctl.h>
32/* Foxconn added end, Winster Chan, 06/26/2006 */
33
34#define PACKET_MAX 8196
35/* test for a 32 bit counter overflow */
36#define WRAPPED( curseq, lastseq) \
37    ((((curseq) & 0xffffff00) == 0) && \
38     (((lastseq) & 0xffffff00 ) == 0xffffff00))
39
40static u_int32_t ack_sent, ack_recv;
41static u_int32_t seq_sent, seq_recv;
42static u_int16_t pptp_gre_call_id, pptp_gre_peer_call_id;
43gre_stats_t stats;
44
45/* Foxconn added start, Winster Chan, 06/26/2006 */
46static int pox_fd = -1;
47/* Foxconn added start, Winster Chan, 06/26/2006 */
48
49typedef int (*callback_t)(int cl, void *pack, unsigned int len);
50
51/* decaps_hdlc gets all the packets possible with ONE blocking read */
52/* returns <0 if read() call fails */
53int decaps_hdlc(int fd, callback_t callback, int cl);
54int encaps_hdlc(int fd, void *pack, unsigned int len);
55int decaps_gre (int fd, callback_t callback, int cl);
56int encaps_gre (int fd, void *pack, unsigned int len);
57int dequeue_gre(callback_t callback, int cl);
58
59#ifdef CODE_IN_USE  //Winster Chan added 05/16/2006
60#include <stdio.h>
61void print_packet(int fd, void *pack, unsigned int len)
62{
63    unsigned char *b = (unsigned char *)pack;
64    unsigned int i,j;
65    FILE *out = fdopen(fd, "w");
66    fprintf(out,"-- begin packet (%u) --\n", len);
67    for (i = 0; i < len; i += 16) {
68        for (j = 0; j < 8; j++)
69            if (i + 2 * j + 1 < len)
70                fprintf(out, "%02x%02x ",
71                        (unsigned int) b[i + 2 * j],
72                        (unsigned int) b[i + 2 * j + 1]);
73            else if (i + 2 * j < len)
74                fprintf(out, "%02x ", (unsigned int) b[i + 2 * j]);
75        fprintf(out, "\n");
76    }
77    fprintf(out, "-- end packet --\n");
78    fflush(out);
79}
80#endif  //CODE_IN_USE Winster Chan added 05/16/2006
81
82/*** time_now_usecs ***********************************************************/
83uint64_t time_now_usecs()
84{
85    struct timeval tv;
86    gettimeofday(&tv, NULL);
87    return (tv.tv_sec * 1000000) + tv.tv_usec;
88}
89
90/* Foxconn added start, Winster Chan, 06/26/2006 */
91/**************************************************************************
92** Function:    addr_itox()
93** Description: Convert the <int> address value getting from file to
94**                  <unsigned char> address type.
95** Parameters:  (unsigned char *) daddr -- destination address value
96**              (int *) saddr -- source address value
97**              (int) convlen -- convert length
98** Return:      none.
99**************************************************************************/
100static void addr_itox(unsigned char *daddr, int *saddr, int convlen)
101{
102    int i;
103
104    for (i = 0; i < convlen; i++)
105        daddr[i] = (unsigned char)saddr[i];
106}
107
108/**************************************************************************
109** Function:    pptp_pppox_open()
110** Description: Open socket to kernel pppox driver, and open ppp device
111** Parameters:  (int *) poxfd -- pointer of file descriptor for pppox
112**              (int *) pppfd -- pointer of file descriptor for ppp device
113** Return:      none.
114**************************************************************************/
115void pptp_pppox_open(int *poxfd, int *pppfd)
116{
117    /* Open socket to pppox kernel module */
118    *poxfd = socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_TP);
119    if (*poxfd >= 0) {
120        /*
121         * Save the file descriptor for getting the GRE sequence number
122         * from kernel side.
123         */
124        pox_fd = *poxfd;
125        /* Open ppp device */
126        *pppfd = open("/dev/ppp", O_RDWR);
127    }
128    else {
129        *poxfd = -1;
130        *pppfd = -1;
131    }
132}
133
134/**************************************************************************
135** Function:    pptp_pppox_get_info()
136** Description: Get the essential information for connecting pptp kernel
137**                  module. Such as Source IP, Destination IP, Remote MAC
138**                  address, Device name, call_id, and peer_call_id, etc.
139** Parameters:  none.
140** Return:      (struct sockaddr_pptpox)sp_info -- structure of information.
141**************************************************************************/
142struct sockaddr_pptpox pptp_pppox_get_info(void)
143{
144    struct sockaddr_pptpox sp_info;
145    FILE *fp = NULL;
146    int nulluserip = 0;
147    unsigned char buf[128];
148    unsigned char userIp[IPV4_LEN], servIp[IPV4_LEN], arpIp[IPV4_LEN];
149    unsigned char userNetMask[IPV4_LEN];    /* pling added 03/22/2012 */
150    unsigned char dhcpIp[IPV4_LEN], gateWay[IPV4_LEN], netMask[IPV4_LEN];
151    //unsigned char addrname[12];
152    unsigned char addrname[32];
153    unsigned int getIp[IPV4_LEN];
154    int call_id = 0, peer_call_id = 0;
155    unsigned char wan_ifname[IFNAMSIZ]; /* Foxconn, added by EricHuang, 03/20/2007 */
156    unsigned char pptp_gw[IPV4_LEN]; /* for static IP case, Foxconn added by EricHuang, 04/03/2007 */
157
158    memset(&sp_info, 0, sizeof(struct sockaddr_pptpox));
159
160    sp_info.sa_family = AF_PPPOX;
161    sp_info.sa_protocol = PX_PROTO_TP;
162
163    memset(userIp, 0, IPV4_LEN);
164    memset(servIp, 0, IPV4_LEN);
165    memset(arpIp, 0, IPV4_LEN);
166    memset(dhcpIp, 0, IPV4_LEN);
167    memset(gateWay, 0, IPV4_LEN);
168    memset(netMask, 0, IPV4_LEN);
169
170    /* Get user IP and server IP from /tmp/ppp/pptpIp file */
171    if ((fp = fopen("/tmp/ppp/pptpIp", "r")) != NULL) {
172        char user_nvram[] = "pptp_user_ip";
173        char gw_nvram[] = "pptp_gateway_ip"; /* Foxconn added by EricHuang, 04/03/2007 */
174        char user_netmask[] = "pptp_user_netmask"; /* Foxconn added by EricHuang, 04/03/2007 */
175
176        /* Get WAN interface name */
177        fgets(buf, sizeof(buf), fp);
178        sscanf(buf, "%s", &wan_ifname[0]);
179        memcpy(sp_info.sa_addr.pptp.dev, wan_ifname, IFNAMSIZ);
180
181        while (fgets(buf, sizeof(buf), fp)) {
182            sscanf(buf, "%s %d.%d.%d.%d",
183                &addrname[0], &getIp[0], &getIp[1], &getIp[2], &getIp[3]);
184            /* Get user IP */
185            if (memcmp(addrname, user_nvram, sizeof(user_nvram)) == 0) {
186                /* User IP is not NULL. It's tatic IP */
187                addr_itox(userIp, getIp, IPV4_LEN);
188                if ((userIp[0] == 0x0) && (userIp[1] == 0x0) &&
189                    (userIp[2] == 0x0) && (userIp[3] == 0x0)) {
190                    nulluserip = 1;
191                }
192                else {
193                    memcpy(&sp_info.sa_addr.pptp.srcaddr, userIp, IPV4_LEN);
194                    nulluserip = 0;
195                }
196            }
197            /* Foxconn added start by EricHuang, 04/03/2007 */
198            else if (memcmp(addrname, gw_nvram, sizeof(gw_nvram)) == 0) {
199                addr_itox(pptp_gw, getIp, IPV4_LEN);
200                //memcpy(&sp_info.sa_addr.pptp.srcaddr, pptp_gw, IPV4_LEN);
201            }
202            /* Foxconn added end by EricHuang, 04/03/2007 */
203            /* Foxconn added start pling 03/22/2012 */
204            /* Read the user's static netmask settings */
205            else if (memcmp(addrname, user_netmask, sizeof(user_netmask)) == 0) {
206                addr_itox(userNetMask, getIp, IPV4_LEN);
207            }
208            /* Foxconn added end pling 03/22/2012 */
209
210        } /* End while() */
211        fclose(fp);
212        //unlink("/tmp/ppp/pptpIp");
213    } /* End if(fp) */
214
215    /* Foxconn added start by EricHuang, 03/20/2007 */
216    /* get pptp server ip after gethostbyname, it called in pptp.c */
217    if ((fp = fopen("/tmp/ppp/pptpSrvIp", "r")) != NULL) {
218        memcpy(sp_info.sa_addr.pptp.dev, wan_ifname, IFNAMSIZ);
219
220        while (fgets(buf, sizeof(buf), fp)) {
221            sscanf(buf, "%d.%d.%d.%d",
222                &getIp[0], &getIp[1], &getIp[2], &getIp[3]);
223
224                addr_itox(servIp, getIp, IPV4_LEN);
225                memcpy(&sp_info.sa_addr.pptp.dstaddr, servIp, IPV4_LEN);
226        }
227        fclose(fp);
228    }
229    /* Foxconn added end by EricHuang, 03/20/2007 */
230
231
232    if (nulluserip) {
233        /* NULL user IP, get user IP by dhcp client */
234        char dhcp_ip[] = "user_ip_addr";
235        char gate_way[] = "gateway_addr";
236        char net_mask[] = "netmask_addr";
237
238        if ((fp = fopen("/tmp/ppp/dhcpIp", "r")) != NULL) {
239            /* Get IP by dhcp client */
240            while (fgets(buf, sizeof(buf), fp)) {
241                sscanf(buf, "%s %d.%d.%d.%d", &addrname[0],
242                    &getIp[0], &getIp[1], &getIp[2], &getIp[3]);
243                if (memcmp(addrname, dhcp_ip, sizeof(dhcp_ip)) == 0) {
244                    /* Save dhcp user IP address */
245                    addr_itox(dhcpIp, getIp, IPV4_LEN);
246                    memcpy(&sp_info.sa_addr.pptp.srcaddr, dhcpIp, IPV4_LEN);
247                }
248                else if (memcmp(addrname, gate_way, sizeof(gate_way)) == 0) {
249                    /* Save gateway address */
250                    addr_itox(gateWay, getIp, IPV4_LEN);
251                }
252                else if (memcmp(addrname, net_mask, sizeof(net_mask)) == 0) {
253                    /* Save net mask address */
254                    addr_itox(netMask, getIp, IPV4_LEN);
255                }
256            } /* End while() */
257            fclose(fp);
258            //unlink("/tmp/ppp/dhcpIp");
259        } /* End if(fp) */
260    }
261
262    /* Get MAC address and interface name from /proc/net/arp file */
263    if ((fp = fopen("/proc/net/arp", "r")) != NULL) {
264        int nMac[ETH_ALEN];
265        unsigned char cMac[ETH_ALEN], ifname[IFNAMSIZ];
266        unsigned char tmpChr[16];
267        unsigned char cmpIp[IPV4_LEN];
268
269        memset(nMac, 0, ETH_ALEN);
270        memset(cMac, 0, ETH_ALEN);
271
272        if (nulluserip) {
273            /* Case: get IP by dhcp client */
274            if (((dhcpIp[0] & netMask[0]) == (servIp[0] & netMask[0])) &&
275                ((dhcpIp[1] & netMask[1]) == (servIp[1] & netMask[1])) &&
276                ((dhcpIp[2] & netMask[2]) == (servIp[2] & netMask[2])) &&
277                ((dhcpIp[3] & netMask[3]) == (servIp[3] & netMask[3]))) {
278                /*
279                 * dhcp IP & server IP are in same subnet,
280                 * match the arp table with server IP.
281                 */
282                memcpy(cmpIp, servIp, IPV4_LEN);
283            }
284            else {
285                /*
286                 * dhcp IP & server IP are in different subnet,
287                 * match the arp table with gateway IP.
288                 */
289                memcpy(cmpIp, gateWay, IPV4_LEN);
290            }
291        }
292        else {
293            /* Case: static IP */
294            /* TODO: not consider gateway case currently! */
295
296            /* foxconn modified start by EricHuang, 04/03/2007 */
297            /* pptp_gw will be solved in /rc/pptp.c, and if user don't enter the
298               gateway address in the gui, we use pptp server ip as gateway ip.
299            */
300            //memcpy(cmpIp, servIp, IPV4_LEN);
301            //memcpy(cmpIp, pptp_gw, IPV4_LEN); /* pling removed 03/22/2012 */
302            /* foxconn modified end by EricHuang, 04/03/2007 */
303
304            /* Foxconn added start pling 03/22/2012 */
305            /* Set the gateway properly according to subnet */
306            if (((userIp[0] & userNetMask[0]) == (servIp[0] & userNetMask[0])) &&
307                ((userIp[1] & userNetMask[1]) == (servIp[1] & userNetMask[1])) &&
308                ((userIp[2] & userNetMask[2]) == (servIp[2] & userNetMask[2])) &&
309                ((userIp[3] & userNetMask[3]) == (servIp[3] & userNetMask[3]))) {
310                /*
311                 * dhcp IP & server IP are in same subnet,
312                 * match the arp table with server IP.
313                 */
314                memcpy(cmpIp, servIp, IPV4_LEN);
315            }
316            else {
317                /*
318                 * dhcp IP & server IP are in different subnet,
319                 * match the arp table with gateway IP.
320                 */
321                memcpy(cmpIp, pptp_gw, IPV4_LEN);
322            }
323            /* Foxconn added end pling 03/22/2012 */
324        }
325
326        /* Skip the title name line */
327        fgets(buf, sizeof(buf), fp);
328        while (fgets(buf, sizeof(buf), fp)) {
329            sscanf(buf, "%d.%d.%d.%d %s %s %02x:%02x:%02x:%02x:%02x:%02x %s %s",
330                &getIp[0], &getIp[1], &getIp[2], &getIp[3],
331                &tmpChr[0], &tmpChr[0],
332                &nMac[0], &nMac[1], &nMac[2], &nMac[3], &nMac[4], &nMac[5],
333                &tmpChr[0], &ifname[0]);
334            addr_itox(arpIp, getIp, IPV4_LEN);
335            /* Destination entry was found in the arp table */
336            if (memcmp(cmpIp, arpIp, IPV4_LEN) == 0) {
337                addr_itox(sp_info.sa_addr.pptp.remote, nMac, ETH_ALEN);
338                break; /* Break off the while loop */
339            }
340        } /* End while() */
341        fclose(fp);
342    } /* End if(fp) */
343
344    /* Get PPTP call_id & peer_call_id */
345    if ((fp = fopen("/tmp/ppp/callIds", "r")) != NULL) {
346        while (fgets(buf, sizeof(buf), fp)) {
347            sscanf(buf, "%d %d", &call_id, &peer_call_id);
348
349            sp_info.sa_addr.pptp.cid = call_id;
350            sp_info.sa_addr.pptp.pcid = peer_call_id;
351        }
352        fclose(fp);
353    } /* End if(fp) */
354
355    return (struct sockaddr_pptpox)sp_info;
356}
357
358/**************************************************************************
359** Function:    pptp_pppox_connect()
360** Description: Actually connect to pppox kernel module with the structure
361**                  got by pptp_pppox_get_info().
362** Parameters:  (int *) poxfd -- pointer of file descriptor for pppox
363**              (int *) pppfd -- pointer of file descriptor for ppp device
364**              (u_int16_t) call_id -- local host call id
365**              (u_int16_t) peer_call_id -- peer server call id
366** Return:      (int)err -- Fail = -1
367**                          Success = 0.
368**************************************************************************/
369void pptp_pppox_connect(int *poxfd, int *pppfd,
370        u_int16_t call_id, u_int16_t peer_call_id)
371{
372    struct sockaddr_pptpox lsp;
373    int err = -1;
374    int chindex;
375	int flags;
376
377    memset(&lsp, 0, sizeof(struct sockaddr_pptpox));
378    lsp = pptp_pppox_get_info();
379
380    if (*poxfd >= 0) {
381        /* Connect pptp kernel connection */
382        err = connect(*poxfd, (struct sockaddr*)&lsp,
383            sizeof(struct sockaddr_pptpox));
384        if (err == 0) {
385            /* Get PPP channel */
386            if (ioctl(*poxfd, PPPIOCGCHAN, &chindex) == -1)
387                warn("Couldn't get channel number");
388
389            if (*pppfd >= 0) {
390                /* Attach to PPP channel */
391                if ((err = ioctl(*pppfd, PPPIOCATTCHAN, &chindex)) < 0)
392                    warn("Couldn't attach to channel");
393                flags = fcntl(*pppfd, F_GETFL);
394                if (flags == -1 || fcntl(*pppfd, F_SETFL, flags | O_NONBLOCK) == -1)
395                    warn("Couldn't set /dev/ppp (channel) to nonblock");
396            }
397            else
398                warn("Couldn't reopen /dev/ppp");
399        }
400        else
401            warn("Couldn't connect pppox, err: %d, %s", err, strerror(errno));
402    }
403}
404
405/**************************************************************************
406** Function:    pptp_pppox_release()
407** Description: Release the connection between user program and pppox kernel
408**                  driver with ioctl() and connect(), and clear the
409**                  essential information in kernel.
410** Parameters:  (int *) poxfd -- pointer of file descriptor for pppox
411**              (int *) pppfd -- pointer of file descriptor for ppp device
412** Return:      (int)err -- Fail = -1
413**                          Success = 0.
414**************************************************************************/
415void pptp_pppox_release(int *poxfd, int *pppfd)
416{
417    struct sockaddr_pptpox lsp;
418    int err = -1;
419
420    if (*poxfd >= 0) {
421        memset(&lsp, 0, sizeof(struct sockaddr_pptpox));
422        lsp = pptp_pppox_get_info();
423        if (*pppfd >= 0) {
424            /* Detach from PPP */
425    	    if (ioctl(*pppfd, PPPIOCDETACH) < 0)
426                warn("pptp_pppox_release ioctl(PPPIOCDETACH) failed");
427	    }
428
429        /* Release pptp kernel connection */
430        lsp.sa_addr.pptp.srcaddr = 0;
431        err = connect(*poxfd, (struct sockaddr*)&lsp,
432            sizeof(struct sockaddr_pptpox));
433        if (err != 0)
434            warn("Couldn't connect to pptp kernel module");
435    }
436    else
437        warn("Couldn't connect socket to pppox");
438}
439/* Foxconn added end, Winster Chan, 06/26/2006 */
440
441/*** Open IP protocol socket **************************************************/
442int pptp_gre_bind(struct in_addr inetaddr)
443{
444    struct sockaddr_in src_addr, loc_addr;
445    extern struct in_addr localbind;
446    int s = socket(AF_INET, SOCK_RAW, PPTP_PROTO);
447    if (s < 0) { warn("socket: %s", strerror(errno)); return -1; }
448    if (localbind.s_addr != INADDR_NONE) {
449        bzero(&loc_addr, sizeof(loc_addr));
450        loc_addr.sin_family = AF_INET;
451        loc_addr.sin_addr   = localbind;
452        if (bind(s, (struct sockaddr *) &loc_addr, sizeof(loc_addr)) != 0) {
453            warn("bind: %s", strerror(errno)); close(s); return -1;
454        }
455    }
456    src_addr.sin_family = AF_INET;
457    src_addr.sin_addr   = inetaddr;
458    src_addr.sin_port   = 0;
459    if (connect(s, (struct sockaddr *) &src_addr, sizeof(src_addr)) < 0) {
460        warn("connect: %s", strerror(errno)); close(s); return -1;
461    }
462    return s;
463}
464
465/*** pptp_gre_copy ************************************************************/
466void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id,
467		   int pty_fd, int gre_fd)
468{
469    int max_fd;
470    pptp_gre_call_id = call_id;
471    pptp_gre_peer_call_id = peer_call_id;
472    /* Pseudo-terminal already open. */
473    ack_sent = ack_recv = seq_sent = seq_recv = 0;
474    /* weird select semantics */
475    max_fd = gre_fd;
476    if (pty_fd > max_fd) max_fd = pty_fd;
477    /* Dispatch loop */
478    for (;;) { /* until error happens on gre_fd or pty_fd */
479        struct timeval tv = {0, 0};
480        struct timeval *tvp;
481        fd_set rfds;
482        int retval;
483        pqueue_t *head;
484        int block_usecs = -1; /* wait forever */
485        extern void connect_pppunit(void); /* foxconn wklin added, 04/08/2011 */
486        connect_pppunit(); /* foxconn wklin added, 04/08/2011 */
487        /* watch terminal and socket for input */
488        FD_ZERO(&rfds);
489        FD_SET(gre_fd, &rfds);
490        FD_SET(pty_fd, &rfds);
491        /*
492         * if there are multiple pending ACKs, then do a minimal timeout;
493         * else if there is a single pending ACK then timeout after 0,5 seconds;
494         * else block until data is available.
495         */
496        if (ack_sent != seq_recv) {
497            if (ack_sent + 1 == seq_recv)  /* u_int wrap-around safe */
498                block_usecs = 500000;
499            else
500                /* don't use zero, this will force a resceduling */
501                /* when calling select(), giving pppd a chance to */
502                /* run. */
503                block_usecs = 1;
504        }
505        /* otherwise block_usecs == -1, which means wait forever */
506        /*
507         * If there is a packet in the queue, then don't wait longer than
508         * the time remaining until it expires.
509         */
510        head = pqueue_head();
511        if (head != NULL) {
512            int expiry_time = pqueue_expiry_time(head);
513            if (block_usecs == -1 || expiry_time < block_usecs)
514                block_usecs = expiry_time;
515        }
516        if (block_usecs == -1) {
517            tvp = NULL;
518        } else {
519            tvp = &tv;
520            tv.tv_usec = block_usecs;
521            tv.tv_sec  = tv.tv_usec / 1000000;
522            tv.tv_usec %= 1000000;
523        }
524        retval = select(max_fd + 1, &rfds, NULL, NULL, tvp);
525        if (FD_ISSET(pty_fd, &rfds)) {
526            if (decaps_hdlc(pty_fd, encaps_gre,  gre_fd) < 0)
527                break;
528        } else if (retval == 0 && ack_sent != seq_recv) {
529            /* if outstanding ack */
530            /* send ack with no payload */
531            encaps_gre(gre_fd, NULL, 0);
532        }
533        if (FD_ISSET(gre_fd, &rfds)) {
534            if (decaps_gre (gre_fd, encaps_hdlc, pty_fd) < 0)
535                break;
536        }
537        if (dequeue_gre (encaps_hdlc, pty_fd) < 0)
538            break;
539    }
540    /* Close up when done. */
541    close(gre_fd);
542    close(pty_fd);
543}
544
545#define HDLC_FLAG         0x7E
546#define HDLC_ESCAPE       0x7D
547#define HDLC_TRANSPARENCY 0x20
548
549/* ONE blocking read per call; dispatches all packets possible */
550/* returns 0 on success, or <0 on read failure                 */
551int decaps_hdlc(int fd, int (*cb)(int cl, void *pack, unsigned int len), int cl)
552{
553    unsigned char buffer[PACKET_MAX];
554    unsigned int start = 0;
555    int end;
556    int status;
557    static unsigned int len = 0, escape = 0;
558    static unsigned char copy[PACKET_MAX];
559    static int checkedsync = 0;
560    /* start is start of packet.  end is end of buffer data */
561    /*  this is the only blocking read we will allow */
562    if ((end = read (fd, buffer, sizeof(buffer))) <= 0) {
563        int saved_errno = errno;
564        warn("short read (%d): %s", end, strerror(saved_errno));
565	switch (saved_errno) {
566	  case EMSGSIZE: {
567	    int optval, optlen = sizeof(optval);
568	    warn("transmitted GRE packet triggered an ICMP destination unreachable, fragmentation needed, or exceeds the MTU of the network interface");
569#define IP_MTU 14
570	    if(getsockopt(fd, IPPROTO_IP, IP_MTU, &optval, &optlen) < 0)
571	      warn("getsockopt: %s", strerror(errno));
572	    warn("getsockopt: IP_MTU: %d\n", optval);
573	    return 0;
574	  }
575	case EIO:
576    	    warn("pppd may have shutdown, see pppd log");
577	    break;
578	}
579        return -1;
580    }
581    /* warn if the sync options of ppp and pptp don't match */
582    if( !checkedsync) {
583        checkedsync = 1;
584        if( buffer[0] == HDLC_FLAG){
585            if( syncppp )
586                warn( "pptp --sync option is active, "
587                        "yet the ppp mode is asynchronous!\n");
588        }
589	else if( !syncppp )
590            warn( "The ppp mode is synchronous, "
591                    "yet no pptp --sync option is specified!\n");
592    }
593    /* in synchronous mode there are no hdlc control characters nor checksum
594     * bytes. Find end of packet with the length information in the PPP packet
595     */
596    if ( syncppp ){
597        while ( start + 8 < end) {
598            len = ntoh16(*(short int *)(buffer + start + 6)) + 4;
599            /* note: the buffer may contain an incomplete packet at the end
600             * this packet will be read again at the next read() */
601            if ( start + len <= end)
602                if ((status = cb (cl, buffer + start, len)) < 0)
603                    return status; /* error-check */
604            start += len;
605        }
606        return 0;
607    }
608    /* asynchronous mode */
609    while (start < end) {
610        /* Copy to 'copy' and un-escape as we go. */
611        while (buffer[start] != HDLC_FLAG) {
612            if ((escape == 0) && buffer[start] == HDLC_ESCAPE) {
613                escape = HDLC_TRANSPARENCY;
614            } else {
615                if (len < PACKET_MAX)
616                    copy [len++] = buffer[start] ^ escape;
617                escape = 0;
618            }
619            start++;
620            if (start >= end)
621                return 0; /* No more data, but the frame is not complete yet. */
622        }
623        /* found flag.  skip past it */
624        start++;
625        /* check for over-short packets and silently discard, as per RFC1662 */
626        if ((len < 4) || (escape != 0)) {
627            len = 0; escape = 0;
628            continue;
629        }
630        /* check, then remove the 16-bit FCS checksum field */
631        if (pppfcs16 (PPPINITFCS16, copy, len) != PPPGOODFCS16)
632            warn("Bad Frame Check Sequence during PPP to GRE decapsulation");
633        len -= sizeof(u_int16_t);
634        /* so now we have a packet of length 'len' in 'copy' */
635        if ((status = cb (cl, copy, len)) < 0)
636            return status; /* error-check */
637        /* Great!  Let's do more! */
638        len = 0; escape = 0;
639    }
640    return 0;
641    /* No more data to process. */
642}
643
644/*** Make stripped packet into HDLC packet ************************************/
645int encaps_hdlc(int fd, void *pack, unsigned int len)
646{
647    unsigned char *source = (unsigned char *)pack;
648    unsigned char dest[2 * PACKET_MAX + 2]; /* largest expansion possible */
649    unsigned int pos = 0, i;
650    u_int16_t fcs;
651    /* in synchronous mode there is little to do */
652    if ( syncppp )
653        return write(fd, source, len);
654    /* asynchronous mode */
655    /* Compute the FCS */
656    fcs = pppfcs16(PPPINITFCS16, source, len) ^ 0xFFFF;
657    /* start character */
658    dest[pos++] = HDLC_FLAG;
659    /* escape the payload */
660    for (i = 0; i < len + 2; i++) {
661        /* wacked out assignment to add FCS to end of source buffer */
662        unsigned char c =
663            (i < len)?source[i]:(i == len)?(fcs & 0xFF):((fcs >> 8) & 0xFF);
664        if (pos >= sizeof(dest)) break; /* truncate on overflow */
665        if ( (c < 0x20) || (c == HDLC_FLAG) || (c == HDLC_ESCAPE) ) {
666            dest[pos++] = HDLC_ESCAPE;
667            if (pos < sizeof(dest))
668                dest[pos++] = c ^ 0x20;
669        } else
670            dest[pos++] = c;
671    }
672    /* tack on the end-flag */
673    if (pos < sizeof(dest))
674        dest[pos++] = HDLC_FLAG;
675    /* now write this packet */
676    return write(fd, dest, pos);
677}
678
679/*** decaps_gre ***************************************************************/
680int decaps_gre (int fd, callback_t callback, int cl)
681{
682    unsigned char buffer[PACKET_MAX + 64 /*ip header*/];
683    struct pptp_gre_header *header;
684    int status, ip_len = 0;
685    static int first = 1;
686    unsigned int headersize;
687    unsigned int payload_len;
688    u_int32_t seq;
689
690    if ((status = read (fd, buffer, sizeof(buffer))) <= 0) {
691        warn("short read (%d): %s", status, strerror(errno));
692        stats.rx_errors++;
693        return -1;
694    }
695    /* strip off IP header, if present */
696    if ((buffer[0] & 0xF0) == 0x40)
697        ip_len = (buffer[0] & 0xF) * 4;
698    header = (struct pptp_gre_header *)(buffer + ip_len);
699    /* verify packet (else discard) */
700    if (    /* version should be 1 */
701            ((ntoh8(header->ver) & 0x7F) != PPTP_GRE_VER) ||
702            /* PPTP-GRE protocol for PPTP */
703            (ntoh16(header->protocol) != PPTP_GRE_PROTO)||
704            /* flag C should be clear   */
705            PPTP_GRE_IS_C(ntoh8(header->flags)) ||
706            /* flag R should be clear   */
707            PPTP_GRE_IS_R(ntoh8(header->flags)) ||
708            /* flag K should be set     */
709            (!PPTP_GRE_IS_K(ntoh8(header->flags))) ||
710            /* routing and recursion ctrl = 0  */
711            ((ntoh8(header->flags)&0xF) != 0)) {
712        /* if invalid, discard this packet */
713        warn("Discarding GRE: %X %X %X %X %X %X",
714                ntoh8(header->ver)&0x7F, ntoh16(header->protocol),
715                PPTP_GRE_IS_C(ntoh8(header->flags)),
716                PPTP_GRE_IS_R(ntoh8(header->flags)),
717                PPTP_GRE_IS_K(ntoh8(header->flags)),
718                ntoh8(header->flags) & 0xF);
719        stats.rx_invalid++;
720        return 0;
721    }
722    /* silently discard packets not for this call */
723    if (ntoh16(header->call_id) != pptp_gre_call_id) return 0;
724    /* test if acknowledgement present */
725    if (PPTP_GRE_IS_A(ntoh8(header->ver))) {
726        u_int32_t ack = (PPTP_GRE_IS_S(ntoh8(header->flags)))?
727            header->ack:header->seq; /* ack in different place if S = 0 */
728        ack = ntoh32( ack);
729        if (ack > ack_recv) ack_recv = ack;
730        /* also handle sequence number wrap-around  */
731        if (WRAPPED(ack,ack_recv)) ack_recv = ack;
732        if (ack_recv == stats.pt.seq) {
733            int rtt = time_now_usecs() - stats.pt.time;
734            stats.rtt = (stats.rtt + rtt) / 2;
735        }
736    }
737    /* test if payload present */
738    if (!PPTP_GRE_IS_S(ntoh8(header->flags)))
739        return 0; /* ack, but no payload */
740    headersize  = sizeof(*header);
741    payload_len = ntoh16(header->payload_len);
742    seq         = ntoh32(header->seq);
743    /* no ack present? */
744    if (!PPTP_GRE_IS_A(ntoh8(header->ver))) headersize -= sizeof(header->ack);
745    /* check for incomplete packet (length smaller than expected) */
746    if (status - headersize < payload_len) {
747        warn("discarding truncated packet (expected %d, got %d bytes)",
748                payload_len, status - headersize);
749        stats.rx_truncated++;
750        return 0;
751    }
752    /* wklin modified start, 01/25/2007 */
753    /* The seq# is maintained in the kernel, cannot use the seq# to determine if
754     * the packet can be accepted or not. Just forward all the ppp control
755     * packets to pppd, those packets should be justified there.
756     */
757    stats.rx_accepted++;
758    first = 0;
759    seq_recv = seq;
760    return callback(cl, buffer + ip_len + headersize, payload_len);
761#if 0
762    /* check for expected sequence number */
763    if ( first || (seq == seq_recv + 1)) { /* wrap-around safe */
764	if ( log_level >= 2 )
765            log("accepting packet %d", seq);
766        stats.rx_accepted++;
767        first = 0;
768        seq_recv = seq;
769        return callback(cl, buffer + ip_len + headersize, payload_len);
770    /* out of order, check if the number is too low and discard the packet.
771     * (handle sequence number wrap-around, and try to do it right) */
772    } else if ( seq < seq_recv + 1 || WRAPPED(seq_recv, seq) ) {
773	if ( log_level >= 1 )
774            log("discarding duplicate or old packet %d (expecting %d)",
775                seq, seq_recv + 1);
776        stats.rx_underwin++;
777    /* sequence number too high, is it reasonably close? */
778    } else if ( seq < seq_recv + MISSING_WINDOW ||
779                WRAPPED(seq, seq_recv + MISSING_WINDOW) ) {
780	stats.rx_buffered++;
781        if ( log_level >= 1 )
782            log("%s packet %d (expecting %d, lost or reordered)",
783                disable_buffer ? "accepting" : "buffering",
784                seq, seq_recv+1);
785        if ( disable_buffer ) {
786            seq_recv = seq;
787            stats.rx_lost += seq - seq_recv - 1;
788            return callback(cl, buffer + ip_len + headersize, payload_len);
789        } else {
790            pqueue_add(seq, buffer + ip_len + headersize, payload_len);
791	}
792    /* no, packet must be discarded */
793    } else {
794	if ( log_level >= 1 )
795            warn("discarding bogus packet %d (expecting %d)",
796		 seq, seq_recv + 1);
797        stats.rx_overwin++;
798    }
799#endif /* wklin modified end, 01/25/2007 */
800    return 0;
801}
802
803/*** dequeue_gre **************************************************************/
804int dequeue_gre (callback_t callback, int cl)
805{
806    pqueue_t *head;
807    int status;
808    /* process packets in the queue that either are expected or have
809     * timed out. */
810    head = pqueue_head();
811    while ( head != NULL &&
812            ( (head->seq == seq_recv + 1) || /* wrap-around safe */
813              (pqueue_expiry_time(head) <= 0)
814            )
815          ) {
816        /* if it is timed out... */
817        if (head->seq != seq_recv + 1 ) {  /* wrap-around safe */
818            stats.rx_lost += head->seq - seq_recv - 1;
819	    if (log_level >= 2)
820                log("timeout waiting for %d packets", head->seq - seq_recv - 1);
821        }
822	if (log_level >= 2)
823            log("accepting %d from queue", head->seq);
824        seq_recv = head->seq;
825        status = callback(cl, head->packet, head->packlen);
826        pqueue_del(head);
827        if (status < 0)
828            return status;
829        head = pqueue_head();
830    }
831    return 0;
832}
833
834/*** encaps_gre ***************************************************************/
835int encaps_gre (int fd, void *pack, unsigned int len)
836{
837    union {
838        struct pptp_gre_header header;
839        unsigned char buffer[PACKET_MAX + sizeof(struct pptp_gre_header)];
840    } u;
841    //static u_int32_t seq = 1; /* first sequence number sent must be 1 */
842    unsigned int header_len;
843    int rc;
844    /* Foxconn added start, Winster Chan, 06/26/2006 */
845    static u_int32_t kerseq; /* Sequence number got from kernel by ioctl() */
846    /* Foxconn added end, Winster Chan, 06/26/2006 */
847
848    /* package this up in a GRE shell. */
849    u.header.flags       = hton8 (PPTP_GRE_FLAG_K);
850    u.header.ver         = hton8 (PPTP_GRE_VER);
851    u.header.protocol    = hton16(PPTP_GRE_PROTO);
852    u.header.payload_len = hton16(len);
853    u.header.call_id     = hton16(pptp_gre_peer_call_id);
854    /* special case ACK with no payload */
855    if (pack == NULL) {
856        if (ack_sent != seq_recv) {
857            u.header.ver |= hton8(PPTP_GRE_FLAG_A);
858            u.header.payload_len = hton16(0);
859            /* ack is in odd place because S == 0 */
860            u.header.seq = hton32(seq_recv);
861            ack_sent = seq_recv;
862            rc = write(fd, &u.header, sizeof(u.header) - sizeof(u.header.seq));
863            if (rc < 0) {
864                stats.tx_failed++;
865            } else if (rc < sizeof(u.header) - sizeof(u.header.seq)) {
866                stats.tx_short++;
867            } else {
868                stats.tx_acks++;
869            }
870            return rc;
871        } else return 0; /* we don't need to send ACK */
872    } /* explicit brace to avoid ambiguous `else' warning */
873    /* send packet with payload */
874    u.header.flags |= hton8(PPTP_GRE_FLAG_S);
875    /* Foxconn modified start, Winster Chan, 06/26/2006 */
876    //u.header.seq    = hton32(seq);
877    if (pox_fd >= 0) {
878    	if (ioctl(pox_fd, PPTPIOCGGRESEQ, &kerseq) == -1) {
879            warn("Couldn't get GRE sequence number");
880        }
881	}
882	else
883        warn("Socket not opened");
884    u.header.seq    = hton32(kerseq);
885    /* Foxconn modified end, Winster Chan, 06/26/2006 */
886    if (ack_sent != seq_recv) { /* send ack with this message */
887        u.header.ver |= hton8(PPTP_GRE_FLAG_A);
888        u.header.ack  = hton32(seq_recv);
889        ack_sent = seq_recv;
890        header_len = sizeof(u.header);
891    } else { /* don't send ack */
892        header_len = sizeof(u.header) - sizeof(u.header.ack);
893    }
894    if (header_len + len >= sizeof(u.buffer)) {
895        stats.tx_oversize++;
896        return 0; /* drop this, it's too big */
897    }
898    /* copy payload into buffer */
899    memcpy(u.buffer + header_len, pack, len);
900    /* record and increment sequence numbers */
901    /* Foxconn modified start, Winster Chan, 06/26/2006 */
902    //seq_sent = seq; seq++;
903    /*
904     * Note: the kerseq(kernel sequence number) is maintained by
905     *       pptp kernel driver
906     */
907    seq_sent = kerseq;
908    /* Foxconn modified end, Winster Chan, 06/26/2006 */
909    /* write this baby out to the net */
910    /* print_packet(2, u.buffer, header_len + len); */
911    rc = write(fd, u.buffer, header_len + len);
912    if (rc < 0) {
913        stats.tx_failed++;
914    } else if (rc < header_len + len) {
915        stats.tx_short++;
916    } else {
917        stats.tx_sent++;
918        stats.pt.seq  = seq_sent;
919        stats.pt.time = time_now_usecs();
920    }
921    return rc;
922}
923