ipcpin.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2004 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  * -
00033  * Portions are 
00034  * Copyright (c) 1989 by Carnegie Mellon University.
00035  * All rights reserved.
00036  *
00037  * Redistribution and use in source and binary forms are permitted
00038  * provided that the above copyright notice and this paragraph are
00039  * duplicated in all such forms and that any documentation,
00040  * advertising materials, and other materials related to such
00041  * distribution and use acknowledge that the software was developed
00042  * by Carnegie Mellon University.  The name of the
00043  * University may not be used to endorse or promote products derived
00044  * from this software without specific prior written permission.
00045  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
00046  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
00047  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00048  */
00049 
00050 /*
00051  * $Log: ipcpin.c,v $
00052  * Revision 1.7  2005/04/08 15:20:50  olereinhardt
00053  * added <sys/types.h> (__APPLE__) and <netinet/in.h> (__linux__)
00054  * for htons and simmilar.
00055  *
00056  * Revision 1.6  2004/03/08 11:24:48  haraldkipp
00057  * PppUp() replaced by direct post.
00058  *
00059  * Revision 1.5  2004/01/30 11:36:52  haraldkipp
00060  * Memory hole fixed
00061  *
00062  * Revision 1.4  2003/12/18 20:44:11  drsung
00063  * Bug fix in IpcpRxConfReq. Thanks to Michel Hendriks.
00064  *
00065  * Revision 1.3  2003/08/14 15:17:50  haraldkipp
00066  * Caller controls ID increment
00067  *
00068  * Revision 1.2  2003/07/24 16:12:53  haraldkipp
00069  * First bugfix: PPP always used the secondary DNS.
00070  * Second bugfix: When the PPP server rejects the
00071  * secondary DNS, IPCP negotiation was trapped in a
00072  * loop.
00073  *
00074  * Revision 1.1.1.1  2003/05/09 14:41:30  haraldkipp
00075  * Initial using 3.2.1
00076  *
00077  * Revision 1.2  2003/05/06 18:04:57  harald
00078  * PPP IP config to DCB
00079  *
00080  * Revision 1.1  2003/03/31 14:53:27  harald
00081  * Prepare release 3.1
00082  *
00083  */
00084 
00085 #include <sys/event.h>
00086 #include <sys/types.h>
00087 #include <net/if_var.h>
00088 #include <dev/ppp.h>
00089 
00090 #include <netinet/if_ppp.h>
00091 #include <netinet/ppp_fsm.h>
00092 #include <netinet/in.h>
00097 
00098 /*
00099  * Received Configure-Request.
00100  */
00101 void IpcpRxConfReq(NUTDEVICE * dev, u_char id, NETBUF * nb)
00102 {
00103     PPPDCB *dcb = dev->dev_dcb;
00104     int rc = XCP_CONFACK;
00105     XCPOPT *xcpo;
00106     u_short xcpl;
00107     XCPOPT *xcpr;
00108     u_short xcps;
00109     u_short len = 0;
00110     u_char i;
00111 
00112     switch (dcb->dcb_ipcp_state) {
00113     case PPPS_CLOSED:
00114         /*
00115          * Go away, we're closed. 
00116          */
00117         NutNetBufFree(nb);
00118         NutIpcpOutput(dev, XCP_TERMACK, id, 0);
00119         return;
00120 
00121     case PPPS_CLOSING:
00122     case PPPS_STOPPING:
00123         /*
00124          * Ignore if we are going down.
00125          */
00126         NutNetBufFree(nb);
00127         return;
00128 
00129     case PPPS_OPENED:
00130         /* 
00131          * Go down and restart negotiation.
00132          */
00133         IpcpLowerDown(dev);
00134         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00135         break;
00136 
00137     case PPPS_STOPPED:
00138         /* 
00139          * Negotiation started by our peer.
00140          */
00141         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00142         dcb->dcb_ipcp_state = PPPS_REQSENT;
00143         break;
00144     }
00145 
00146     /*
00147      * Check if there is anything to reject.
00148      */
00149     xcpo = nb->nb_ap.vp;
00150     xcpl = nb->nb_ap.sz;
00151     xcpr = nb->nb_ap.vp;
00152     xcps = 0;
00153     while (xcpl >= 2) {
00154         len = xcpo->xcpo_len;
00155         if (len > xcpl)
00156             len = xcpl;
00157         else {
00158             switch (xcpo->xcpo_type) {
00159             case IPCP_COMPRESSTYPE:
00160                 break;
00161             case IPCP_ADDR:
00162             case IPCP_MS_DNS1:
00163             case IPCP_MS_DNS2:
00164                 if (xcpo->xcpo_len == 6)
00165                     len = 0;
00166                 break;
00167             }
00168         }
00169 
00170         if (len) {
00171             if (xcpr != xcpo) {
00172                 xcpr->xcpo_type = xcpo->xcpo_type;
00173                 xcpr->xcpo_len = len;
00174                 for (i = 0; i < len - 2; i++)
00175                     /* bug fix by Michel Hendriks. Thanks! */
00176                     xcpr->xcpo_.uc[i] = xcpo->xcpo_.uc[i];
00177             }
00178             xcpr = (XCPOPT *) ((char *) xcpr + len);
00179             xcps += len;
00180         }
00181         xcpl -= xcpo->xcpo_len;
00182         xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len);
00183     }
00184 
00185     if (xcps) {
00186         nb->nb_ap.sz = xcps;
00187         rc = XCP_CONFREJ;
00188     }
00189 
00190     /*
00191      * Check if there is anything to negotiate.
00192      */
00193     else {
00194         xcpo = nb->nb_ap.vp;
00195         xcpl = nb->nb_ap.sz;
00196         xcpr = nb->nb_ap.vp;
00197         xcps = 0;
00198         len = 0;
00199         while (xcpl >= 2) {
00200             switch (xcpo->xcpo_type) {
00201             case IPCP_ADDR:
00202                 if (xcpo->xcpo_.ul)
00203                     dcb->dcb_remote_ip = xcpo->xcpo_.ul;
00204                 else if (dcb->dcb_remote_ip == 0)
00205                     len = xcpo->xcpo_len;
00206                 break;
00207             case IPCP_COMPRESSTYPE:
00208                 len = 6;
00209                 xcpr->xcpo_.ul = 0;
00210                 break;
00211             case IPCP_MS_DNS1:
00212                 if (xcpo->xcpo_.ul)
00213                     dcb->dcb_ip_dns1 = xcpo->xcpo_.ul;
00214                 break;
00215             case IPCP_MS_DNS2:
00216                 if (xcpo->xcpo_.ul)
00217                     dcb->dcb_ip_dns2 = xcpo->xcpo_.ul;
00218                 break;
00219             }
00220 
00221             if (len) {
00222                 if (xcpr != xcpo) {
00223                     xcpr->xcpo_type = xcpo->xcpo_type;
00224                     xcpr->xcpo_len = len;
00225                 }
00226                 xcpr = (XCPOPT *) ((char *) xcpr + len);
00227                 xcps += len;
00228                 len = 0;
00229             }
00230             xcpl -= xcpo->xcpo_len;
00231             xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len);
00232         }
00233         if (xcps) {
00234             nb->nb_ap.sz = xcps;
00235             rc = XCP_CONFNAK;
00236         }
00237     }
00238 
00239     NutIpcpOutput(dev, rc, id, nb);
00240 
00241     if (rc == XCP_CONFACK) {
00242         if (dcb->dcb_ipcp_state == PPPS_ACKRCVD) {
00243             dcb->dcb_ipcp_state = PPPS_OPENED;
00244             NutEventPost(&dcb->dcb_state_chg);
00245         } else
00246             dcb->dcb_ipcp_state = PPPS_ACKSENT;
00247         dcb->dcb_ipcp_naks = 0;
00248     } else if (dcb->dcb_ipcp_state != PPPS_ACKRCVD)
00249         dcb->dcb_ipcp_state = PPPS_REQSENT;
00250 }
00251 
00252 /*
00253  * Configure-Ack received.
00254  */
00255 void IpcpRxConfAck(NUTDEVICE * dev, u_char id, NETBUF * nb)
00256 {
00257     PPPDCB *dcb = dev->dev_dcb;
00258     XCPOPT *xcpo;
00259     u_short xcpl;
00260 
00261     /*
00262      * Ignore, if we are not expecting this id.
00263      */
00264     if (id != dcb->dcb_reqid || dcb->dcb_acked) {
00265         return;
00266     }
00267 
00268     switch (dcb->dcb_ipcp_state) {
00269     case PPPS_CLOSED:
00270     case PPPS_STOPPED:
00271         /*
00272          * Go away, we're closed. 
00273          */
00274         NutNetBufFree(nb);
00275         NutIpcpOutput(dev, XCP_TERMACK, id, 0);
00276         return;
00277 
00278     case PPPS_REQSENT:
00279         dcb->dcb_ipcp_state = PPPS_ACKRCVD;
00280         dcb->dcb_retries = 0;
00281         break;
00282 
00283     case PPPS_ACKRCVD:
00284         /* Huh? an extra valid Ack? oh well... */
00285         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00286         dcb->dcb_ipcp_state = PPPS_REQSENT;
00287         break;
00288 
00289     case PPPS_ACKSENT:
00290         dcb->dcb_ipcp_state = PPPS_OPENED;
00291         dcb->dcb_retries = 0;
00292         NutEventPost(&dcb->dcb_state_chg);
00293         break;
00294 
00295     case PPPS_OPENED:
00296         /* Go down and restart negotiation */
00297         IpcpLowerDown(dev);
00298         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00299         dcb->dcb_ipcp_state = PPPS_REQSENT;
00300         break;
00301     }
00302 
00303     xcpo = nb->nb_ap.vp;
00304     xcpl = nb->nb_ap.sz;
00305     while (xcpl >= 2) {
00306         switch (xcpo->xcpo_type) {
00307         case IPCP_ADDR:
00308             if (xcpo->xcpo_.ul)
00309                 dcb->dcb_local_ip = xcpo->xcpo_.ul;
00310             break;
00311         case IPCP_COMPRESSTYPE:
00312             break;
00313         case IPCP_MS_DNS1:
00314             if (xcpo->xcpo_.ul)
00315                 dcb->dcb_ip_dns1 = xcpo->xcpo_.ul;
00316             break;
00317         case IPCP_MS_DNS2:
00318             /* Fixed secondary DNS bug, thanks to Tarmo Fimberg
00319                and Jelle Martijn Kok. */
00320             if (xcpo->xcpo_.ul)
00321                 dcb->dcb_ip_dns2 = xcpo->xcpo_.ul;
00322             break;
00323         }
00324         xcpl -= xcpo->xcpo_len;
00325         xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len);
00326     }
00327 
00328     dcb->dcb_acked = 1;
00329     NutNetBufFree(nb);
00330 }
00331 
00332 /*
00333  * Configure-Nak or Configure-Reject received.
00334  */
00335 static void IpcpRxConfNakRej(NUTDEVICE * dev, u_char id, NETBUF * nb, u_char rejected)
00336 {
00337     PPPDCB *dcb = dev->dev_dcb;
00338     XCPOPT *xcpo;
00339     u_short xcpl;
00340 
00341     /*
00342      * Ignore, if we are not expecting this id.
00343      */
00344     if (id != dcb->dcb_reqid || dcb->dcb_acked) {
00345         NutNetBufFree(nb);
00346         return;
00347     }
00348 
00349     switch (dcb->dcb_ipcp_state) {
00350     case PPPS_CLOSED:
00351     case PPPS_STOPPED:
00352         /*
00353          * Go away, we're closed. 
00354          */
00355         NutNetBufFree(nb);
00356         NutIpcpOutput(dev, XCP_TERMACK, id, 0);
00357         return;
00358 
00359     case PPPS_REQSENT:
00360     case PPPS_ACKSENT:
00361     case PPPS_ACKRCVD:
00362     case PPPS_OPENED:
00363         break;
00364 
00365     default:
00366         NutNetBufFree(nb);
00367         return;
00368     }
00369 
00370     dcb->dcb_acked = 1;
00371 
00372     xcpo = nb->nb_ap.vp;
00373     xcpl = nb->nb_ap.sz;
00374     while (xcpl >= 2) {
00375         switch (xcpo->xcpo_type) {
00376         case IPCP_ADDR:
00377             if (xcpo->xcpo_.ul)
00378                 dcb->dcb_local_ip = xcpo->xcpo_.ul;
00379             break;
00380         case IPCP_COMPRESSTYPE:
00381             break;
00382         case IPCP_MS_DNS1:
00383             if (rejected)
00384                 dcb->dcb_rejects |= REJ_IPCP_DNS1;
00385             else if (xcpo->xcpo_.ul)
00386                 dcb->dcb_ip_dns1 = xcpo->xcpo_.ul;
00387             break;
00388         case IPCP_MS_DNS2:
00389             if (rejected)
00390                 dcb->dcb_rejects |= REJ_IPCP_DNS2;
00391             else if (xcpo->xcpo_.ul)
00392                 dcb->dcb_ip_dns2 = xcpo->xcpo_.ul;
00393             break;
00394         }
00395         xcpl -= xcpo->xcpo_len;
00396         xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len);
00397     }
00398     NutNetBufFree(nb);
00399 
00400     switch (dcb->dcb_ipcp_state) {
00401 
00402     case PPPS_REQSENT:
00403     case PPPS_ACKSENT:
00404         /* They didn't agree to what we wanted - try another request */
00405         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00406         break;
00407 
00408     case PPPS_ACKRCVD:
00409         /* Got a Nak/reject when we had already had an Ack?? oh well... */
00410         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00411         dcb->dcb_ipcp_state = PPPS_REQSENT;
00412         break;
00413 
00414     case PPPS_OPENED:
00415         /* Go down and restart negotiation */
00416         IpcpLowerDown(dev);
00417         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00418         dcb->dcb_ipcp_state = PPPS_REQSENT;
00419         break;
00420     }
00421 }
00422 
00423 /*
00424  * \brief Terminate request received.
00425  */
00426 void IpcpRxTermReq(NUTDEVICE * dev, u_char id, NETBUF * nb)
00427 {
00428     PPPDCB *dcb = dev->dev_dcb;
00429 
00430     NutNetBufFree(nb);
00431     switch (dcb->dcb_ipcp_state) {
00432     case PPPS_ACKRCVD:
00433     case PPPS_ACKSENT:
00434         dcb->dcb_ipcp_state = PPPS_REQSENT;
00435         break;
00436 
00437     case PPPS_OPENED:
00438         IpcpLowerDown(dev);
00439         dcb->dcb_ipcp_state = PPPS_STOPPING;
00440         break;
00441     }
00442     NutIpcpOutput(dev, XCP_TERMACK, id, 0);
00443 }
00444 
00445 /*
00446  * Terminate-Ack received.
00447  */
00448 void IpcpRxTermAck(NUTDEVICE * dev, u_char id, NETBUF * nb)
00449 {
00450     PPPDCB *dcb = dev->dev_dcb;
00451 
00452     switch (dcb->dcb_ipcp_state) {
00453     case PPPS_CLOSING:
00454         dcb->dcb_ipcp_state = PPPS_CLOSED;
00455         break;
00456     case PPPS_STOPPING:
00457         dcb->dcb_ipcp_state = PPPS_STOPPED;
00458         break;
00459 
00460     case PPPS_ACKRCVD:
00461         dcb->dcb_ipcp_state = PPPS_REQSENT;
00462         break;
00463 
00464     case PPPS_OPENED:
00465         IpcpLowerDown(dev);
00466         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00467         break;
00468     }
00469 }
00470 
00471 /*
00472  * Peer doesn't speak this protocol.
00473  *
00474  * Treat this as a catastrophic error (RXJ-).
00475  */
00476 void IpcpRxProtRej(NUTDEVICE * dev)
00477 {
00478     PPPDCB *dcb = dev->dev_dcb;
00479 
00480     switch (dcb->dcb_ipcp_state) {
00481     case PPPS_CLOSING:
00482     case PPPS_CLOSED:
00483         dcb->dcb_ipcp_state = PPPS_CLOSED;
00484         break;
00485 
00486     case PPPS_STOPPING:
00487     case PPPS_REQSENT:
00488     case PPPS_ACKRCVD:
00489     case PPPS_ACKSENT:
00490     case PPPS_STOPPED:
00491         dcb->dcb_ipcp_state = PPPS_STOPPED;
00492         break;
00493 
00494     case PPPS_OPENED:
00495         IpcpLowerDown(dev);
00496         NutIpcpOutput(dev, XCP_TERMREQ, dcb->dcb_reqid, 0);
00497         dcb->dcb_ipcp_state = PPPS_STOPPING;
00498         break;
00499     }
00500 }
00501 
00502 /*
00503  * Receive an Code-Reject.
00504  */
00505 static void IpcpRxCodeRej(NUTDEVICE * dev, u_char id, NETBUF * nb)
00506 {
00507     PPPDCB *dcb = dev->dev_dcb;
00508 
00509     NutNetBufFree(nb);
00510     if (dcb->dcb_ipcp_state == PPPS_ACKRCVD)
00511         dcb->dcb_ipcp_state = PPPS_REQSENT;
00512 }
00513 
00514 
00515 
00530 void NutIpcpInput(NUTDEVICE * dev, NETBUF * nb)
00531 {
00532     XCPHDR *xch;
00533     PPPDCB *dcb = dev->dev_dcb;
00534     u_short len;
00535 
00536     /*
00537      * Discard packets with illegal lengths.
00538      */
00539     if (nb->nb_nw.sz < sizeof(XCPHDR)) {
00540         NutNetBufFree(nb);
00541         return;
00542     }
00543     xch = (XCPHDR *) nb->nb_nw.vp;
00544     if ((len = htons(xch->xch_len)) < sizeof(XCPHDR) || len > nb->nb_nw.sz) {
00545         NutNetBufFree(nb);
00546         return;
00547     }
00548 
00549     /*
00550      * Discard all packets while we are in initial or starting state.
00551      */
00552     if (dcb->dcb_ipcp_state == PPPS_INITIAL || dcb->dcb_ipcp_state == PPPS_STARTING) {
00553         NutNetBufFree(nb);
00554         return;
00555     }
00556 
00557     /*
00558      * Split the IPCP packet.
00559      */
00560     nb->nb_ap.vp = xch + 1;
00561     nb->nb_ap.sz = htons(xch->xch_len) - sizeof(XCPHDR);
00562 
00563     /*
00564      * Action depends on code.
00565      */
00566     switch (xch->xch_code) {
00567     case XCP_CONFREQ:
00568         IpcpRxConfReq(dev, xch->xch_id, nb);
00569         break;
00570 
00571     case XCP_CONFACK:
00572         IpcpRxConfAck(dev, xch->xch_id, nb);
00573         break;
00574 
00575     case XCP_CONFNAK:
00576         IpcpRxConfNakRej(dev, xch->xch_id, nb, 0);
00577         break;
00578 
00579     case XCP_CONFREJ:
00580         IpcpRxConfNakRej(dev, xch->xch_id, nb, 1);
00581         break;
00582 
00583     case XCP_TERMREQ:
00584         IpcpRxTermReq(dev, xch->xch_id, nb);
00585         break;
00586 
00587     case XCP_TERMACK:
00588         IpcpRxTermAck(dev, xch->xch_id, nb);
00589         break;
00590 
00591     case XCP_CODEREJ:
00592         IpcpRxCodeRej(dev, xch->xch_id, nb);
00593         break;
00594 
00595     default:
00596         /*
00597          * TODO: Send code reject.
00598          */
00599         NutNetBufFree(nb);
00600         break;
00601     }
00602 }
00603 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/