xref: /netbsd-src/external/bsd/ppp/dist/pppd/demand.c (revision 3f351f34c6d827cf017cdcff3543f6ec0c88b420)
1 /*	$NetBSD: demand.c,v 1.5 2021/01/09 16:39:28 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.5 2021/01/09 16:39:28 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(unsigned char *, int);
81 
82 /*
83  * demand_conf - configure the interface for doing dial-on-demand.
84  */
85 void
86 demand_conf(void)
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(void)
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(void)
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(void)
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(unsigned char *p, int n)
226 {
227     int c, rv;
228 
229     rv = 0;
230     for (; n > 0; --n) {
231 	c = *p++;
232 	if (c == PPP_FLAG) {
233 	    if (!escape_flag && !flush_flag
234 		&& framelen > 2 && fcs == PPP_GOODFCS) {
235 		framelen -= 2;
236 		if (loop_frame((unsigned char *)frame, framelen))
237 		    rv = 1;
238 	    }
239 	    framelen = 0;
240 	    flush_flag = 0;
241 	    escape_flag = 0;
242 	    fcs = PPP_INITFCS;
243 	    continue;
244 	}
245 	if (flush_flag)
246 	    continue;
247 	if (escape_flag) {
248 	    c ^= PPP_TRANS;
249 	    escape_flag = 0;
250 	} else if (c == PPP_ESCAPE) {
251 	    escape_flag = 1;
252 	    continue;
253 	}
254 	if (framelen >= framemax) {
255 	    flush_flag = 1;
256 	    continue;
257 	}
258 	frame[framelen++] = c;
259 	fcs = PPP_FCS(fcs, c);
260     }
261     return rv;
262 }
263 
264 /*
265  * loop_frame - given a frame obtained from the loopback,
266  * decide whether to bring up the link or not, and, if we want
267  * to transmit this frame later, put it on the pending queue.
268  * Return value is 1 if we need to bring up the link, 0 otherwise.
269  * We assume that the kernel driver has already applied the
270  * pass_filter, so we won't get packets it rejected.
271  * We apply the active_filter to see if we want this packet to
272  * bring up the link.
273  */
274 int
275 loop_frame(unsigned char *frame, int len)
276 {
277     struct packet *pkt;
278 
279     /* dbglog("from loop: %P", frame, len); */
280     if (len < PPP_HDRLEN)
281 	return 0;
282     if ((PPP_PROTOCOL(frame) & 0x8000) != 0)
283 	return 0;		/* shouldn't get any of these anyway */
284     if (!active_packet(frame, len))
285 	return 0;
286 
287     pkt = (struct packet *) malloc(sizeof(struct packet) + len);
288     if (pkt != NULL) {
289 	pkt->length = len;
290 	pkt->next = NULL;
291 	memcpy(pkt->data, frame, len);
292 	if (pend_q == NULL)
293 	    pend_q = pkt;
294 	else
295 	    pend_qtail->next = pkt;
296 	pend_qtail = pkt;
297     }
298     return 1;
299 }
300 
301 /*
302  * demand_rexmit - Resend all those frames which we got via the
303  * loopback, now that the real serial link is up.
304  */
305 void
306 demand_rexmit(int proto)
307 {
308     struct packet *pkt, *prev, *nextpkt;
309 
310     prev = NULL;
311     pkt = pend_q;
312     pend_q = NULL;
313     for (; pkt != NULL; pkt = nextpkt) {
314 	nextpkt = pkt->next;
315 	if (PPP_PROTOCOL(pkt->data) == proto) {
316 	    output(0, pkt->data, pkt->length);
317 	    free(pkt);
318 	} else {
319 	    if (prev == NULL)
320 		pend_q = pkt;
321 	    else
322 		prev->next = pkt;
323 	    prev = pkt;
324 	}
325     }
326     pend_qtail = prev;
327     if (prev != NULL)
328 	prev->next = NULL;
329 }
330 
331 /*
332  * Scan a packet to decide whether it is an "active" packet,
333  * that is, whether it is worth bringing up the link for.
334  */
335 static int
336 active_packet(unsigned char *p, int len)
337 {
338     int proto, i;
339     struct protent *protp;
340 
341     if (len < PPP_HDRLEN)
342 	return 0;
343     proto = PPP_PROTOCOL(p);
344 #ifdef PPP_FILTER
345     p[0] = 1;		/* outbound packet indicator */
346     if ((pass_filter_out.bf_len != 0
347 	 && bpf_filter(pass_filter_out.bf_insns, p, len, len) == 0)
348 	|| (active_filter_out.bf_len != 0
349 	    && bpf_filter(active_filter_out.bf_insns, p, len, len) == 0)) {
350 	p[0] = 0xff;
351 	return 0;
352     }
353     p[0] = 0xff;
354 #endif
355     for (i = 0; (protp = protocols[i]) != NULL; ++i) {
356 	if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
357 	    if (!protp->enabled_flag)
358 		return 0;
359 	    if (protp->active_pkt == NULL)
360 		return 1;
361 	    return (*protp->active_pkt)(p, len);
362 	}
363     }
364     return 0;			/* not a supported protocol !!?? */
365 }
366