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