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