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