The Pedigree Project  0.1
demand.c
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 
61 char *frame;
62 int framelen;
63 int framemax;
64 int escape_flag;
65 int flush_flag;
66 int fcs;
67 
68 struct packet {
69  int length;
70  struct packet *next;
71  unsigned char data[1];
72 };
73 
74 struct packet *pend_q;
75 struct packet *pend_qtail;
76 
77 static int active_packet (unsigned char *, int);
78 
79 /*
80  * demand_conf - configure the interface for doing dial-on-demand.
81  */
82 void
83 demand_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  */
127 void
128 demand_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  */
143 void
144 demand_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  */
170 void
171 demand_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  */
184 static 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  */
224 int
225 loop_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  */
284 int
285 loop_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  */
317 void
318 demand_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  */
433 static int
434 active_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 */
Definition: inet.h:77