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