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