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