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