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 "
36static 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
64char *frame;
65int framelen;
66int framemax;
67int escape_flag;
68int flush_flag;
69int fcs;
70
71struct packet {
72    int length;
73    struct packet *next;
74    unsigned char data[1];
75};
76
77struct packet *pend_q;
78struct packet *pend_qtail;
79
80static int active_packet(unsigned char *, int);
81
82/*
83 * demand_conf - configure the interface for doing dial-on-demand.
84 */
85void
86demand_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 */
127void
128demand_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 */
143void
144demand_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 */
170void
171demand_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 */
184static 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 */
224int
225loop_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 */
274int
275loop_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 */
305void
306demand_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 */
335static int
336active_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