Nut/OS  4.10.3
API Reference
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$
00052  * Revision 1.8  2008/08/11 07:00:30  haraldkipp
00053  * BSD types replaced by stdint types (feature request #1282721).
00054  *
00055  * Revision 1.7  2005/04/08 15:20:50  olereinhardt
00056  * added <sys/types.h> (__APPLE__) and <netinet/in.h> (__linux__)
00057  * for htons and simmilar.
00058  *
00059  * Revision 1.6  2004/03/08 11:24:48  haraldkipp
00060  * PppUp() replaced by direct post.
00061  *
00062  * Revision 1.5  2004/01/30 11:36:52  haraldkipp
00063  * Memory hole fixed
00064  *
00065  * Revision 1.4  2003/12/18 20:44:11  drsung
00066  * Bug fix in IpcpRxConfReq. Thanks to Michel Hendriks.
00067  *
00068  * Revision 1.3  2003/08/14 15:17:50  haraldkipp
00069  * Caller controls ID increment
00070  *
00071  * Revision 1.2  2003/07/24 16:12:53  haraldkipp
00072  * First bugfix: PPP always used the secondary DNS.
00073  * Second bugfix: When the PPP server rejects the
00074  * secondary DNS, IPCP negotiation was trapped in a
00075  * loop.
00076  *
00077  * Revision 1.1.1.1  2003/05/09 14:41:30  haraldkipp
00078  * Initial using 3.2.1
00079  *
00080  * Revision 1.2  2003/05/06 18:04:57  harald
00081  * PPP IP config to DCB
00082  *
00083  * Revision 1.1  2003/03/31 14:53:27  harald
00084  * Prepare release 3.1
00085  *
00086  */
00087 
00088 #include <sys/event.h>
00089 #include <sys/types.h>
00090 #include <net/if_var.h>
00091 #include <dev/ppp.h>
00092 
00093 #include <netinet/if_ppp.h>
00094 #include <netinet/ppp_fsm.h>
00095 #include <netinet/in.h>
00100 
00101 /*
00102  * Received Configure-Request.
00103  */
00104 void IpcpRxConfReq(NUTDEVICE * dev, uint8_t id, NETBUF * nb)
00105 {
00106     PPPDCB *dcb = dev->dev_dcb;
00107     int rc = XCP_CONFACK;
00108     XCPOPT *xcpo;
00109     uint16_t xcpl;
00110     XCPOPT *xcpr;
00111     uint16_t xcps;
00112     uint16_t len = 0;
00113     uint_fast8_t i;
00114 
00115     switch (dcb->dcb_ipcp_state) {
00116     case PPPS_CLOSED:
00117         /*
00118          * Go away, we're closed. 
00119          */
00120         NutNetBufFree(nb);
00121         NutIpcpOutput(dev, XCP_TERMACK, id, 0);
00122         return;
00123 
00124     case PPPS_CLOSING:
00125     case PPPS_STOPPING:
00126         /*
00127          * Ignore if we are going down.
00128          */
00129         NutNetBufFree(nb);
00130         return;
00131 
00132     case PPPS_OPENED:
00133         /* 
00134          * Go down and restart negotiation.
00135          */
00136         IpcpLowerDown(dev);
00137         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00138         break;
00139 
00140     case PPPS_STOPPED:
00141         /* 
00142          * Negotiation started by our peer.
00143          */
00144         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00145         dcb->dcb_ipcp_state = PPPS_REQSENT;
00146         break;
00147     }
00148 
00149     /*
00150      * Check if there is anything to reject.
00151      */
00152     xcpo = nb->nb_ap.vp;
00153     xcpl = nb->nb_ap.sz;
00154     xcpr = nb->nb_ap.vp;
00155     xcps = 0;
00156     while (xcpl >= 2) {
00157         len = xcpo->xcpo_len;
00158         if (len > xcpl)
00159             len = xcpl;
00160         else {
00161             switch (xcpo->xcpo_type) {
00162             case IPCP_COMPRESSTYPE:
00163                 break;
00164             case IPCP_ADDR:
00165             case IPCP_MS_DNS1:
00166             case IPCP_MS_DNS2:
00167                 if (xcpo->xcpo_len == 6)
00168                     len = 0;
00169                 break;
00170             }
00171         }
00172 
00173         if (len) {
00174             if (xcpr != xcpo) {
00175                 xcpr->xcpo_type = xcpo->xcpo_type;
00176                 xcpr->xcpo_len = len;
00177                 for (i = 0; i < len - 2; i++)
00178                     /* bug fix by Michel Hendriks. Thanks! */
00179                     xcpr->xcpo_.uc[i] = xcpo->xcpo_.uc[i];
00180             }
00181             xcpr = (XCPOPT *) ((char *) xcpr + len);
00182             xcps += len;
00183         }
00184         xcpl -= xcpo->xcpo_len;
00185         xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len);
00186     }
00187 
00188     if (xcps) {
00189         nb->nb_ap.sz = xcps;
00190         rc = XCP_CONFREJ;
00191     }
00192 
00193     /*
00194      * Check if there is anything to negotiate.
00195      */
00196     else {
00197         xcpo = nb->nb_ap.vp;
00198         xcpl = nb->nb_ap.sz;
00199         xcpr = nb->nb_ap.vp;
00200         xcps = 0;
00201         len = 0;
00202         while (xcpl >= 2) {
00203             switch (xcpo->xcpo_type) {
00204             case IPCP_ADDR:
00205                 if (xcpo->xcpo_.ul)
00206                     dcb->dcb_remote_ip = xcpo->xcpo_.ul;
00207                 else if (dcb->dcb_remote_ip == 0)
00208                     len = xcpo->xcpo_len;
00209                 break;
00210             case IPCP_COMPRESSTYPE:
00211                 len = 6;
00212                 xcpr->xcpo_.ul = 0;
00213                 break;
00214             case IPCP_MS_DNS1:
00215                 if (xcpo->xcpo_.ul)
00216                     dcb->dcb_ip_dns1 = xcpo->xcpo_.ul;
00217                 break;
00218             case IPCP_MS_DNS2:
00219                 if (xcpo->xcpo_.ul)
00220                     dcb->dcb_ip_dns2 = xcpo->xcpo_.ul;
00221                 break;
00222             }
00223 
00224             if (len) {
00225                 if (xcpr != xcpo) {
00226                     xcpr->xcpo_type = xcpo->xcpo_type;
00227                     xcpr->xcpo_len = len;
00228                 }
00229                 xcpr = (XCPOPT *) ((char *) xcpr + len);
00230                 xcps += len;
00231                 len = 0;
00232             }
00233             xcpl -= xcpo->xcpo_len;
00234             xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len);
00235         }
00236         if (xcps) {
00237             nb->nb_ap.sz = xcps;
00238             rc = XCP_CONFNAK;
00239         }
00240     }
00241 
00242     NutIpcpOutput(dev, rc, id, nb);
00243 
00244     if (rc == XCP_CONFACK) {
00245         if (dcb->dcb_ipcp_state == PPPS_ACKRCVD) {
00246             dcb->dcb_ipcp_state = PPPS_OPENED;
00247             NutEventPost(&dcb->dcb_state_chg);
00248         } else
00249             dcb->dcb_ipcp_state = PPPS_ACKSENT;
00250         dcb->dcb_ipcp_naks = 0;
00251     } else if (dcb->dcb_ipcp_state != PPPS_ACKRCVD)
00252         dcb->dcb_ipcp_state = PPPS_REQSENT;
00253 }
00254 
00255 /*
00256  * Configure-Ack received.
00257  */
00258 void IpcpRxConfAck(NUTDEVICE * dev, uint8_t id, NETBUF * nb)
00259 {
00260     PPPDCB *dcb = dev->dev_dcb;
00261     XCPOPT *xcpo;
00262     uint16_t xcpl;
00263 
00264     /*
00265      * Ignore, if we are not expecting this id.
00266      */
00267     if (id != dcb->dcb_reqid || dcb->dcb_acked) {
00268         return;
00269     }
00270 
00271     switch (dcb->dcb_ipcp_state) {
00272     case PPPS_CLOSED:
00273     case PPPS_STOPPED:
00274         /*
00275          * Go away, we're closed. 
00276          */
00277         NutNetBufFree(nb);
00278         NutIpcpOutput(dev, XCP_TERMACK, id, 0);
00279         return;
00280 
00281     case PPPS_REQSENT:
00282         dcb->dcb_ipcp_state = PPPS_ACKRCVD;
00283         dcb->dcb_retries = 0;
00284         break;
00285 
00286     case PPPS_ACKRCVD:
00287         /* Huh? an extra valid Ack? oh well... */
00288         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00289         dcb->dcb_ipcp_state = PPPS_REQSENT;
00290         break;
00291 
00292     case PPPS_ACKSENT:
00293         dcb->dcb_ipcp_state = PPPS_OPENED;
00294         dcb->dcb_retries = 0;
00295         NutEventPost(&dcb->dcb_state_chg);
00296         break;
00297 
00298     case PPPS_OPENED:
00299         /* Go down and restart negotiation */
00300         IpcpLowerDown(dev);
00301         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00302         dcb->dcb_ipcp_state = PPPS_REQSENT;
00303         break;
00304     }
00305 
00306     xcpo = nb->nb_ap.vp;
00307     xcpl = nb->nb_ap.sz;
00308     while (xcpl >= 2) {
00309         switch (xcpo->xcpo_type) {
00310         case IPCP_ADDR:
00311             if (xcpo->xcpo_.ul)
00312                 dcb->dcb_local_ip = xcpo->xcpo_.ul;
00313             break;
00314         case IPCP_COMPRESSTYPE:
00315             break;
00316         case IPCP_MS_DNS1:
00317             if (xcpo->xcpo_.ul)
00318                 dcb->dcb_ip_dns1 = xcpo->xcpo_.ul;
00319             break;
00320         case IPCP_MS_DNS2:
00321             /* Fixed secondary DNS bug, thanks to Tarmo Fimberg
00322                and Jelle Martijn Kok. */
00323             if (xcpo->xcpo_.ul)
00324                 dcb->dcb_ip_dns2 = xcpo->xcpo_.ul;
00325             break;
00326         }
00327         xcpl -= xcpo->xcpo_len;
00328         xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len);
00329     }
00330 
00331     dcb->dcb_acked = 1;
00332     NutNetBufFree(nb);
00333 }
00334 
00335 /*
00336  * Configure-Nak or Configure-Reject received.
00337  */
00338 static void IpcpRxConfNakRej(NUTDEVICE * dev, uint8_t id, NETBUF * nb, uint8_t rejected)
00339 {
00340     PPPDCB *dcb = dev->dev_dcb;
00341     XCPOPT *xcpo;
00342     uint16_t xcpl;
00343 
00344     /*
00345      * Ignore, if we are not expecting this id.
00346      */
00347     if (id != dcb->dcb_reqid || dcb->dcb_acked) {
00348         NutNetBufFree(nb);
00349         return;
00350     }
00351 
00352     switch (dcb->dcb_ipcp_state) {
00353     case PPPS_CLOSED:
00354     case PPPS_STOPPED:
00355         /*
00356          * Go away, we're closed. 
00357          */
00358         NutNetBufFree(nb);
00359         NutIpcpOutput(dev, XCP_TERMACK, id, 0);
00360         return;
00361 
00362     case PPPS_REQSENT:
00363     case PPPS_ACKSENT:
00364     case PPPS_ACKRCVD:
00365     case PPPS_OPENED:
00366         break;
00367 
00368     default:
00369         NutNetBufFree(nb);
00370         return;
00371     }
00372 
00373     dcb->dcb_acked = 1;
00374 
00375     xcpo = nb->nb_ap.vp;
00376     xcpl = nb->nb_ap.sz;
00377     while (xcpl >= 2) {
00378         switch (xcpo->xcpo_type) {
00379         case IPCP_ADDR:
00380             if (xcpo->xcpo_.ul)
00381                 dcb->dcb_local_ip = xcpo->xcpo_.ul;
00382             break;
00383         case IPCP_COMPRESSTYPE:
00384             break;
00385         case IPCP_MS_DNS1:
00386             if (rejected)
00387                 dcb->dcb_rejects |= REJ_IPCP_DNS1;
00388             else if (xcpo->xcpo_.ul)
00389                 dcb->dcb_ip_dns1 = xcpo->xcpo_.ul;
00390             break;
00391         case IPCP_MS_DNS2:
00392             if (rejected)
00393                 dcb->dcb_rejects |= REJ_IPCP_DNS2;
00394             else if (xcpo->xcpo_.ul)
00395                 dcb->dcb_ip_dns2 = xcpo->xcpo_.ul;
00396             break;
00397         }
00398         xcpl -= xcpo->xcpo_len;
00399         xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len);
00400     }
00401     NutNetBufFree(nb);
00402 
00403     switch (dcb->dcb_ipcp_state) {
00404 
00405     case PPPS_REQSENT:
00406     case PPPS_ACKSENT:
00407         /* They didn't agree to what we wanted - try another request */
00408         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00409         break;
00410 
00411     case PPPS_ACKRCVD:
00412         /* Got a Nak/reject when we had already had an Ack?? oh well... */
00413         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00414         dcb->dcb_ipcp_state = PPPS_REQSENT;
00415         break;
00416 
00417     case PPPS_OPENED:
00418         /* Go down and restart negotiation */
00419         IpcpLowerDown(dev);
00420         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00421         dcb->dcb_ipcp_state = PPPS_REQSENT;
00422         break;
00423     }
00424 }
00425 
00426 /*
00427  * \brief Terminate request received.
00428  */
00429 void IpcpRxTermReq(NUTDEVICE * dev, uint8_t id, NETBUF * nb)
00430 {
00431     PPPDCB *dcb = dev->dev_dcb;
00432 
00433     NutNetBufFree(nb);
00434     switch (dcb->dcb_ipcp_state) {
00435     case PPPS_ACKRCVD:
00436     case PPPS_ACKSENT:
00437         dcb->dcb_ipcp_state = PPPS_REQSENT;
00438         break;
00439 
00440     case PPPS_OPENED:
00441         IpcpLowerDown(dev);
00442         dcb->dcb_ipcp_state = PPPS_STOPPING;
00443         break;
00444     }
00445     NutIpcpOutput(dev, XCP_TERMACK, id, 0);
00446 }
00447 
00448 /*
00449  * Terminate-Ack received.
00450  */
00451 void IpcpRxTermAck(NUTDEVICE * dev, uint8_t id, NETBUF * nb)
00452 {
00453     PPPDCB *dcb = dev->dev_dcb;
00454 
00455     switch (dcb->dcb_ipcp_state) {
00456     case PPPS_CLOSING:
00457         dcb->dcb_ipcp_state = PPPS_CLOSED;
00458         break;
00459     case PPPS_STOPPING:
00460         dcb->dcb_ipcp_state = PPPS_STOPPED;
00461         break;
00462 
00463     case PPPS_ACKRCVD:
00464         dcb->dcb_ipcp_state = PPPS_REQSENT;
00465         break;
00466 
00467     case PPPS_OPENED:
00468         IpcpLowerDown(dev);
00469         IpcpTxConfReq(dev, ++dcb->dcb_reqid);
00470         break;
00471     }
00472 }
00473 
00474 /*
00475  * Peer doesn't speak this protocol.
00476  *
00477  * Treat this as a catastrophic error (RXJ-).
00478  */
00479 void IpcpRxProtRej(NUTDEVICE * dev)
00480 {
00481     PPPDCB *dcb = dev->dev_dcb;
00482 
00483     switch (dcb->dcb_ipcp_state) {
00484     case PPPS_CLOSING:
00485     case PPPS_CLOSED:
00486         dcb->dcb_ipcp_state = PPPS_CLOSED;
00487         break;
00488 
00489     case PPPS_STOPPING:
00490     case PPPS_REQSENT:
00491     case PPPS_ACKRCVD:
00492     case PPPS_ACKSENT:
00493     case PPPS_STOPPED:
00494         dcb->dcb_ipcp_state = PPPS_STOPPED;
00495         break;
00496 
00497     case PPPS_OPENED:
00498         IpcpLowerDown(dev);
00499         NutIpcpOutput(dev, XCP_TERMREQ, dcb->dcb_reqid, 0);
00500         dcb->dcb_ipcp_state = PPPS_STOPPING;
00501         break;
00502     }
00503 }
00504 
00505 /*
00506  * Receive an Code-Reject.
00507  */
00508 static void IpcpRxCodeRej(NUTDEVICE * dev, uint8_t id, NETBUF * nb)
00509 {
00510     PPPDCB *dcb = dev->dev_dcb;
00511 
00512     NutNetBufFree(nb);
00513     if (dcb->dcb_ipcp_state == PPPS_ACKRCVD)
00514         dcb->dcb_ipcp_state = PPPS_REQSENT;
00515 }
00516 
00517 
00518 
00533 void NutIpcpInput(NUTDEVICE * dev, NETBUF * nb)
00534 {
00535     XCPHDR *xch;
00536     PPPDCB *dcb = dev->dev_dcb;
00537     uint16_t len;
00538 
00539     /*
00540      * Discard packets with illegal lengths.
00541      */
00542     if (nb->nb_nw.sz < sizeof(XCPHDR)) {
00543         NutNetBufFree(nb);
00544         return;
00545     }
00546     xch = (XCPHDR *) nb->nb_nw.vp;
00547     if ((len = htons(xch->xch_len)) < sizeof(XCPHDR) || len > nb->nb_nw.sz) {
00548         NutNetBufFree(nb);
00549         return;
00550     }
00551 
00552     /*
00553      * Discard all packets while we are in initial or starting state.
00554      */
00555     if (dcb->dcb_ipcp_state == PPPS_INITIAL || dcb->dcb_ipcp_state == PPPS_STARTING) {
00556         NutNetBufFree(nb);
00557         return;
00558     }
00559 
00560     /*
00561      * Split the IPCP packet.
00562      */
00563     nb->nb_ap.vp = xch + 1;
00564     nb->nb_ap.sz = htons(xch->xch_len) - sizeof(XCPHDR);
00565 
00566     /*
00567      * Action depends on code.
00568      */
00569     switch (xch->xch_code) {
00570     case XCP_CONFREQ:
00571         IpcpRxConfReq(dev, xch->xch_id, nb);
00572         break;
00573 
00574     case XCP_CONFACK:
00575         IpcpRxConfAck(dev, xch->xch_id, nb);
00576         break;
00577 
00578     case XCP_CONFNAK:
00579         IpcpRxConfNakRej(dev, xch->xch_id, nb, 0);
00580         break;
00581 
00582     case XCP_CONFREJ:
00583         IpcpRxConfNakRej(dev, xch->xch_id, nb, 1);
00584         break;
00585 
00586     case XCP_TERMREQ:
00587         IpcpRxTermReq(dev, xch->xch_id, nb);
00588         break;
00589 
00590     case XCP_TERMACK:
00591         IpcpRxTermAck(dev, xch->xch_id, nb);
00592         break;
00593 
00594     case XCP_CODEREJ:
00595         IpcpRxCodeRej(dev, xch->xch_id, nb);
00596         break;
00597 
00598     default:
00599         /*
00600          * TODO: Send code reject.
00601          */
00602         NutNetBufFree(nb);
00603         break;
00604     }
00605 }
00606