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