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