1 /* $NetBSD: demand.c,v 1.6 2025/01/08 19:59:39 christos Exp $ */ 2 3 /* 4 * demand.c - Support routines for demand-dialling. 5 * 6 * Copyright (c) 1996-2024 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 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 21 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 22 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 23 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 24 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 25 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 26 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 27 */ 28 29 #include <sys/cdefs.h> 30 __RCSID("$NetBSD: demand.c,v 1.6 2025/01/08 19:59:39 christos Exp $"); 31 32 #ifdef HAVE_CONFIG_H 33 #include "config.h" 34 #endif 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <netdb.h> 42 #include <sys/param.h> 43 #include <sys/types.h> 44 #include <sys/wait.h> 45 #include <sys/time.h> 46 #include <sys/resource.h> 47 #include <sys/stat.h> 48 #include <sys/socket.h> 49 #ifdef PPP_WITH_FILTER 50 #ifdef __NetBSD__ 51 #include <pcap.h> 52 #else 53 #include <pcap-bpf.h> 54 #endif 55 #endif 56 57 #include "pppd-private.h" 58 #include "fsm.h" 59 #include "ipcp.h" 60 #include "lcp.h" 61 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(void) 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_set_mtu(0, MIN(lcp_allowoptions[0].mru, PPP_MRU)); 104 if (ppp_send_config(0, PPP_MRU, (u_int32_t) 0, 0, 0) < 0 105 || ppp_recv_config(0, PPP_MRU, (u_int32_t) 0, 0, 0) < 0) 106 fatal("Couldn't set up demand-dialled PPP interface: %m"); 107 108 #ifdef PPP_WITH_FILTER 109 set_filters(&pass_filter_in, &pass_filter_out, 110 &active_filter_in, &active_filter_out); 111 #endif 112 113 /* 114 * Call the demand_conf procedure for each protocol that's got one. 115 */ 116 for (i = 0; (protp = protocols[i]) != NULL; ++i) 117 if (protp->enabled_flag && protp->demand_conf != NULL) 118 if (!((*protp->demand_conf)(0))) 119 die(1); 120 } 121 122 123 /* 124 * demand_block - set each network protocol to block further packets. 125 */ 126 void 127 demand_block(void) 128 { 129 int i; 130 struct protent *protp; 131 132 for (i = 0; (protp = protocols[i]) != NULL; ++i) 133 if (protp->enabled_flag && protp->demand_conf != NULL) 134 sifnpmode(0, protp->protocol & ~0x8000, NPMODE_QUEUE); 135 get_loop_output(); 136 } 137 138 /* 139 * demand_discard - set each network protocol to discard packets 140 * with an error. 141 */ 142 void 143 demand_discard(void) 144 { 145 struct packet *pkt, *nextpkt; 146 int i; 147 struct protent *protp; 148 149 for (i = 0; (protp = protocols[i]) != NULL; ++i) 150 if (protp->enabled_flag && protp->demand_conf != NULL) 151 sifnpmode(0, protp->protocol & ~0x8000, NPMODE_ERROR); 152 get_loop_output(); 153 154 /* discard all saved packets */ 155 for (pkt = pend_q; pkt != NULL; pkt = nextpkt) { 156 nextpkt = pkt->next; 157 free(pkt); 158 } 159 pend_q = NULL; 160 framelen = 0; 161 flush_flag = 0; 162 escape_flag = 0; 163 fcs = PPP_INITFCS; 164 } 165 166 /* 167 * demand_unblock - set each enabled network protocol to pass packets. 168 */ 169 void 170 demand_unblock(void) 171 { 172 int i; 173 struct protent *protp; 174 175 for (i = 0; (protp = protocols[i]) != NULL; ++i) 176 if (protp->enabled_flag && protp->demand_conf != NULL) 177 sifnpmode(0, protp->protocol & ~0x8000, NPMODE_PASS); 178 } 179 180 /* 181 * FCS lookup table as calculated by genfcstab. 182 */ 183 static u_short fcstab[256] = { 184 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 185 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 186 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 187 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 188 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 189 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 190 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 191 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 192 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 193 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 194 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 195 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 196 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 197 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 198 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 199 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 200 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 201 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 202 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 203 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 204 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 205 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 206 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 207 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 208 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 209 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 210 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 211 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 212 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 213 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 214 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 215 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 216 }; 217 #define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) 218 219 /* 220 * loop_chars - process characters received from the loopback. 221 * Calls loop_frame when a complete frame has been accumulated. 222 * Return value is 1 if we need to bring up the link, 0 otherwise. 223 */ 224 int 225 loop_chars(unsigned char *p, int n) 226 { 227 int c, rv; 228 229 rv = 0; 230 for (; n > 0; --n) { 231 c = *p++; 232 if (c == PPP_FLAG) { 233 if (!escape_flag && !flush_flag 234 && framelen > 2 && fcs == PPP_GOODFCS) { 235 framelen -= 2; 236 if (loop_frame((unsigned char *)frame, framelen)) 237 rv = 1; 238 } 239 framelen = 0; 240 flush_flag = 0; 241 escape_flag = 0; 242 fcs = PPP_INITFCS; 243 continue; 244 } 245 if (flush_flag) 246 continue; 247 if (escape_flag) { 248 c ^= PPP_TRANS; 249 escape_flag = 0; 250 } else if (c == PPP_ESCAPE) { 251 escape_flag = 1; 252 continue; 253 } 254 if (framelen >= framemax) { 255 flush_flag = 1; 256 continue; 257 } 258 frame[framelen++] = c; 259 fcs = PPP_FCS(fcs, c); 260 } 261 return rv; 262 } 263 264 /* 265 * loop_frame - given a frame obtained from the loopback, 266 * decide whether to bring up the link or not, and, if we want 267 * to transmit this frame later, put it on the pending queue. 268 * Return value is 1 if we need to bring up the link, 0 otherwise. 269 * We assume that the kernel driver has already applied the 270 * pass_filter, so we won't get packets it rejected. 271 * We apply the active_filter to see if we want this packet to 272 * bring up the link. 273 */ 274 int 275 loop_frame(unsigned char *frame, int len) 276 { 277 struct packet *pkt; 278 279 /* dbglog("from loop: %P", frame, len); */ 280 if (len < PPP_HDRLEN) 281 return 0; 282 if ((PPP_PROTOCOL(frame) & 0x8000) != 0) 283 return 0; /* shouldn't get any of these anyway */ 284 if (!active_packet(frame, len)) 285 return 0; 286 287 pkt = (struct packet *) malloc(sizeof(struct packet) + len); 288 if (pkt != NULL) { 289 pkt->length = len; 290 pkt->next = NULL; 291 memcpy(pkt->data, frame, len); 292 if (pend_q == NULL) 293 pend_q = pkt; 294 else 295 pend_qtail->next = pkt; 296 pend_qtail = pkt; 297 } 298 return 1; 299 } 300 301 /* 302 * demand_rexmit - Resend all those frames which we got via the 303 * loopback, now that the real serial link is up. 304 */ 305 void 306 demand_rexmit(int proto) 307 { 308 struct packet *pkt, *prev, *nextpkt; 309 310 prev = NULL; 311 pkt = pend_q; 312 pend_q = NULL; 313 for (; pkt != NULL; pkt = nextpkt) { 314 nextpkt = pkt->next; 315 if (PPP_PROTOCOL(pkt->data) == proto) { 316 output(0, pkt->data, pkt->length); 317 free(pkt); 318 } else { 319 if (prev == NULL) 320 pend_q = pkt; 321 else 322 prev->next = pkt; 323 prev = pkt; 324 } 325 } 326 pend_qtail = prev; 327 if (prev != NULL) 328 prev->next = NULL; 329 } 330 331 /* 332 * Scan a packet to decide whether it is an "active" packet, 333 * that is, whether it is worth bringing up the link for. 334 */ 335 static int 336 active_packet(unsigned char *p, int len) 337 { 338 int proto, i; 339 struct protent *protp; 340 341 if (len < PPP_HDRLEN) 342 return 0; 343 proto = PPP_PROTOCOL(p); 344 #ifdef PPP_WITH_FILTER 345 p[0] = 1; /* outbound packet indicator */ 346 if ((pass_filter_out.bf_len != 0 347 && bpf_filter(pass_filter_out.bf_insns, p, len, len) == 0) 348 || (active_filter_out.bf_len != 0 349 && bpf_filter(active_filter_out.bf_insns, p, len, len) == 0)) { 350 p[0] = 0xff; 351 return 0; 352 } 353 p[0] = 0xff; 354 #endif 355 for (i = 0; (protp = protocols[i]) != NULL; ++i) { 356 if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) { 357 if (!protp->enabled_flag) 358 return 0; 359 if (protp->active_pkt == NULL) 360 return 1; 361 return (*protp->active_pkt)(p, len); 362 } 363 } 364 return 0; /* not a supported protocol !!?? */ 365 } 366