http://downloads.netgear.com/files/GPL/GPL_Source_V361j_DM111PSP_series_consumer_rele...
[bcm963xx.git] / userapps / opensource / ppp / pppoe / demand.c
1 /*
2  * demand.c - Support routines for demand-dialling.
3  *
4  * Copyright (c) 1993 The Australian National University.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms are permitted
8  * provided that the above copyright notice and this paragraph are
9  * duplicated in all such forms and that any documentation,
10  * advertising materials, and other materials related to such
11  * distribution and use acknowledge that the software was developed
12  * by the Australian National University.  The name of the University
13  * may not be used to endorse or promote products derived from this
14  * software without specific prior written permission.
15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  */
19
20 #define RCSID   "$Id: demand.c,v 1.2 2006/05/31 09:34:26 andylin Exp $"
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <netdb.h>
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <sys/time.h>
32 #include <sys/resource.h>
33 #include <sys/stat.h>
34 #include <sys/socket.h>
35 #ifdef PPP_FILTER
36 #include <net/if.h>
37 #include <net/bpf.h>
38 #include <pcap.h>
39 #endif
40
41 #include "pppd.h"
42 #include "fsm.h"
43 #include "ipcp.h"
44 #include "lcp.h"
45
46 static const char rcsid[] = RCSID;
47
48 char *frame;
49 int framelen;
50 int framemax;
51 int escape_flag;
52 int flush_flag;
53 int fcs;
54
55 struct packet {
56     int length;
57     struct packet *next;
58     unsigned char data[1];
59 };
60
61 struct packet *pend_q;
62 struct packet *pend_qtail;
63
64 static int active_packet __P((unsigned char *, int));
65
66 /*
67  * demand_conf - configure the interface for doing dial-on-demand.
68  */
69 void
70 demand_conf()
71 {
72     int i;
73     struct protent *protp;
74 // cwu
75 /*    framemax = lcp_allowoptions[0].mru;
76     if (framemax < PPP_MRU) */
77         framemax = PPP_MRU;
78     framemax += PPP_HDRLEN + PPP_FCSLEN;
79     frame = malloc(framemax);
80     if (frame == NULL)
81         novm("demand frame");
82     framelen = 0;
83     pend_q = NULL;
84     escape_flag = 0;
85     flush_flag = 0;
86     fcs = PPP_INITFCS;
87
88     netif_set_mtu(0, MIN(lcp_allowoptions[0].mru, PPP_MRU));
89 #if defined(INCLUDE_MTU_LAN_PPP)
90         ppp_send_config(0, lcp_allowoptions[0].mru, (u_int32_t) 0, 0, 0);
91 #else    
92     ppp_send_config(0, PPP_MRU, (u_int32_t) 0, 0, 0);
93 #endif
94 #if defined(INCLUDE_MTU_LAN_PPP)
95         ppp_recv_config(0, lcp_allowoptions[0].mru, (u_int32_t) 0, 0, 0);
96 #else    
97     ppp_recv_config(0, PPP_MRU, (u_int32_t) 0, 0, 0);
98 #endif
99 #ifdef PPP_FILTER
100     set_filters(&pass_filter, &active_filter);
101 #endif
102
103     /*
104      * Call the demand_conf procedure for each protocol that's got one.
105      */
106     for (i = 0; (protp = protocols[i]) != NULL; ++i)
107         if (protp->enabled_flag && protp->demand_conf != NULL)
108             if (!((*protp->demand_conf)(0)))
109                 die(1);
110
111 }
112
113
114 /*
115  * demand_block - set each network protocol to block further packets.
116  */
117 void
118 demand_block()
119 {
120     int i;
121     struct protent *protp;
122
123     for (i = 0; (protp = protocols[i]) != NULL; ++i)
124         if (protp->enabled_flag && protp->demand_conf != NULL)
125             sifnpmode(0, protp->protocol & ~0x8000, NPMODE_QUEUE);
126     get_loop_output();
127 }
128
129 /*
130  * demand_discard - set each network protocol to discard packets
131  * with an error.
132  */
133 void
134 demand_discard()
135 {
136     struct packet *pkt, *nextpkt;
137     int i;
138     struct protent *protp;
139
140     for (i = 0; (protp = protocols[i]) != NULL; ++i)
141         if (protp->enabled_flag && protp->demand_conf != NULL)
142             sifnpmode(0, protp->protocol & ~0x8000, NPMODE_ERROR);
143     get_loop_output();
144
145     /* discard all saved packets */
146     for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
147         nextpkt = pkt->next;
148         free(pkt);
149     }
150     pend_q = NULL;
151     framelen = 0;
152     flush_flag = 0;
153     escape_flag = 0;
154     fcs = PPP_INITFCS;
155 }
156
157 /*
158  * demand_unblock - set each enabled network protocol to pass packets.
159  */
160 void
161 demand_unblock()
162 {
163     int i;
164     struct protent *protp;
165
166     for (i = 0; (protp = protocols[i]) != NULL; ++i)
167         if (protp->enabled_flag && protp->demand_conf != NULL)
168             sifnpmode(0, protp->protocol & ~0x8000, NPMODE_PASS);
169 }
170
171 /*
172  * FCS lookup table as calculated by genfcstab.
173  */
174 static u_short fcstab[256] = {
175         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
176         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
177         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
178         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
179         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
180         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
181         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
182         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
183         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
184         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
185         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
186         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
187         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
188         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
189         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
190         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
191         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
192         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
193         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
194         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
195         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
196         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
197         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
198         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
199         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
200         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
201         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
202         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
203         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
204         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
205         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
206         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
207 };
208
209 /*
210  * loop_chars - process characters received from the loopback.
211  * Calls loop_frame when a complete frame has been accumulated.
212  * Return value is 1 if we need to bring up the link, 0 otherwise.
213  */
214 int
215 loop_chars(p, n)
216     unsigned char *p;
217     int n;
218 {
219     int c, rv;
220
221     rv = 0;
222     for (; n > 0; --n) {
223         c = *p++;
224         if (c == PPP_FLAG) {
225             if (!escape_flag && !flush_flag
226                 && framelen > 2 && fcs == PPP_GOODFCS) {
227                 framelen -= 2;
228                 if (loop_frame((unsigned char *)frame, framelen))
229                     rv = 1;
230             }
231             framelen = 0;
232             flush_flag = 0;
233             escape_flag = 0;
234             fcs = PPP_INITFCS;
235             continue;
236         }
237         if (flush_flag)
238             continue;
239         if (escape_flag) {
240             c ^= PPP_TRANS;
241             escape_flag = 0;
242         } else if (c == PPP_ESCAPE) {
243             escape_flag = 1;
244             continue;
245         }
246         if (framelen >= framemax) {
247             flush_flag = 1;
248             continue;
249         }
250         frame[framelen++] = c;
251         fcs = PPP_FCS(fcs, c);
252     }
253     return rv;
254 }
255
256 /*
257  * loop_frame - given a frame obtained from the loopback,
258  * decide whether to bring up the link or not, and, if we want
259  * to transmit this frame later, put it on the pending queue.
260  * Return value is 1 if we need to bring up the link, 0 otherwise.
261  * We assume that the kernel driver has already applied the
262  * pass_filter, so we won't get packets it rejected.
263  * We apply the active_filter to see if we want this packet to
264  * bring up the link.
265  */
266
267 int
268 loop_frame(frame, len)
269     unsigned char *frame;
270     int len;
271 {
272     struct packet *pkt;
273
274         /**********************************************************
275         * Fix bug(494):Setup ppp is manual mode. Router hanged up *
276         * if user generated packets to WAN side and the PPP       *
277         * connection is down.                                     *
278         * Andy (2005/10/18)                                       *
279         **************************************************/
280         extern int ppp_status;
281     if (ppp_manual && !ppp_status)// is manual mode and ppp is down
282                 return 0;
283         
284     /* dbglog("from loop: %P", frame, len); */
285     if (len < PPP_HDRLEN)
286         return 0;
287     if ((PPP_PROTOCOL(frame) & 0x8000) != 0)
288         return 0;               /* shouldn't get any of these anyway */
289     if (!active_packet(frame, len))
290         return 0;
291
292     pkt = (struct packet *) malloc(sizeof(struct packet) + len);
293     if (pkt != NULL) {
294         pkt->length = len;
295         pkt->next = NULL;
296         memcpy(pkt->data, frame, len);
297         if (pend_q == NULL)
298             pend_q = pkt;
299         else
300             pend_qtail->next = pkt;
301         pend_qtail = pkt;
302     }
303     return 1;
304 }
305
306 /*
307  * demand_rexmit - Resend all those frames which we got via the
308  * loopback, now that the real serial link is up.
309  */
310 void
311 demand_rexmit(proto)
312     int proto;
313 {
314     struct packet *pkt, *prev, *nextpkt;
315
316     prev = NULL;
317     pkt = pend_q;
318     pend_q = NULL;
319     for (; pkt != NULL; pkt = nextpkt) {
320         nextpkt = pkt->next;
321         if (PPP_PROTOCOL(pkt->data) == proto) {
322             output(0, pkt->data, pkt->length);
323             free(pkt);
324         } else {
325             if (prev == NULL)
326                 pend_q = pkt;
327             else
328                 prev->next = pkt;
329             prev = pkt;
330         }
331     }
332     pend_qtail = prev;
333     if (prev != NULL)
334         prev->next = NULL;
335 }
336
337 /*
338  * Scan a packet to decide whether it is an "active" packet,
339  * that is, whether it is worth bringing up the link for.
340  */
341 static int
342 active_packet(p, len)
343     unsigned char *p;
344     int len;
345 {
346     int proto, i;
347     struct protent *protp;
348
349     if (len < PPP_HDRLEN)
350         return 0;
351     proto = PPP_PROTOCOL(p);
352 #ifdef PPP_FILTER
353     if (pass_filter.bf_len != 0
354         && bpf_filter(pass_filter.bf_insns, p, len, len) == 0)
355         return 0;
356     if (active_filter.bf_len != 0
357         && bpf_filter(active_filter.bf_insns, p, len, len) == 0)
358         return 0;
359 #endif
360     for (i = 0; (protp = protocols[i]) != NULL; ++i) {
361         if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
362             if (!protp->enabled_flag)
363                 return 0;
364             if (protp->active_pkt == NULL)
365                 return 1;
366             return (*protp->active_pkt)(p, len);
367         }
368     }
369     return 0;                   /* not a supported protocol !!?? */
370 }