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