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