lcpin.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.7  2008/08/11 07:00:30  haraldkipp
00053  * BSD types replaced by stdint types (feature request #1282721).
00054  *
00055  * Revision 1.6  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.5  2004/03/08 11:26:13  haraldkipp
00060  * Accept incoming header compression.
00061  *
00062  * Revision 1.4  2004/01/30 11:37:58  haraldkipp
00063  * Handle magic number rejects
00064  *
00065  * Revision 1.3  2004/01/14 19:05:53  drsung
00066  * Bug fix in LcpRxConfReq. Thanks to Michel Hendriks.
00067  *
00068  * Revision 1.2  2003/08/14 15:19:15  haraldkipp
00069  * Echo support added.
00070  *
00071  * Revision 1.1.1.1  2003/05/09 14:41:34  haraldkipp
00072  * Initial using 3.2.1
00073  *
00074  * Revision 1.2  2003/05/06 18:14:45  harald
00075  * Cleanup
00076  *
00077  * Revision 1.1  2003/03/31 14:53:27  harald
00078  * Prepare release 3.1
00079  *
00080  */
00081 
00082 #include <net/if_var.h>
00083 #include <dev/ppp.h>
00084 #include <sys/types.h>
00085 #include <netinet/if_ppp.h>
00086 #include <netinet/ppp_fsm.h>
00087 #include <netinet/in.h>
00088 #include <string.h>
00089 
00095 
00096 extern uint32_t new_magic;
00097 
00098 /*
00099  * Received Configure-Request.
00100  */
00101 static void LcpRxConfReq(NUTDEVICE * dev, uint8_t id, NETBUF * nb)
00102 {
00103     PPPDCB *dcb = dev->dev_dcb;
00104     int rc = XCP_CONFACK;
00105     XCPOPT *xcpo;
00106     uint16_t xcpl;
00107     XCPOPT *xcpr;
00108     uint16_t xcps;
00109     uint16_t len = 0;
00110     uint16_t sval;
00111     uint_fast8_t i;
00112 
00113     switch (dcb->dcb_lcp_state) {
00114     case PPPS_CLOSED:
00115         /*
00116          * Go away, we're closed. 
00117          */
00118         NutNetBufFree(nb);
00119         NutLcpOutput(dev, XCP_TERMACK, id, 0);
00120         return;
00121 
00122     case PPPS_CLOSING:
00123     case PPPS_STOPPING:
00124         /*
00125          * Silently ignore configuration requests while going down.
00126          */
00127         NutNetBufFree(nb);
00128         return;
00129 
00130     case PPPS_OPENED:
00131         /* 
00132          * Go down and restart negotiation.
00133          */
00134         IpcpLowerDown(dev);
00135         LcpTxConfReq(dev, ++dcb->dcb_reqid, 0);
00136         break;
00137 
00138     case PPPS_STOPPED:
00139         /* 
00140          * Negotiation started by our peer.
00141          */
00142         LcpTxConfReq(dev, ++dcb->dcb_reqid, 0);
00143         dcb->dcb_lcp_state = PPPS_REQSENT;
00144         break;
00145     }
00146 
00147     /*
00148      * Check if there is anything to reject.
00149      */
00150     xcpo = nb->nb_ap.vp;
00151     xcpl = nb->nb_ap.sz;
00152     xcpr = nb->nb_ap.vp;
00153     xcps = 0;
00154     while (xcpl >= 2) {
00155         len = xcpo->xcpo_len;
00156         if (len > xcpl)
00157             len = xcpl;
00158         else {
00159             switch (xcpo->xcpo_type) {
00160             case LCP_MRU:
00161                 if (xcpo->xcpo_len == 4)
00162                     len = 0;
00163                 break;
00164             case LCP_MAGICNUMBER:
00165             case LCP_ASYNCMAP:
00166                 if (xcpo->xcpo_len == 6)
00167                     len = 0;
00168                 break;
00169             case LCP_AUTHTYPE:
00170                 if (xcpo->xcpo_len >= 4)
00171                     len = 0;
00172                 break;
00173             case LCP_PCOMPRESSION:
00174                 len = 0;
00175                 break;
00176             case LCP_ACCOMPRESSION:
00177                 len = 0;
00178                 break;
00179             }
00180         }
00181 
00182         if (len) {
00183             if (xcpr != xcpo) {
00184                 xcpr->xcpo_type = xcpo->xcpo_type;
00185                 xcpr->xcpo_len = len;
00186                 for (i = 0; i < len - 2; i++)
00187                     /* bug fix by Michel Hendriks. Thanks! */
00188                     xcpr->xcpo_.uc[i] = xcpo->xcpo_.uc[i];
00189             }
00190             xcpr = (XCPOPT *) ((char *) xcpr + len);
00191             xcps += len;
00192         }
00193         xcpl -= xcpo->xcpo_len;
00194         xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len);
00195     }
00196 
00197     if (xcps) {
00198         nb->nb_ap.sz = xcps;
00199         rc = XCP_CONFREJ;
00200     }
00201 
00202     /*
00203      * Check if there is anything to negotiate.
00204      */
00205     else {
00206         xcpo = nb->nb_ap.vp;
00207         xcpl = nb->nb_ap.sz;
00208         xcpr = nb->nb_ap.vp;
00209         xcps = 0;
00210         len = 0;
00211         while (xcpl >= 2) {
00212             switch (xcpo->xcpo_type) {
00213             case LCP_MRU:
00214                 if ((sval = htons(xcpo->xcpo_.us)) < MIN_LCPMRU) {
00215                     len = 4;
00216                     xcpr->xcpo_.us = ntohs(MIN_LCPMRU);
00217                 } else
00218                     dcb->dcb_rem_mru = sval;
00219                 break;
00220             case LCP_ASYNCMAP:
00221                 dcb->dcb_accm = ntohl(xcpo->xcpo_.ul);
00222                 break;
00223             case LCP_AUTHTYPE:
00224                 if (htons(xcpo->xcpo_.us) != PPP_PAP) {
00225                     len = 4;
00226                     xcpr->xcpo_.us = htons(PPP_PAP);
00227                 }
00228                 break;
00229             case LCP_MAGICNUMBER:
00230                 if (xcpo->xcpo_.ul == dcb->dcb_loc_magic || xcpo->xcpo_.ul == dcb->dcb_neg_magic) {
00231                     dcb->dcb_rem_magic = new_magic;
00232                     len = 6;
00233                     xcpr->xcpo_.ul = dcb->dcb_rem_magic;
00234                 }
00235                 break;
00236             case LCP_PCOMPRESSION:
00237                 dcb->dcb_compr |= PPP_PFC;
00238                 break;
00239             case LCP_ACCOMPRESSION:
00240                 dcb->dcb_compr |= PPP_ACFC;
00241                 break;
00242             }
00243 
00244             if (len) {
00245                 if (xcpr != xcpo) {
00246                     xcpr->xcpo_type = xcpo->xcpo_type;
00247                     xcpr->xcpo_len = len;
00248                 }
00249                 xcpr = (XCPOPT *) ((char *) xcpr + len);
00250                 xcps += len;
00251                 len = 0;
00252             }
00253             xcpl -= xcpo->xcpo_len;
00254             xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len);
00255         }
00256         if (xcps) {
00257             nb->nb_ap.sz = xcps;
00258             rc = XCP_CONFNAK;
00259         }
00260     }
00261 
00262     NutLcpOutput(dev, rc, id, nb);
00263 
00264     if (rc == XCP_CONFACK) {
00265         if (dcb->dcb_lcp_state == PPPS_ACKRCVD) {
00266             dcb->dcb_lcp_state = PPPS_OPENED;
00267             if (dcb->dcb_auth == PPP_PAP)
00268                 PapTxAuthReq(dev, ++dcb->dcb_reqid);
00269             else
00270                 IpcpLowerUp(dev);
00271         } else
00272             dcb->dcb_lcp_state = PPPS_ACKSENT;
00273         dcb->dcb_lcp_naks = 0;
00274     } else if (dcb->dcb_lcp_state != PPPS_ACKRCVD)
00275         dcb->dcb_lcp_state = PPPS_REQSENT;
00276 }
00277 
00278 /*
00279  * Configure-Ack received.
00280  * Never called in INITIAL or STARTING phase.
00281  */
00282 static void LcpRxConfAck(NUTDEVICE * dev, uint8_t id, NETBUF * nb)
00283 {
00284     PPPDCB *dcb = dev->dev_dcb;
00285     XCPOPT *xcpo;
00286     uint16_t xcpl;
00287 
00288     /*
00289      * Check if this is a valid ack.
00290      */
00291     if (id == dcb->dcb_reqid && dcb->dcb_acked == 0) {
00292         dcb->dcb_acked = 1;
00293         xcpo = nb->nb_ap.vp;
00294         xcpl = nb->nb_ap.sz;
00295         while (xcpl >= 2) {
00296             switch (xcpo->xcpo_type) {
00297             case LCP_MRU:
00298                 if (htons(xcpo->xcpo_.us) != 1500)
00299                     dcb->dcb_acked = 0;
00300                 break;
00301             case LCP_ASYNCMAP:
00302                 //if(ntohl(xcpo->xcpo_.ul) != )
00303                 //    dcb->dcb_acked = 0;
00304                 break;
00305             case LCP_AUTHTYPE:
00306                 if (htons(xcpo->xcpo_.us) != dcb->dcb_auth)
00307                     dcb->dcb_acked = 0;
00308                 break;
00309             case LCP_MAGICNUMBER:
00310                 if (xcpo->xcpo_.ul == dcb->dcb_neg_magic) {
00311                     dcb->dcb_loc_magic = dcb->dcb_neg_magic;
00312                 } else {
00313                     dcb->dcb_acked = 0;
00314                 }
00315                 break;
00316             case LCP_PCOMPRESSION:
00317                 dcb->dcb_acked = 0;
00318                 break;
00319             case LCP_ACCOMPRESSION:
00320                 dcb->dcb_acked = 0;
00321                 break;
00322             }
00323             xcpl -= xcpo->xcpo_len;
00324             xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len);
00325         }
00326     }
00327 
00328     /*
00329      * We don't need the NETBUF any more.
00330      */
00331     NutNetBufFree(nb);
00332 
00333     /*
00334      * Ignore invalid acks.
00335      */
00336     if (dcb->dcb_acked == 0)
00337         return;
00338 
00339     switch (dcb->dcb_lcp_state) {
00340     case PPPS_CLOSED:
00341     case PPPS_STOPPED:
00342         /*
00343          * Go away, we're closed. 
00344          */
00345         NutLcpOutput(dev, XCP_TERMACK, id, 0);
00346         break;
00347 
00348     case PPPS_REQSENT:
00349         dcb->dcb_lcp_state = PPPS_ACKRCVD;
00350         dcb->dcb_retries = 0;
00351         break;
00352 
00353     case PPPS_ACKRCVD:
00354         LcpTxConfReq(dev, ++dcb->dcb_reqid, 0);
00355         dcb->dcb_lcp_state = PPPS_REQSENT;
00356         break;
00357 
00358     case PPPS_ACKSENT:
00359         /*
00360          * ACK sent and ACK received.
00361          */
00362         dcb->dcb_lcp_state = PPPS_OPENED;
00363 
00364         if (dcb->dcb_auth == PPP_PAP)
00365             PapTxAuthReq(dev, ++dcb->dcb_reqid);
00366         else
00367             IpcpLowerUp(dev);
00368         break;
00369 
00370     case PPPS_OPENED:
00371         /* 
00372          * Go down and restart negotiation.
00373          */
00374         IpcpLowerDown(dev);
00375         LcpTxConfReq(dev, ++dcb->dcb_reqid, 0);
00376         dcb->dcb_lcp_state = PPPS_REQSENT;
00377         break;
00378     }
00379 }
00380 
00381 /*
00382  * Configure-Nak or Configure-Reject received.
00383  */
00384 static void LcpRxConfNakRej(NUTDEVICE * dev, uint8_t id, NETBUF * nb, uint8_t rejected)
00385 {
00386     PPPDCB *dcb = dev->dev_dcb;
00387 
00388     XCPOPT *xcpo;
00389     uint16_t xcpl;
00390 
00391     /*
00392      * Ignore, if we are not expecting this id.
00393      */
00394     if (id != dcb->dcb_reqid || dcb->dcb_acked) {
00395         NutNetBufFree(nb);
00396         return;
00397     }
00398 
00399     /*
00400      * TODO: Process acked options.
00401      */
00402     dcb->dcb_acked = 1;
00403 
00404     xcpo = nb->nb_ap.vp;
00405     xcpl = nb->nb_ap.sz;
00406     while (xcpl >= 2) {
00407         xcpl -= xcpo->xcpo_len;
00408         xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len);
00409     }
00410 
00411     NutNetBufFree(nb);
00412 
00413     switch (dcb->dcb_lcp_state) {
00414     case PPPS_CLOSED:
00415     case PPPS_STOPPED:
00416         /*
00417          * Go away, we're closed. 
00418          */
00419         NutLcpOutput(dev, XCP_TERMACK, id, 0);
00420         break;
00421 
00422     case PPPS_REQSENT:
00423     case PPPS_ACKSENT:
00424         /* They didn't agree to what we wanted - try another request */
00425         LcpTxConfReq(dev, ++dcb->dcb_reqid, rejected);
00426         break;
00427 
00428     case PPPS_ACKRCVD:
00429         /* Got a Nak/reject when we had already had an Ack?? oh well... */
00430         LcpTxConfReq(dev, ++dcb->dcb_reqid, 0);
00431         dcb->dcb_lcp_state = PPPS_REQSENT;
00432         break;
00433 
00434     case PPPS_OPENED:
00435         /* 
00436          * Go down and restart negotiation.
00437          */
00438         IpcpLowerDown(dev);
00439         LcpTxConfReq(dev, ++dcb->dcb_reqid, 0);
00440         dcb->dcb_lcp_state = PPPS_REQSENT;
00441         break;
00442     }
00443 }
00444 
00445 /*
00446  * Terminate-Request received.
00447  */
00448 static void LcpRxTermReq(NUTDEVICE * dev, uint8_t id, NETBUF * nb)
00449 {
00450     PPPDCB *dcb = dev->dev_dcb;
00451 
00452     NutNetBufFree(nb);
00453 
00454     switch (dcb->dcb_lcp_state) {
00455     case PPPS_ACKRCVD:
00456     case PPPS_ACKSENT:
00457         dcb->dcb_lcp_state = PPPS_REQSENT;      /* Start over but keep trying */
00458         break;
00459 
00460     case PPPS_OPENED:
00461         IpcpLowerDown(dev);
00462         dcb->dcb_lcp_state = PPPS_STOPPING;
00463         break;
00464     }
00465     NutLcpOutput(dev, XCP_TERMACK, id, 0);
00466 }
00467 
00468 /*
00469  * Terminate-Ack received.
00470  */
00471 static void LcpRxTermAck(NUTDEVICE * dev, uint8_t id, NETBUF * nb)
00472 {
00473     PPPDCB *dcb = dev->dev_dcb;
00474 
00475     NutNetBufFree(nb);
00476 
00477     switch (dcb->dcb_lcp_state) {
00478     case PPPS_CLOSING:
00479         dcb->dcb_lcp_state = PPPS_CLOSED;
00480         break;
00481     case PPPS_STOPPING:
00482         dcb->dcb_lcp_state = PPPS_STOPPED;
00483         break;
00484 
00485     case PPPS_ACKRCVD:
00486         dcb->dcb_lcp_state = PPPS_REQSENT;
00487         break;
00488 
00489     case PPPS_OPENED:
00490         IpcpLowerDown(dev);
00491         LcpTxConfReq(dev, ++dcb->dcb_reqid, 0);
00492         break;
00493     }
00494 }
00495 
00496 /*
00497  * Peer doesn't speak this protocol.
00498  *
00499  * Treat this as a catastrophic error (RXJ-).
00500  */
00501 void LcpRxProtRej(NUTDEVICE * dev)
00502 {
00503     PPPDCB *dcb = dev->dev_dcb;
00504 
00505     switch (dcb->dcb_lcp_state) {
00506     case PPPS_CLOSING:
00507     case PPPS_CLOSED:
00508         dcb->dcb_lcp_state = PPPS_CLOSED;
00509         break;
00510 
00511     case PPPS_STOPPING:
00512     case PPPS_REQSENT:
00513     case PPPS_ACKRCVD:
00514     case PPPS_ACKSENT:
00515     case PPPS_STOPPED:
00516         dcb->dcb_lcp_state = PPPS_STOPPED;
00517         break;
00518 
00519     case PPPS_OPENED:
00520         IpcpLowerDown(dev);
00521         NutIpcpOutput(dev, XCP_TERMREQ, dcb->dcb_reqid, 0);
00522         dcb->dcb_lcp_state = PPPS_STOPPING;
00523         break;
00524     }
00525 }
00526 
00527 /*
00528  * Received a Code-Reject.
00529  */
00530 static void LcpRxCodeRej(NUTDEVICE * dev, uint8_t id, NETBUF * nb)
00531 {
00532     PPPDCB *dcb = dev->dev_dcb;
00533 
00534     NutNetBufFree(nb);
00535 
00536     if (dcb->dcb_lcp_state == PPPS_ACKRCVD)
00537         dcb->dcb_lcp_state = PPPS_REQSENT;
00538 }
00539 
00540 /*
00541  * Received an Echo-Request.
00542  */
00543 static void LcpRxEchoReq(NUTDEVICE * dev, uint8_t id, NETBUF * nb)
00544 {
00545     PPPDCB *dcb = dev->dev_dcb;
00546 
00547     if (dcb->dcb_lcp_state != PPPS_OPENED) {
00548         NutNetBufFree(nb);
00549     } else {
00550         /* Use local magic number. */
00551         memcpy(nb->nb_ap.vp, &dcb->dcb_loc_magic, sizeof(uint32_t));
00552         NutLcpOutput(dev, LCP_ERP, id, nb);
00553     }
00554 }
00555 
00556 
00557 
00572 void NutLcpInput(NUTDEVICE * dev, NETBUF * nb)
00573 {
00574     XCPHDR *lcp;
00575     PPPDCB *dcb = dev->dev_dcb;
00576     uint16_t len;
00577 
00578     /*
00579      * Discard packets with illegal lengths.
00580      */
00581     if (nb->nb_nw.sz < sizeof(XCPHDR)) {
00582         NutNetBufFree(nb);
00583         return;
00584     }
00585     lcp = (XCPHDR *) nb->nb_nw.vp;
00586     if ((len = htons(lcp->xch_len)) < sizeof(XCPHDR) || len > nb->nb_nw.sz) {
00587         NutNetBufFree(nb);
00588         return;
00589     }
00590 
00591     /*
00592      * Discard all packets while we are in initial or starting state.
00593      */
00594     if (dcb->dcb_lcp_state == PPPS_INITIAL || dcb->dcb_lcp_state == PPPS_STARTING) {
00595         NutNetBufFree(nb);
00596         return;
00597     }
00598 
00599     /*
00600      * Split the LCP packet.
00601      */
00602     nb->nb_ap.vp = lcp + 1;
00603     nb->nb_ap.sz = htons(lcp->xch_len) - sizeof(XCPHDR);
00604 
00605     /*
00606      * Action depends on code.
00607      */
00608     switch (lcp->xch_code) {
00609     case XCP_CONFREQ:
00610         LcpRxConfReq(dev, lcp->xch_id, nb);
00611         break;
00612 
00613     case XCP_CONFACK:
00614         LcpRxConfAck(dev, lcp->xch_id, nb);
00615         break;
00616 
00617     case XCP_CONFNAK:
00618         LcpRxConfNakRej(dev, lcp->xch_id, nb, 0);
00619         break;
00620 
00621     case XCP_CONFREJ:
00622         LcpRxConfNakRej(dev, lcp->xch_id, nb, 1);
00623         break;
00624 
00625     case XCP_TERMREQ:
00626         LcpRxTermReq(dev, lcp->xch_id, nb);
00627         break;
00628 
00629     case XCP_TERMACK:
00630         LcpRxTermAck(dev, lcp->xch_id, nb);
00631         break;
00632 
00633     case XCP_CODEREJ:
00634         LcpRxCodeRej(dev, lcp->xch_id, nb);
00635         break;
00636 
00637     case LCP_ERQ:
00638         LcpRxEchoReq(dev, lcp->xch_id, nb);
00639         break;
00640 
00641     case LCP_ERP:
00642     case LCP_DRQ:
00643         /* Silently ignore echo responses and discard requests. */
00644         NutNetBufFree(nb);
00645         break;
00646 
00647     default:
00648         /*
00649          * TODO: Send code reject.
00650          */
00651         NutNetBufFree(nb);
00652         break;
00653     }
00654 }
00655 

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