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