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