www.usr.com/support/gpl/USR9107_release.1.4.tar.gz
[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.15 2001/03/08 05:14:26 paulus 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
75 // cwu
76 /*    framemax = lcp_allowoptions[0].mru;
77     if (framemax < PPP_MRU) */
78         framemax = PPP_MRU;
79     framemax += PPP_HDRLEN + PPP_FCSLEN;
80     frame = malloc(framemax);
81     if (frame == NULL)
82         novm("demand frame");
83     framelen = 0;
84     pend_q = NULL;
85     escape_flag = 0;
86     flush_flag = 0;
87     fcs = PPP_INITFCS;
88
89     netif_set_mtu(0, MIN(lcp_allowoptions[0].mru, PPP_MRU));
90     ppp_send_config(0, PPP_MRU, (u_int32_t) 0, 0, 0);
91     ppp_recv_config(0, PPP_MRU, (u_int32_t) 0, 0, 0);
92
93 #ifdef PPP_FILTER
94     set_filters(&pass_filter, &active_filter);
95 #endif
96
97     /*
98      * Call the demand_conf procedure for each protocol that's got one.
99      */
100     for (i = 0; (protp = protocols[i]) != NULL; ++i)
101         if (protp->enabled_flag && protp->demand_conf != NULL)
102             if (!((*protp->demand_conf)(0)))
103                 die(1);
104 }
105
106
107 /*
108  * demand_block - set each network protocol to block further packets.
109  */
110 void
111 demand_block()
112 {
113     int i;
114     struct protent *protp;
115
116     for (i = 0; (protp = protocols[i]) != NULL; ++i)
117         if (protp->enabled_flag && protp->demand_conf != NULL)
118             sifnpmode(0, protp->protocol & ~0x8000, NPMODE_QUEUE);
119     get_loop_output();
120 }
121
122 /*
123  * demand_discard - set each network protocol to discard packets
124  * with an error.
125  */
126 void
127 demand_discard()
128 {
129     struct packet *pkt, *nextpkt;
130     int i;
131     struct protent *protp;
132
133     for (i = 0; (protp = protocols[i]) != NULL; ++i)
134         if (protp->enabled_flag && protp->demand_conf != NULL)
135             sifnpmode(0, protp->protocol & ~0x8000, NPMODE_ERROR);
136     get_loop_output();
137
138     /* discard all saved packets */
139     for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
140         nextpkt = pkt->next;
141         free(pkt);
142     }
143     pend_q = NULL;
144     framelen = 0;
145     flush_flag = 0;
146     escape_flag = 0;
147     fcs = PPP_INITFCS;
148 }
149
150 /*
151  * demand_unblock - set each enabled network protocol to pass packets.
152  */
153 void
154 demand_unblock()
155 {
156     int i;
157     struct protent *protp;
158
159     for (i = 0; (protp = protocols[i]) != NULL; ++i)
160         if (protp->enabled_flag && protp->demand_conf != NULL)
161             sifnpmode(0, protp->protocol & ~0x8000, NPMODE_PASS);
162 }
163
164 /*
165  * FCS lookup table as calculated by genfcstab.
166  */
167 static u_short fcstab[256] = {
168         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
169         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
170         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
171         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
172         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
173         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
174         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
175         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
176         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
177         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
178         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
179         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
180         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
181         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
182         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
183         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
184         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
185         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
186         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
187         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
188         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
189         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
190         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
191         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
192         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
193         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
194         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
195         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
196         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
197         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
198         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
199         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
200 };
201
202 /*
203  * loop_chars - process characters received from the loopback.
204  * Calls loop_frame when a complete frame has been accumulated.
205  * Return value is 1 if we need to bring up the link, 0 otherwise.
206  */
207 int
208 loop_chars(p, n)
209     unsigned char *p;
210     int n;
211 {
212     int c, rv;
213
214     rv = 0;
215     for (; n > 0; --n) {
216         c = *p++;
217         if (c == PPP_FLAG) {
218             if (!escape_flag && !flush_flag
219                 && framelen > 2 && fcs == PPP_GOODFCS) {
220                 framelen -= 2;
221                 if (loop_frame((unsigned char *)frame, framelen))
222                     rv = 1;
223             }
224             framelen = 0;
225             flush_flag = 0;
226             escape_flag = 0;
227             fcs = PPP_INITFCS;
228             continue;
229         }
230         if (flush_flag)
231             continue;
232         if (escape_flag) {
233             c ^= PPP_TRANS;
234             escape_flag = 0;
235         } else if (c == PPP_ESCAPE) {
236             escape_flag = 1;
237             continue;
238         }
239         if (framelen >= framemax) {
240             flush_flag = 1;
241             continue;
242         }
243         frame[framelen++] = c;
244         fcs = PPP_FCS(fcs, c);
245     }
246     return rv;
247 }
248
249 /*
250  * loop_frame - given a frame obtained from the loopback,
251  * decide whether to bring up the link or not, and, if we want
252  * to transmit this frame later, put it on the pending queue.
253  * Return value is 1 if we need to bring up the link, 0 otherwise.
254  * We assume that the kernel driver has already applied the
255  * pass_filter, so we won't get packets it rejected.
256  * We apply the active_filter to see if we want this packet to
257  * bring up the link.
258  */
259 int
260 loop_frame(frame, len)
261     unsigned char *frame;
262     int len;
263 {
264     struct packet *pkt;
265
266     /* dbglog("from loop: %P", frame, len); */
267     if (len < PPP_HDRLEN)
268         return 0;
269     if ((PPP_PROTOCOL(frame) & 0x8000) != 0)
270         return 0;               /* shouldn't get any of these anyway */
271     if (!active_packet(frame, len))
272         return 0;
273
274     pkt = (struct packet *) malloc(sizeof(struct packet) + len);
275     if (pkt != NULL) {
276         pkt->length = len;
277         pkt->next = NULL;
278         memcpy(pkt->data, frame, len);
279         if (pend_q == NULL)
280             pend_q = pkt;
281         else
282             pend_qtail->next = pkt;
283         pend_qtail = pkt;
284     }
285     return 1;
286 }
287
288 /*
289  * demand_rexmit - Resend all those frames which we got via the
290  * loopback, now that the real serial link is up.
291  */
292 void
293 demand_rexmit(proto)
294     int proto;
295 {
296     struct packet *pkt, *prev, *nextpkt;
297
298     prev = NULL;
299     pkt = pend_q;
300     pend_q = NULL;
301     for (; pkt != NULL; pkt = nextpkt) {
302         nextpkt = pkt->next;
303         if (PPP_PROTOCOL(pkt->data) == proto) {
304             output(0, pkt->data, pkt->length);
305             free(pkt);
306         } else {
307             if (prev == NULL)
308                 pend_q = pkt;
309             else
310                 prev->next = pkt;
311             prev = pkt;
312         }
313     }
314     pend_qtail = prev;
315     if (prev != NULL)
316         prev->next = NULL;
317 }
318
319 /*
320  * Scan a packet to decide whether it is an "active" packet,
321  * that is, whether it is worth bringing up the link for.
322  */
323 static int
324 active_packet(p, len)
325     unsigned char *p;
326     int len;
327 {
328     int proto, i;
329     struct protent *protp;
330
331     if (len < PPP_HDRLEN)
332         return 0;
333     proto = PPP_PROTOCOL(p);
334 #ifdef PPP_FILTER
335     if (pass_filter.bf_len != 0
336         && bpf_filter(pass_filter.bf_insns, p, len, len) == 0)
337         return 0;
338     if (active_filter.bf_len != 0
339         && bpf_filter(active_filter.bf_insns, p, len, len) == 0)
340         return 0;
341 #endif
342     for (i = 0; (protp = protocols[i]) != NULL; ++i) {
343         if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
344             if (!protp->enabled_flag)
345                 return 0;
346             if (protp->active_pkt == NULL)
347                 return 1;
348             return (*protp->active_pkt)(p, len);
349         }
350     }
351     return 0;                   /* not a supported protocol !!?? */
352 }