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