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