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

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