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