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