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