demand.c revision 1.6
1/*	$OpenBSD: demand.c,v 1.6 1998/07/12 04:34:39 angelos 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.7 1997/11/27 06:08:26 paulus Exp $";
25#else
26static char rcsid[] = "$OpenBSD: demand.c,v 1.6 1998/07/12 04:34:39 angelos 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#ifdef PPP_FILTER
45#include <net/if.h>
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_drop - set each network protocol to discard packets
157 * without an error.
158 */
159void
160demand_drop()
161{
162    struct packet *pkt, *nextpkt;
163    int i;
164    struct protent *protp;
165
166    for (i = 0; (protp = protocols[i]) != NULL; ++i)
167        if (protp->enabled_flag && protp->demand_conf != NULL)
168            sifnpmode(0, protp->protocol & ~0x8000, NPMODE_DROP);
169    get_loop_output();
170
171    /* discard all saved packets */
172    for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
173        nextpkt = pkt->next;
174        free(pkt);
175    }
176    pend_q = NULL;
177    framelen = 0;
178    flush_flag = 0;
179    escape_flag = 0;
180    fcs = PPP_INITFCS;
181}
182
183/*
184 * demand_unblock - set each enabled network protocol to pass packets.
185 */
186void
187demand_unblock()
188{
189    int i;
190    struct protent *protp;
191
192    for (i = 0; (protp = protocols[i]) != NULL; ++i)
193	if (protp->enabled_flag && protp->demand_conf != NULL)
194	    sifnpmode(0, protp->protocol & ~0x8000, NPMODE_PASS);
195}
196
197/*
198 * FCS lookup table as calculated by genfcstab.
199 */
200static u_short fcstab[256] = {
201	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
202	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
203	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
204	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
205	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
206	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
207	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
208	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
209	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
210	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
211	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
212	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
213	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
214	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
215	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
216	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
217	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
218	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
219	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
220	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
221	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
222	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
223	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
224	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
225	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
226	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
227	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
228	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
229	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
230	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
231	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
232	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
233};
234
235/*
236 * loop_chars - process characters received from the loopback.
237 * Calls loop_frame when a complete frame has been accumulated.
238 * Return value is 1 if we need to bring up the link, 0 otherwise.
239 */
240int
241loop_chars(p, n)
242    unsigned char *p;
243    int n;
244{
245    int c, rv;
246
247    rv = 0;
248    for (; n > 0; --n) {
249	c = *p++;
250	if (c == PPP_FLAG) {
251	    if (!escape_flag && !flush_flag
252		&& framelen > 2 && fcs == PPP_GOODFCS) {
253		framelen -= 2;
254		if (loop_frame(frame, framelen))
255		    rv = 1;
256	    }
257	    framelen = 0;
258	    flush_flag = 0;
259	    escape_flag = 0;
260	    fcs = PPP_INITFCS;
261	    continue;
262	}
263	if (flush_flag)
264	    continue;
265	if (escape_flag) {
266	    c ^= PPP_TRANS;
267	    escape_flag = 0;
268	} else if (c == PPP_ESCAPE) {
269	    escape_flag = 1;
270	    continue;
271	}
272	if (framelen >= framemax) {
273	    flush_flag = 1;
274	    continue;
275	}
276	frame[framelen++] = c;
277	fcs = PPP_FCS(fcs, c);
278    }
279    return rv;
280}
281
282/*
283 * loop_frame - given a frame obtained from the loopback,
284 * decide whether to bring up the link or not, and, if we want
285 * to transmit this frame later, put it on the pending queue.
286 * Return value is 1 if we need to bring up the link, 0 otherwise.
287 * We assume that the kernel driver has already applied the
288 * pass_filter, so we won't get packets it rejected.
289 * We apply the active_filter to see if we want this packet to
290 * bring up the link.
291 */
292int
293loop_frame(frame, len)
294    unsigned char *frame;
295    int len;
296{
297    struct packet *pkt;
298
299    /* log_packet(frame, len, "from loop: ", LOG_DEBUG); */
300    if (len < PPP_HDRLEN)
301	return 0;
302    if ((PPP_PROTOCOL(frame) & 0x8000) != 0)
303	return 0;		/* shouldn't get any of these anyway */
304    if (!active_packet(frame, len))
305	return 0;
306
307    pkt = (struct packet *) malloc(sizeof(struct packet) + len);
308    if (pkt != NULL) {
309	pkt->length = len;
310	pkt->next = NULL;
311	memcpy(pkt->data, frame, len);
312	if (pend_q == NULL)
313	    pend_q = pkt;
314	else
315	    pend_qtail->next = pkt;
316	pend_qtail = pkt;
317    }
318    return 1;
319}
320
321/*
322 * demand_rexmit - Resend all those frames which we got via the
323 * loopback, now that the real serial link is up.
324 */
325void
326demand_rexmit(proto)
327    int proto;
328{
329    struct packet *pkt, *prev, *nextpkt;
330
331    prev = NULL;
332    pkt = pend_q;
333    pend_q = NULL;
334    for (; pkt != NULL; pkt = nextpkt) {
335	nextpkt = pkt->next;
336	if (PPP_PROTOCOL(pkt->data) == proto) {
337	    output(0, pkt->data, pkt->length);
338	    free(pkt);
339	} else {
340	    if (prev == NULL)
341		pend_q = pkt;
342	    else
343		prev->next = pkt;
344	    prev = pkt;
345	}
346    }
347    pend_qtail = prev;
348    if (prev != NULL)
349	prev->next = NULL;
350}
351
352/*
353 * Scan a packet to decide whether it is an "active" packet,
354 * that is, whether it is worth bringing up the link for.
355 */
356static int
357active_packet(p, len)
358    unsigned char *p;
359    int len;
360{
361    int proto, i;
362    struct protent *protp;
363
364    if (len < PPP_HDRLEN)
365	return 0;
366    proto = PPP_PROTOCOL(p);
367#ifdef PPP_FILTER
368    if (active_filter.bf_len != 0
369	&& bpf_filter(active_filter.bf_insns, frame, len, len) == 0)
370	return 0;
371#endif
372    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
373	if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
374	    if (!protp->enabled_flag)
375		return 0;
376	    if (protp->active_pkt == NULL)
377		return 1;
378	    return (*protp->active_pkt)(p, len);
379	}
380    }
381    return 0;			/* not a supported protocol !!?? */
382}
383