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