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