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