Home | History | Annotate | Line # | Download | only in pppd
      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