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