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