Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_demand.c Source File

lwip_demand.c

00001 /*
00002  * demand.c - Support routines for demand-dialling.
00003  *
00004  * Copyright (c) 1996-2002 Paul Mackerras. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *
00013  * 2. The name(s) of the authors of this software must not be used to
00014  *    endorse or promote products derived from this software without
00015  *    prior written permission.
00016  *
00017  * 3. Redistributions of any form whatsoever must retain the following
00018  *    acknowledgment:
00019  *    "This product includes software developed by Paul Mackerras
00020  *     <paulus@samba.org>".
00021  *
00022  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
00023  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00024  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
00025  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00026  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
00027  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
00028  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00029  */
00030 
00031 #include "netif/ppp/ppp_opts.h"
00032 #if PPP_SUPPORT && DEMAND_SUPPORT  /* don't build if not configured for use in lwipopts.h */
00033 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <errno.h>
00038 #include <fcntl.h>
00039 #include <netdb.h>
00040 #include <unistd.h>
00041 #include <syslog.h>
00042 #include <sys/param.h>
00043 #include <sys/types.h>
00044 #include <sys/wait.h>
00045 #include <sys/time.h>
00046 #include <sys/resource.h>
00047 #include <sys/stat.h>
00048 #include <sys/socket.h>
00049 #include <netinet/in.h>
00050 #include <arpa/inet.h>
00051 #ifdef PPP_FILTER
00052 #include <pcap-bpf.h>
00053 #endif
00054 
00055 #include "netif/ppp/ppp_impl.h"
00056 
00057 #include "netif/ppp/fsm.h"
00058 #include "netif/ppp/ipcp.h"
00059 #include "netif/ppp/lcp.h"
00060 
00061 char *frame;
00062 int framelen;
00063 int framemax;
00064 int escape_flag;
00065 int flush_flag;
00066 int fcs;
00067 
00068 struct packet {
00069     int length;
00070     struct packet *next;
00071     unsigned char data[1];
00072 };
00073 
00074 struct packet *pend_q;
00075 struct packet *pend_qtail;
00076 
00077 static int active_packet (unsigned char *, int);
00078 
00079 /*
00080  * demand_conf - configure the interface for doing dial-on-demand.
00081  */
00082 void
00083 demand_conf()
00084 {
00085     int i;
00086     const struct protent *protp;
00087 
00088 /*    framemax = lcp_allowoptions[0].mru;
00089     if (framemax < PPP_MRU) */
00090     framemax = PPP_MRU;
00091     framemax += PPP_HDRLEN + PPP_FCSLEN;
00092     frame = malloc(framemax);
00093     if (frame == NULL)
00094     novm("demand frame");
00095     framelen = 0;
00096     pend_q = NULL;
00097     escape_flag = 0;
00098     flush_flag = 0;
00099     fcs = PPP_INITFCS;
00100 
00101     netif_set_mtu(pcb, LWIP_MIN(lcp_allowoptions[0].mru, PPP_MRU));
00102     if (ppp_send_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0
00103     || ppp_recv_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0)
00104         fatal("Couldn't set up demand-dialled PPP interface: %m");
00105 
00106 #ifdef PPP_FILTER
00107     set_filters(&pass_filter, &active_filter);
00108 #endif
00109 
00110     /*
00111      * Call the demand_conf procedure for each protocol that's got one.
00112      */
00113     for (i = 0; (protp = protocols[i]) != NULL; ++i)
00114     if (protp->demand_conf != NULL)
00115         ((*protp->demand_conf)(pcb));
00116 /* FIXME: find a way to die() here */
00117 #if 0
00118         if (!((*protp->demand_conf)(pcb)))
00119         die(1);
00120 #endif
00121 }
00122 
00123 
00124 /*
00125  * demand_block - set each network protocol to block further packets.
00126  */
00127 void
00128 demand_block()
00129 {
00130     int i;
00131     const struct protent *protp;
00132 
00133     for (i = 0; (protp = protocols[i]) != NULL; ++i)
00134     if (protp->demand_conf != NULL)
00135         sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_QUEUE);
00136     get_loop_output();
00137 }
00138 
00139 /*
00140  * demand_discard - set each network protocol to discard packets
00141  * with an error.
00142  */
00143 void
00144 demand_discard()
00145 {
00146     struct packet *pkt, *nextpkt;
00147     int i;
00148     const struct protent *protp;
00149 
00150     for (i = 0; (protp = protocols[i]) != NULL; ++i)
00151     if (protp->demand_conf != NULL)
00152         sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_ERROR);
00153     get_loop_output();
00154 
00155     /* discard all saved packets */
00156     for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
00157     nextpkt = pkt->next;
00158     free(pkt);
00159     }
00160     pend_q = NULL;
00161     framelen = 0;
00162     flush_flag = 0;
00163     escape_flag = 0;
00164     fcs = PPP_INITFCS;
00165 }
00166 
00167 /*
00168  * demand_unblock - set each enabled network protocol to pass packets.
00169  */
00170 void
00171 demand_unblock()
00172 {
00173     int i;
00174     const struct protent *protp;
00175 
00176     for (i = 0; (protp = protocols[i]) != NULL; ++i)
00177     if (protp->demand_conf != NULL)
00178         sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_PASS);
00179 }
00180 
00181 /*
00182  * FCS lookup table as calculated by genfcstab.
00183  */
00184 static u_short fcstab[256] = {
00185     0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
00186     0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
00187     0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
00188     0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
00189     0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
00190     0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
00191     0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
00192     0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
00193     0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
00194     0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
00195     0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
00196     0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
00197     0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
00198     0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
00199     0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
00200     0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
00201     0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
00202     0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
00203     0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
00204     0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
00205     0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
00206     0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
00207     0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
00208     0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
00209     0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
00210     0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
00211     0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
00212     0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
00213     0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
00214     0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
00215     0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
00216     0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
00217 };
00218 
00219 /*
00220  * loop_chars - process characters received from the loopback.
00221  * Calls loop_frame when a complete frame has been accumulated.
00222  * Return value is 1 if we need to bring up the link, 0 otherwise.
00223  */
00224 int
00225 loop_chars(p, n)
00226     unsigned char *p;
00227     int n;
00228 {
00229     int c, rv;
00230 
00231     rv = 0;
00232 
00233 /* check for synchronous connection... */
00234 
00235     if ( (p[0] == 0xFF) && (p[1] == 0x03) ) {
00236         rv = loop_frame(p,n);
00237         return rv;
00238     }
00239 
00240     for (; n > 0; --n) {
00241     c = *p++;
00242     if (c == PPP_FLAG) {
00243         if (!escape_flag && !flush_flag
00244         && framelen > 2 && fcs == PPP_GOODFCS) {
00245         framelen -= 2;
00246         if (loop_frame((unsigned char *)frame, framelen))
00247             rv = 1;
00248         }
00249         framelen = 0;
00250         flush_flag = 0;
00251         escape_flag = 0;
00252         fcs = PPP_INITFCS;
00253         continue;
00254     }
00255     if (flush_flag)
00256         continue;
00257     if (escape_flag) {
00258         c ^= PPP_TRANS;
00259         escape_flag = 0;
00260     } else if (c == PPP_ESCAPE) {
00261         escape_flag = 1;
00262         continue;
00263     }
00264     if (framelen >= framemax) {
00265         flush_flag = 1;
00266         continue;
00267     }
00268     frame[framelen++] = c;
00269     fcs = PPP_FCS(fcs, c);
00270     }
00271     return rv;
00272 }
00273 
00274 /*
00275  * loop_frame - given a frame obtained from the loopback,
00276  * decide whether to bring up the link or not, and, if we want
00277  * to transmit this frame later, put it on the pending queue.
00278  * Return value is 1 if we need to bring up the link, 0 otherwise.
00279  * We assume that the kernel driver has already applied the
00280  * pass_filter, so we won't get packets it rejected.
00281  * We apply the active_filter to see if we want this packet to
00282  * bring up the link.
00283  */
00284 int
00285 loop_frame(frame, len)
00286     unsigned char *frame;
00287     int len;
00288 {
00289     struct packet *pkt;
00290 
00291     /* dbglog("from loop: %P", frame, len); */
00292     if (len < PPP_HDRLEN)
00293     return 0;
00294     if ((PPP_PROTOCOL(frame) & 0x8000) != 0)
00295     return 0;       /* shouldn't get any of these anyway */
00296     if (!active_packet(frame, len))
00297     return 0;
00298 
00299     pkt = (struct packet *) malloc(sizeof(struct packet) + len);
00300     if (pkt != NULL) {
00301     pkt->length = len;
00302     pkt->next = NULL;
00303     memcpy(pkt->data, frame, len);
00304     if (pend_q == NULL)
00305         pend_q = pkt;
00306     else
00307         pend_qtail->next = pkt;
00308     pend_qtail = pkt;
00309     }
00310     return 1;
00311 }
00312 
00313 /*
00314  * demand_rexmit - Resend all those frames which we got via the
00315  * loopback, now that the real serial link is up.
00316  */
00317 void
00318 demand_rexmit(proto, newip)
00319     int proto;
00320     u32_t newip;
00321 {
00322     struct packet *pkt, *prev, *nextpkt;
00323     unsigned short checksum;
00324     unsigned short pkt_checksum = 0;
00325     unsigned iphdr;
00326     struct timeval tv;
00327     char cv = 0;
00328     char ipstr[16];
00329 
00330     prev = NULL;
00331     pkt = pend_q;
00332     pend_q = NULL;
00333     tv.tv_sec = 1;
00334     tv.tv_usec = 0;
00335     select(0,NULL,NULL,NULL,&tv);   /* Sleep for 1 Seconds */
00336     for (; pkt != NULL; pkt = nextpkt) {
00337     nextpkt = pkt->next;
00338     if (PPP_PROTOCOL(pkt->data) == proto) {
00339             if ( (proto == PPP_IP) && newip ) {
00340         /* Get old checksum */
00341 
00342         iphdr = (pkt->data[4] & 15) << 2;
00343         checksum = *((unsigned short *) (pkt->data+14));
00344                 if (checksum == 0xFFFF) {
00345                     checksum = 0;
00346                 }
00347 
00348  
00349                 if (pkt->data[13] == 17) {
00350                     pkt_checksum =  *((unsigned short *) (pkt->data+10+iphdr));
00351             if (pkt_checksum) {
00352                         cv = 1;
00353                         if (pkt_checksum == 0xFFFF) {
00354                             pkt_checksum = 0;
00355                         }
00356                     }
00357                     else {
00358                        cv = 0;
00359                     }
00360                 }
00361 
00362         if (pkt->data[13] == 6) {
00363             pkt_checksum = *((unsigned short *) (pkt->data+20+iphdr));
00364             cv = 1;
00365                     if (pkt_checksum == 0xFFFF) {
00366                         pkt_checksum = 0;
00367                     }
00368         }
00369 
00370         /* Delete old Source-IP-Address */
00371                 checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
00372                 checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
00373 
00374         pkt_checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
00375         pkt_checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
00376 
00377         /* Change Source-IP-Address */
00378                 * ((u32_t *) (pkt->data + 16)) = newip;
00379 
00380         /* Add new Source-IP-Address */
00381                 checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
00382                 checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
00383 
00384                 pkt_checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
00385                 pkt_checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
00386 
00387         /* Write new checksum */
00388                 if (!checksum) {
00389                     checksum = 0xFFFF;
00390                 }
00391                 *((unsigned short *) (pkt->data+14)) = checksum;
00392         if (pkt->data[13] == 6) {
00393             *((unsigned short *) (pkt->data+20+iphdr)) = pkt_checksum;
00394         }
00395         if (cv && (pkt->data[13] == 17) ) {
00396             *((unsigned short *) (pkt->data+10+iphdr)) = pkt_checksum;
00397         }
00398 
00399         /* Log Packet */
00400         strcpy(ipstr,inet_ntoa(*( (struct in_addr *) (pkt->data+16))));
00401         if (pkt->data[13] == 1) {
00402             syslog(LOG_INFO,"Open ICMP %s -> %s\n",
00403             ipstr,
00404             inet_ntoa(*( (struct in_addr *) (pkt->data+20))));
00405         } else {
00406             syslog(LOG_INFO,"Open %s %s:%d -> %s:%d\n",
00407             pkt->data[13] == 6 ? "TCP" : "UDP",
00408             ipstr,
00409             ntohs(*( (short *) (pkt->data+iphdr+4))),
00410             inet_ntoa(*( (struct in_addr *) (pkt->data+20))),
00411             ntohs(*( (short *) (pkt->data+iphdr+6))));
00412                 }
00413             }
00414         output(pcb, pkt->data, pkt->length);
00415         free(pkt);
00416     } else {
00417         if (prev == NULL)
00418         pend_q = pkt;
00419         else
00420         prev->next = pkt;
00421         prev = pkt;
00422     }
00423     }
00424     pend_qtail = prev;
00425     if (prev != NULL)
00426     prev->next = NULL;
00427 }
00428 
00429 /*
00430  * Scan a packet to decide whether it is an "active" packet,
00431  * that is, whether it is worth bringing up the link for.
00432  */
00433 static int
00434 active_packet(p, len)
00435     unsigned char *p;
00436     int len;
00437 {
00438     int proto, i;
00439     const struct protent *protp;
00440 
00441     if (len < PPP_HDRLEN)
00442     return 0;
00443     proto = PPP_PROTOCOL(p);
00444 #ifdef PPP_FILTER
00445     p[0] = 1;       /* outbound packet indicator */
00446     if ((pass_filter.bf_len != 0
00447      && bpf_filter(pass_filter.bf_insns, p, len, len) == 0)
00448     || (active_filter.bf_len != 0
00449         && bpf_filter(active_filter.bf_insns, p, len, len) == 0)) {
00450     p[0] = 0xff;
00451     return 0;
00452     }
00453     p[0] = 0xff;
00454 #endif
00455     for (i = 0; (protp = protocols[i]) != NULL; ++i) {
00456     if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
00457         if (protp->active_pkt == NULL)
00458         return 1;
00459         return (*protp->active_pkt)(p, len);
00460     }
00461     }
00462     return 0;           /* not a supported protocol !!?? */
00463 }
00464 
00465 #endif /* PPP_SUPPORT && DEMAND_SUPPORT */