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