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