xref: /netbsd-src/external/bsd/ppp/dist/pppd/demand.c (revision f12839c5f795a8def46f685de6698463dbd213a9)
1 /*	$NetBSD: demand.c,v 1.6 2025/01/08 19:59:39 christos Exp $	*/
2 
3 /*
4  * demand.c - Support routines for demand-dialling.
5  *
6  * Copyright (c) 1996-2024 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  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
21  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
22  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
23  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
25  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
26  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27  */
28 
29 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: demand.c,v 1.6 2025/01/08 19:59:39 christos Exp $");
31 
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <netdb.h>
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/wait.h>
45 #include <sys/time.h>
46 #include <sys/resource.h>
47 #include <sys/stat.h>
48 #include <sys/socket.h>
49 #ifdef PPP_WITH_FILTER
50 #ifdef __NetBSD__
51 #include <pcap.h>
52 #else
53 #include <pcap-bpf.h>
54 #endif
55 #endif
56 
57 #include "pppd-private.h"
58 #include "fsm.h"
59 #include "ipcp.h"
60 #include "lcp.h"
61 
62 
63 char *frame;
64 int framelen;
65 int framemax;
66 int escape_flag;
67 int flush_flag;
68 int fcs;
69 
70 struct packet {
71     int length;
72     struct packet *next;
73     unsigned char data[1];
74 };
75 
76 struct packet *pend_q;
77 struct packet *pend_qtail;
78 
79 static int active_packet(unsigned char *, int);
80 
81 /*
82  * demand_conf - configure the interface for doing dial-on-demand.
83  */
84 void
85 demand_conf(void)
86 {
87     int i;
88     struct protent *protp;
89 
90 /*    framemax = lcp_allowoptions[0].mru;
91     if (framemax < PPP_MRU) */
92 	framemax = PPP_MRU;
93     framemax += PPP_HDRLEN + PPP_FCSLEN;
94     frame = malloc(framemax);
95     if (frame == NULL)
96 	novm("demand frame");
97     framelen = 0;
98     pend_q = NULL;
99     escape_flag = 0;
100     flush_flag = 0;
101     fcs = PPP_INITFCS;
102 
103     ppp_set_mtu(0, MIN(lcp_allowoptions[0].mru, PPP_MRU));
104     if (ppp_send_config(0, PPP_MRU, (u_int32_t) 0, 0, 0) < 0
105 	|| ppp_recv_config(0, PPP_MRU, (u_int32_t) 0, 0, 0) < 0)
106 	    fatal("Couldn't set up demand-dialled PPP interface: %m");
107 
108 #ifdef PPP_WITH_FILTER
109     set_filters(&pass_filter_in, &pass_filter_out,
110 		&active_filter_in, &active_filter_out);
111 #endif
112 
113     /*
114      * Call the demand_conf procedure for each protocol that's got one.
115      */
116     for (i = 0; (protp = protocols[i]) != NULL; ++i)
117 	if (protp->enabled_flag && protp->demand_conf != NULL)
118 	    if (!((*protp->demand_conf)(0)))
119 		die(1);
120 }
121 
122 
123 /*
124  * demand_block - set each network protocol to block further packets.
125  */
126 void
127 demand_block(void)
128 {
129     int i;
130     struct protent *protp;
131 
132     for (i = 0; (protp = protocols[i]) != NULL; ++i)
133 	if (protp->enabled_flag && protp->demand_conf != NULL)
134 	    sifnpmode(0, protp->protocol & ~0x8000, NPMODE_QUEUE);
135     get_loop_output();
136 }
137 
138 /*
139  * demand_discard - set each network protocol to discard packets
140  * with an error.
141  */
142 void
143 demand_discard(void)
144 {
145     struct packet *pkt, *nextpkt;
146     int i;
147     struct protent *protp;
148 
149     for (i = 0; (protp = protocols[i]) != NULL; ++i)
150 	if (protp->enabled_flag && protp->demand_conf != NULL)
151 	    sifnpmode(0, protp->protocol & ~0x8000, NPMODE_ERROR);
152     get_loop_output();
153 
154     /* discard all saved packets */
155     for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
156 	nextpkt = pkt->next;
157 	free(pkt);
158     }
159     pend_q = NULL;
160     framelen = 0;
161     flush_flag = 0;
162     escape_flag = 0;
163     fcs = PPP_INITFCS;
164 }
165 
166 /*
167  * demand_unblock - set each enabled network protocol to pass packets.
168  */
169 void
170 demand_unblock(void)
171 {
172     int i;
173     struct protent *protp;
174 
175     for (i = 0; (protp = protocols[i]) != NULL; ++i)
176 	if (protp->enabled_flag && protp->demand_conf != NULL)
177 	    sifnpmode(0, protp->protocol & ~0x8000, NPMODE_PASS);
178 }
179 
180 /*
181  * FCS lookup table as calculated by genfcstab.
182  */
183 static u_short fcstab[256] = {
184 	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
185 	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
186 	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
187 	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
188 	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
189 	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
190 	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
191 	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
192 	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
193 	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
194 	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
195 	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
196 	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
197 	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
198 	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
199 	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
200 	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
201 	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
202 	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
203 	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
204 	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
205 	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
206 	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
207 	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
208 	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
209 	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
210 	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
211 	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
212 	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
213 	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
214 	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
215 	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
216 };
217 #define PPP_FCS(fcs, c)	(((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
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_WITH_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