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