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