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