demand.c revision 1.4
1/* $OpenBSD: demand.c,v 1.4 1997/09/05 04:32:37 millert 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.6 1997/04/30 05:51:56 paulus Exp"; 25#else 26static char rcsid[] = "$OpenBSD: demand.c,v 1.4 1997/09/05 04:32:37 millert 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#include <net/if.h> 45#ifdef PPP_FILTER 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_unblock - set each enabled network protocol to pass packets. 157 */ 158void 159demand_unblock() 160{ 161 int i; 162 struct protent *protp; 163 164 for (i = 0; (protp = protocols[i]) != NULL; ++i) 165 if (protp->enabled_flag && protp->demand_conf != NULL) 166 sifnpmode(0, protp->protocol & ~0x8000, NPMODE_PASS); 167} 168 169/* 170 * FCS lookup table as calculated by genfcstab. 171 */ 172static u_short fcstab[256] = { 173 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 174 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 175 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 176 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 177 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 178 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 179 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 180 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 181 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 182 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 183 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 184 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 185 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 186 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 187 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 188 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 189 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 190 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 191 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 192 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 193 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 194 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 195 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 196 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 197 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 198 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 199 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 200 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 201 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 202 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 203 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 204 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 205}; 206 207/* 208 * loop_chars - process characters received from the loopback. 209 * Calls loop_frame when a complete frame has been accumulated. 210 * Return value is 1 if we need to bring up the link, 0 otherwise. 211 */ 212int 213loop_chars(p, n) 214 unsigned char *p; 215 int n; 216{ 217 int c, rv; 218 219 rv = 0; 220 for (; n > 0; --n) { 221 c = *p++; 222 if (c == PPP_FLAG) { 223 if (!escape_flag && !flush_flag 224 && framelen > 2 && fcs == PPP_GOODFCS) { 225 framelen -= 2; 226 if (loop_frame(frame, framelen)) 227 rv = 1; 228 } 229 framelen = 0; 230 flush_flag = 0; 231 escape_flag = 0; 232 fcs = PPP_INITFCS; 233 continue; 234 } 235 if (flush_flag) 236 continue; 237 if (escape_flag) { 238 c ^= PPP_TRANS; 239 escape_flag = 0; 240 } else if (c == PPP_ESCAPE) { 241 escape_flag = 1; 242 continue; 243 } 244 if (framelen >= framemax) { 245 flush_flag = 1; 246 continue; 247 } 248 frame[framelen++] = c; 249 fcs = PPP_FCS(fcs, c); 250 } 251 return rv; 252} 253 254/* 255 * loop_frame - given a frame obtained from the loopback, 256 * decide whether to bring up the link or not, and, if we want 257 * to transmit this frame later, put it on the pending queue. 258 * Return value is 1 if we need to bring up the link, 0 otherwise. 259 * We assume that the kernel driver has already applied the 260 * pass_filter, so we won't get packets it rejected. 261 * We apply the active_filter to see if we want this packet to 262 * bring up the link. 263 */ 264int 265loop_frame(frame, len) 266 unsigned char *frame; 267 int len; 268{ 269 struct packet *pkt; 270 271 /* log_packet(frame, len, "from loop: ", LOG_DEBUG); */ 272 if (len < PPP_HDRLEN) 273 return 0; 274 if ((PPP_PROTOCOL(frame) & 0x8000) != 0) 275 return 0; /* shouldn't get any of these anyway */ 276 if (!active_packet(frame, len)) 277 return 0; 278 279 pkt = (struct packet *) malloc(sizeof(struct packet) + len); 280 if (pkt != NULL) { 281 pkt->length = len; 282 pkt->next = NULL; 283 memcpy(pkt->data, frame, len); 284 if (pend_q == NULL) 285 pend_q = pkt; 286 else 287 pend_qtail->next = pkt; 288 pend_qtail = pkt; 289 } 290 return 1; 291} 292 293/* 294 * demand_rexmit - Resend all those frames which we got via the 295 * loopback, now that the real serial link is up. 296 */ 297void 298demand_rexmit(proto) 299 int proto; 300{ 301 struct packet *pkt, *prev, *nextpkt; 302 303 prev = NULL; 304 pkt = pend_q; 305 pend_q = NULL; 306 for (; pkt != NULL; pkt = nextpkt) { 307 nextpkt = pkt->next; 308 if (PPP_PROTOCOL(pkt->data) == proto) { 309 output(0, pkt->data, pkt->length); 310 free(pkt); 311 } else { 312 if (prev == NULL) 313 pend_q = pkt; 314 else 315 prev->next = pkt; 316 prev = pkt; 317 } 318 } 319 pend_qtail = prev; 320 if (prev != NULL) 321 prev->next = NULL; 322} 323 324/* 325 * Scan a packet to decide whether it is an "active" packet, 326 * that is, whether it is worth bringing up the link for. 327 */ 328static int 329active_packet(p, len) 330 unsigned char *p; 331 int len; 332{ 333 int proto, i; 334 struct protent *protp; 335 336 if (len < PPP_HDRLEN) 337 return 0; 338 proto = PPP_PROTOCOL(p); 339#ifdef PPP_FILTER 340 if (active_filter.bf_len != 0 341 && bpf_filter(active_filter.bf_insns, frame, len, len) == 0) 342 return 0; 343#endif 344 for (i = 0; (protp = protocols[i]) != NULL; ++i) { 345 if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) { 346 if (!protp->enabled_flag) 347 return 0; 348 if (protp->active_pkt == NULL) 349 return 1; 350 return (*protp->active_pkt)(p, len); 351 } 352 } 353 return 0; /* not a supported protocol !!?? */ 354} 355