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#include "netif/ppp/ppp_opts.h"
32#if PPP_SUPPORT && DEMAND_SUPPORT  /* don't build if not configured for use in lwipopts.h */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <errno.h>
38#include <fcntl.h>
39#include <netdb.h>
40#include <unistd.h>
41#include <syslog.h>
42#include <sys/param.h>
43#include <sys/types.h>
44#include <sys/wait.h>
45#include <sys/time.h>
46#include <sys/resource.h>
47#include <sys/stat.h>
48#include <sys/socket.h>
49#include <netinet/in.h>
50#include <arpa/inet.h>
51#ifdef PPP_FILTER
52#include <pcap-bpf.h>
53#endif
54
55#include "netif/ppp/ppp_impl.h"
56
57#include "netif/ppp/fsm.h"
58#include "netif/ppp/ipcp.h"
59#include "netif/ppp/lcp.h"
60
61char *frame;
62int framelen;
63int framemax;
64int escape_flag;
65int flush_flag;
66int fcs;
67
68struct packet {
69    int length;
70    struct packet *next;
71    unsigned char data[1];
72};
73
74struct packet *pend_q;
75struct packet *pend_qtail;
76
77static int active_packet (unsigned char *, int);
78
79/*
80 * demand_conf - configure the interface for doing dial-on-demand.
81 */
82void
83demand_conf()
84{
85    int i;
86    const struct protent *protp;
87
88/*    framemax = lcp_allowoptions[0].mru;
89    if (framemax < PPP_MRU) */
90	framemax = PPP_MRU;
91    framemax += PPP_HDRLEN + PPP_FCSLEN;
92    frame = malloc(framemax);
93    if (frame == NULL)
94	novm("demand frame");
95    framelen = 0;
96    pend_q = NULL;
97    escape_flag = 0;
98    flush_flag = 0;
99    fcs = PPP_INITFCS;
100
101    netif_set_mtu(pcb, LWIP_MIN(lcp_allowoptions[0].mru, PPP_MRU));
102    if (ppp_send_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0
103	|| ppp_recv_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0)
104	    fatal("Couldn't set up demand-dialled PPP interface: %m");
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->demand_conf != NULL)
115	    ((*protp->demand_conf)(pcb));
116/* FIXME: find a way to die() here */
117#if 0
118	    if (!((*protp->demand_conf)(pcb)))
119		die(1);
120#endif
121}
122
123
124/*
125 * demand_block - set each network protocol to block further packets.
126 */
127void
128demand_block()
129{
130    int i;
131    const struct protent *protp;
132
133    for (i = 0; (protp = protocols[i]) != NULL; ++i)
134	if (protp->demand_conf != NULL)
135	    sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_QUEUE);
136    get_loop_output();
137}
138
139/*
140 * demand_discard - set each network protocol to discard packets
141 * with an error.
142 */
143void
144demand_discard()
145{
146    struct packet *pkt, *nextpkt;
147    int i;
148    const struct protent *protp;
149
150    for (i = 0; (protp = protocols[i]) != NULL; ++i)
151	if (protp->demand_conf != NULL)
152	    sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_ERROR);
153    get_loop_output();
154
155    /* discard all saved packets */
156    for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
157	nextpkt = pkt->next;
158	free(pkt);
159    }
160    pend_q = NULL;
161    framelen = 0;
162    flush_flag = 0;
163    escape_flag = 0;
164    fcs = PPP_INITFCS;
165}
166
167/*
168 * demand_unblock - set each enabled network protocol to pass packets.
169 */
170void
171demand_unblock()
172{
173    int i;
174    const struct protent *protp;
175
176    for (i = 0; (protp = protocols[i]) != NULL; ++i)
177	if (protp->demand_conf != NULL)
178	    sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_PASS);
179}
180
181/*
182 * FCS lookup table as calculated by genfcstab.
183 */
184static u_short fcstab[256] = {
185	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
186	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
187	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
188	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
189	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
190	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
191	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
192	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
193	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
194	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
195	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
196	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
197	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
198	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
199	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
200	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
201	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
202	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
203	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
204	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
205	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
206	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
207	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
208	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
209	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
210	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
211	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
212	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
213	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
214	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
215	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
216	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
217};
218
219/*
220 * loop_chars - process characters received from the loopback.
221 * Calls loop_frame when a complete frame has been accumulated.
222 * Return value is 1 if we need to bring up the link, 0 otherwise.
223 */
224int
225loop_chars(p, n)
226    unsigned char *p;
227    int n;
228{
229    int c, rv;
230
231    rv = 0;
232
233/* check for synchronous connection... */
234
235    if ( (p[0] == 0xFF) && (p[1] == 0x03) ) {
236        rv = loop_frame(p,n);
237        return rv;
238    }
239
240    for (; n > 0; --n) {
241	c = *p++;
242	if (c == PPP_FLAG) {
243	    if (!escape_flag && !flush_flag
244		&& framelen > 2 && fcs == PPP_GOODFCS) {
245		framelen -= 2;
246		if (loop_frame((unsigned char *)frame, framelen))
247		    rv = 1;
248	    }
249	    framelen = 0;
250	    flush_flag = 0;
251	    escape_flag = 0;
252	    fcs = PPP_INITFCS;
253	    continue;
254	}
255	if (flush_flag)
256	    continue;
257	if (escape_flag) {
258	    c ^= PPP_TRANS;
259	    escape_flag = 0;
260	} else if (c == PPP_ESCAPE) {
261	    escape_flag = 1;
262	    continue;
263	}
264	if (framelen >= framemax) {
265	    flush_flag = 1;
266	    continue;
267	}
268	frame[framelen++] = c;
269	fcs = PPP_FCS(fcs, c);
270    }
271    return rv;
272}
273
274/*
275 * loop_frame - given a frame obtained from the loopback,
276 * decide whether to bring up the link or not, and, if we want
277 * to transmit this frame later, put it on the pending queue.
278 * Return value is 1 if we need to bring up the link, 0 otherwise.
279 * We assume that the kernel driver has already applied the
280 * pass_filter, so we won't get packets it rejected.
281 * We apply the active_filter to see if we want this packet to
282 * bring up the link.
283 */
284int
285loop_frame(frame, len)
286    unsigned char *frame;
287    int len;
288{
289    struct packet *pkt;
290
291    /* dbglog("from loop: %P", frame, len); */
292    if (len < PPP_HDRLEN)
293	return 0;
294    if ((PPP_PROTOCOL(frame) & 0x8000) != 0)
295	return 0;		/* shouldn't get any of these anyway */
296    if (!active_packet(frame, len))
297	return 0;
298
299    pkt = (struct packet *) malloc(sizeof(struct packet) + len);
300    if (pkt != NULL) {
301	pkt->length = len;
302	pkt->next = NULL;
303	memcpy(pkt->data, frame, len);
304	if (pend_q == NULL)
305	    pend_q = pkt;
306	else
307	    pend_qtail->next = pkt;
308	pend_qtail = pkt;
309    }
310    return 1;
311}
312
313/*
314 * demand_rexmit - Resend all those frames which we got via the
315 * loopback, now that the real serial link is up.
316 */
317void
318demand_rexmit(proto, newip)
319    int proto;
320    u32_t newip;
321{
322    struct packet *pkt, *prev, *nextpkt;
323    unsigned short checksum;
324    unsigned short pkt_checksum = 0;
325    unsigned iphdr;
326    struct timeval tv;
327    char cv = 0;
328    char ipstr[16];
329
330    prev = NULL;
331    pkt = pend_q;
332    pend_q = NULL;
333    tv.tv_sec = 1;
334    tv.tv_usec = 0;
335    select(0,NULL,NULL,NULL,&tv);	/* Sleep for 1 Seconds */
336    for (; pkt != NULL; pkt = nextpkt) {
337	nextpkt = pkt->next;
338	if (PPP_PROTOCOL(pkt->data) == proto) {
339            if ( (proto == PPP_IP) && newip ) {
340		/* Get old checksum */
341
342		iphdr = (pkt->data[4] & 15) << 2;
343		checksum = *((unsigned short *) (pkt->data+14));
344                if (checksum == 0xFFFF) {
345                    checksum = 0;
346                }
347
348
349                if (pkt->data[13] == 17) {
350                    pkt_checksum =  *((unsigned short *) (pkt->data+10+iphdr));
351		    if (pkt_checksum) {
352                        cv = 1;
353                        if (pkt_checksum == 0xFFFF) {
354                            pkt_checksum = 0;
355                        }
356                    }
357                    else {
358                       cv = 0;
359                    }
360                }
361
362		if (pkt->data[13] == 6) {
363		    pkt_checksum = *((unsigned short *) (pkt->data+20+iphdr));
364		    cv = 1;
365                    if (pkt_checksum == 0xFFFF) {
366                        pkt_checksum = 0;
367                    }
368		}
369
370		/* Delete old Source-IP-Address */
371                checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
372                checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
373
374		pkt_checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
375		pkt_checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
376
377		/* Change Source-IP-Address */
378                * ((u32_t *) (pkt->data + 16)) = newip;
379
380		/* Add new Source-IP-Address */
381                checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
382                checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
383
384                pkt_checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
385                pkt_checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
386
387		/* Write new checksum */
388                if (!checksum) {
389                    checksum = 0xFFFF;
390                }
391                *((unsigned short *) (pkt->data+14)) = checksum;
392		if (pkt->data[13] == 6) {
393		    *((unsigned short *) (pkt->data+20+iphdr)) = pkt_checksum;
394		}
395		if (cv && (pkt->data[13] == 17) ) {
396		    *((unsigned short *) (pkt->data+10+iphdr)) = pkt_checksum;
397		}
398
399		/* Log Packet */
400		strcpy(ipstr,inet_ntoa(*( (struct in_addr *) (pkt->data+16))));
401		if (pkt->data[13] == 1) {
402		    syslog(LOG_INFO,"Open ICMP %s -> %s\n",
403			ipstr,
404			inet_ntoa(*( (struct in_addr *) (pkt->data+20))));
405		} else {
406		    syslog(LOG_INFO,"Open %s %s:%d -> %s:%d\n",
407			pkt->data[13] == 6 ? "TCP" : "UDP",
408			ipstr,
409			ntohs(*( (short *) (pkt->data+iphdr+4))),
410			inet_ntoa(*( (struct in_addr *) (pkt->data+20))),
411			ntohs(*( (short *) (pkt->data+iphdr+6))));
412                }
413            }
414	    output(pcb, pkt->data, pkt->length);
415	    free(pkt);
416	} else {
417	    if (prev == NULL)
418		pend_q = pkt;
419	    else
420		prev->next = pkt;
421	    prev = pkt;
422	}
423    }
424    pend_qtail = prev;
425    if (prev != NULL)
426	prev->next = NULL;
427}
428
429/*
430 * Scan a packet to decide whether it is an "active" packet,
431 * that is, whether it is worth bringing up the link for.
432 */
433static int
434active_packet(p, len)
435    unsigned char *p;
436    int len;
437{
438    int proto, i;
439    const struct protent *protp;
440
441    if (len < PPP_HDRLEN)
442	return 0;
443    proto = PPP_PROTOCOL(p);
444#ifdef PPP_FILTER
445    p[0] = 1;		/* outbound packet indicator */
446    if ((pass_filter.bf_len != 0
447	 && bpf_filter(pass_filter.bf_insns, p, len, len) == 0)
448	|| (active_filter.bf_len != 0
449	    && bpf_filter(active_filter.bf_insns, p, len, len) == 0)) {
450	p[0] = 0xff;
451	return 0;
452    }
453    p[0] = 0xff;
454#endif
455    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
456	if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
457	    if (protp->active_pkt == NULL)
458		return 1;
459	    return (*protp->active_pkt)(p, len);
460	}
461    }
462    return 0;			/* not a supported protocol !!?? */
463}
464
465#endif /* PPP_SUPPORT && DEMAND_SUPPORT */
466