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