Beispiel #1
0
bool PPP_set_secrets
   (
      _ppp_handle       handle,
            /* [IN] - the PPP state structure */
      uint32_t           secret_number,

      PPP_SECRET_PTR    secret_ptr

   )
{ /* Body */

#if RTCSCFG_ENABLE_IP4

   PPP_CFG_PTR ppp_ptr = handle;
   bool     success=TRUE;

   switch (secret_number) {
      case PPP_PAP_LSECRET:
         PPP_SECRET(ppp_ptr, _PPP_PAP_LSECRET) = secret_ptr;
         break;

      case PPP_PAP_RSECRETS:
         PPP_SECRET(ppp_ptr, _PPP_PAP_RSECRETS) = secret_ptr;
         break;

      case PPP_CHAP_LSECRETS:
         PPP_SECRET(ppp_ptr, _PPP_CHAP_LSECRETS) = secret_ptr;
         break;

      case PPP_CHAP_RSECRETS:
         PPP_SECRET(ppp_ptr, _PPP_CHAP_RSECRETS) = secret_ptr;
         break;
   
      default:
         success=FALSE;
   }

   return success;

#else

    return FALSE;    

#endif /* RTCSCFG_ENABLE_IP4 */ 
   
} /* Endbody */
Beispiel #2
0
void CHAP_challenge
   (
      _ppp_handle    handle
            /* [IN] - the PPP state structure */
   )
{ /* Body */
   PPP_CFG_PTR    ppp_ptr = handle;
   CHAP_DATA_PTR  chap_ptr = &ppp_ptr->CHAP_STATE;
   PCB_PTR        pcb;
   uchar_ptr      outp;
   uint_16        len;
   uint_16        i, idlen;

   chap_ptr->SERVER_STATE = CHAP_STATE_INITIAL;
   chap_ptr->CURID = RTCS_rand() & 0xFF;

   /* Acquire a message buffer */
   /* Start CR 2207 */
   idlen = strlen(PPP_SECRET(ppp_ptr,_PPP_CHAP_LNAME));
   /* End CR 2207 */
   len = CHAP_HDR_LEN + 1 + CHAP_CHALLENGE_LEN + idlen;
   pcb = PPP_pcballoc(PPP_PROT_CHAP, len);
   if (pcb == NULL) {
      return;
   } /* Endif */

   /* Build a Challenge packet */
   outp = pcb->FRAG[0].FRAGMENT + 2;
   *outp++ = CHAP_CODE_CHALLENGE;
   *outp++ = chap_ptr->CURID;
   *outp++ = (len >> 8) & 0xFF;
   *outp++ =  len       & 0xFF;
   *outp++ = CHAP_CHALLENGE_LEN;
   for (i=0; i<CHAP_CHALLENGE_LEN; i++) {
      *outp++ = chap_ptr->MD5[i] = RTCS_rand() & 0xFF;
   } /* Endfor */
   /* Start CR 2207 */
   PPP_memcopy(PPP_SECRET(ppp_ptr,_PPP_CHAP_LNAME), outp, idlen);
   /* End CR 2207 */
   /* Send the PCB */
   PPP_send_rexmit(ppp_ptr, PPP_PROT_CHAP, pcb, 0, CHAP_timeout, chap_ptr);

} /* Endbody */
Beispiel #3
0
static void LCP_resetconfreq
   (
      PPPFSM_CFG_PTR    fsm
            /* [IN] - State Machine */
   )
{ /* Body */
   LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
   uint32_t     if_type;
/* Start CR 2207 */
#if PPP_SECRETS_NOT_SHARED
   PPP_CFG_PTR    ppp_ptr = lcp_ptr->HANDLE;
#endif
/* End CR 2207 */

   _iopcb_ioctl(lcp_ptr->DEVICE, IOPCB_IOCTL_GET_IFTYPE, &if_type);
   if (if_type == IPIFTYPE_ETHERNET) {
      lcp_ptr->SEND_OPT = PPP_DEFAULT_OPTIONS_PPPOE;
      lcp_ptr->RECV_OPT = PPP_DEFAULT_OPTIONS_PPPOE;
      lcp_ptr->RECV_NEG = LCP_DEFAULT_NEG_PPPOE;
   } else {
      lcp_ptr->SEND_OPT = PPP_DEFAULT_OPTIONS;
      lcp_ptr->RECV_OPT = PPP_DEFAULT_OPTIONS;
      lcp_ptr->RECV_NEG = LCP_DEFAULT_NEG;
      lcp_ptr->RECV_NEG.ACCM = _PPP_ACCM;
   } /* Endif */

/* Start CR 2207 */
   if (PPP_SECRET(ppp_ptr,_PPP_CHAP_RSECRETS)) {
/* End CR 2207 */
      lcp_ptr->RECV_NEG.NEG_AP = 1;
      lcp_ptr->RECV_NEG.AP = PPP_PROT_CHAP;
/* Start CR 2207 */
   } else if (PPP_SECRET(ppp_ptr,_PPP_PAP_RSECRETS)) {
/* End CR 2207 */
      lcp_ptr->RECV_NEG.NEG_AP = 1;
      lcp_ptr->RECV_NEG.AP = PPP_PROT_PAP;
   } else {
      lcp_ptr->RECV_NEG.NEG_AP = 0;
   } /* Endif */

} /* Endbody */
Beispiel #4
0
void PAP_send
   (
      _ppp_handle    handle
            /* [IN] - the PPP state structure */
   )
{ /* Body */

#if RTCSCFG_ENABLE_IP4

   PPP_CFG_PTR    ppp_ptr = handle;
   PAP_DATA_PTR   pap_ptr = &ppp_ptr->PAP_STATE;
   PCB_PTR        pcb;
   unsigned char      *outp;
   uint16_t        len;

   pap_ptr->CLIENT_STATE = PAP_STATE_INITIAL;
   pap_ptr->CURID = RTCS_rand() & 0xFF;

   /* Acquire a PCB */
   len = PAP_HDR_LEN + 2
/* Start CR 2207 */
       + PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET->PPP_ID_LENGTH)
       + PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET->PPP_PW_LENGTH);
/* End CR 2207 */

   pcb = PPP_pcballoc(PPP_PROT_PAP, len);
   if (pcb == NULL) {
      return;
   } /* Endif */

   /* Build an Authenticate-Request packet */
   outp = pcb->FRAG[0].FRAGMENT + 2;
   *outp++ = PAP_CODE_AUTH_REQ;
   *outp++ = pap_ptr->CURID;
   *outp++ = (len >> 8) & 0xFF;
   *outp++ =  len       & 0xFF;
/* Start CR 2207 */
   *outp++ = len = PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET->PPP_ID_LENGTH);
   PPP_memcopy(PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET->PPP_ID_PTR), outp, len);
   outp += len;
   *outp++ = len = PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET->PPP_PW_LENGTH);
   PPP_memcopy(PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET->PPP_PW_PTR), outp, len);
/* End CR 2207 */

   /* Send the PCB */
   PPP_send_rexmit(ppp_ptr, PPP_PROT_PAP, pcb, 0, PAP_timeout, pap_ptr);

#endif /* RTCSCFG_ENABLE_IP4 */

} /* Endbody */
Beispiel #5
0
bool PPP_set_chap_lname
   (
      _ppp_handle       handle,
            /* [IN] - the PPP state structure */
      char    *lname

   )
{ /* Body */

#if RTCSCFG_ENABLE_IP4

   PPP_CFG_PTR ppp_ptr = handle;
   PPP_SECRET(ppp_ptr, _PPP_CHAP_LNAME) = lname;
   return TRUE;

#else

    return FALSE;

#endif /* RTCSCFG_ENABLE_IP4 */ 
   
} /* Endbody */
Beispiel #6
0
void PAP_input
   (
      PCB_PTR        pcb,
            /* [IN] - PAP packet */
      _ppp_handle    handle
            /* [IN] - the PPP state structure */
   )
{ /* Body */
   PPP_CFG_PTR    ppp_ptr = handle;
   PAP_DATA_PTR   pap_ptr = &ppp_ptr->PAP_STATE;
   PPP_SECRET_PTR secret;
   uchar_ptr      inp = pcb->FRAG[0].FRAGMENT + 2;
   uchar_ptr      idp, pwp;
   uchar          code, id;
   uchar          idlen, pwlen;
   uint_16        len;
   boolean        delay = FALSE;

   /*
   ** Parse header (code, id and length).
   ** If packet too short, drop it.
   */
   if (pcb->FRAG[0].LENGTH < 2 + PAP_HDR_LEN) {
      pap_ptr->ST_PAP_SHORT++;
      PCB_free(pcb);
      return;
   } /* Endif */

   code = *inp++;
   id = *inp++;
   len = *inp++ << 8;
   len += *inp++;

   if ((len < PAP_HDR_LEN) || (len > pcb->FRAG[0].LENGTH - 2)) {
      pap_ptr->ST_PAP_SHORT++;
      PCB_free(pcb);
      return;
   } /* Endif */
   len -= PAP_HDR_LEN;

   switch (code) {

   case PAP_CODE_AUTH_REQ:
      switch (pap_ptr->SERVER_STATE) {
      case PAP_STATE_INITIAL:

         /* Parse the peer id and password */
         idp = inp;
         idlen = *idp++;
         pwp = idp + idlen;
         pwlen = *pwp++;
         if (len < idlen + pwlen + 2) {
            pap_ptr->ST_PAP_SHORT++;
            PCB_free(pcb);
            break;
         } /* Endif */

         /* Match id/password pair against the secrets table */
/* Start CR 2207 */
         secret = PPP_SECRET(ppp_ptr,_PPP_PAP_RSECRETS);
/* End CR 2207 */
         for (;;) {
            if ((secret->PPP_ID_LENGTH == 0)
             && (secret->PPP_PW_LENGTH == 0)) {
               pap_ptr->SERVER_STATE = PAP_STATE_AUTH_NAK;
               PAP_fail(handle);
               delay = TRUE;
               break;
            } /* Endif */
            if ((secret->PPP_ID_LENGTH == idlen)
             && (secret->PPP_PW_LENGTH == pwlen)
             && (memcmp(secret->PPP_ID_PTR, idp, idlen) == 0)
             && (memcmp(secret->PPP_PW_PTR, pwp, pwlen) == 0)) {
               pap_ptr->SERVER_STATE = PAP_STATE_AUTH_ACK;
               PAP_up(handle);
               break;
            } /* Endif */
            secret++;
         } /* Endfor */

         /* fall through */
      case PAP_STATE_AUTH_ACK:
      case PAP_STATE_AUTH_NAK:
         /* Build an Auth-Ack or Auth-Nak reply */
         inp = pcb->FRAG[0].FRAGMENT + 2;
         *inp++ = pap_ptr->SERVER_STATE;
         inp++;                              /* Keep same ID */
         *inp++ = 0;
         *inp++ = 5;
         *inp++ = 0;
         pcb->FRAG[0].LENGTH = 7;
         if (delay) {
            PPP_send_rexmit(ppp_ptr, PPP_PROT_PAP, pcb, 1, PAP_close, handle);
         } else {
            PPP_send_one(ppp_ptr, PPP_PROT_PAP, pcb);
         } /* Endif */
         break;

      default:
         pap_ptr->ST_PAP_NOAUTH++;
         PCB_free(pcb);
         break;
      } /* Endswitch */
      break;

   case PAP_CODE_AUTH_ACK:
       pap_ptr->CLIENT_STATE = PAP_STATE_AUTH_ACK;
       PAP_up(handle);
   case PAP_CODE_AUTH_NAK:
      if (pap_ptr->CLIENT_STATE != PAP_STATE_AUTH_ACK) {
         pap_ptr->CLIENT_STATE = PAP_STATE_AUTH_NAK;
      } /* Endif */
      
      if (pap_ptr->CLIENT_STATE != PAP_STATE_INITIAL && pap_ptr->CLIENT_STATE != PAP_STATE_AUTH_ACK) {
         pap_ptr->ST_PAP_NOREQ++;
      } else if (id != pap_ptr->CURID) {
         pap_ptr->ST_PAP_ID++;
      } else if (len < 1) {
         pap_ptr->ST_PAP_SHORT++;
      } else if (--len < *inp++) {
         pap_ptr->ST_PAP_SHORT++;
      } else {
         /* All is well -- stop send Auth-Req's */
         PPP_send_stop(ppp_ptr, PPP_PROT_PAP);
      } /* Endif */
      PCB_free(pcb);
      break;

   default:
      pap_ptr->ST_PAP_CODE++;
      PCB_free(pcb);
      break;
   } /* Endswitch */

} /* Endbody */
Beispiel #7
0
static uint32_t LCP_recvconfreq
   (
      PPPFSM_CFG_PTR    fsm,
            /* [IN] - State Machine */
      bool           reject
            /* [IN] - whether to ConfRej if we disagree */
   )
{ /* Body */
   LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
   unsigned char   *inp = fsm->DATA;
   unsigned char   *nakp, *rejp;
   uint32_t     sizeleft = fsm->LENGTH;
   uint32_t     naklen, rejlen;
   bool     apneg = FALSE;
   PPP_OPT     req_opt = lcp_ptr->SEND_OPT;
   unsigned char       code;
   unsigned char       cicode, cilen;
/* Start CR 2207 */
#if PPP_SECRETS_NOT_SHARED
   PPP_CFG_PTR    ppp_ptr = lcp_ptr->HANDLE;
#endif
/* End CR 2207 */

#define CI_REJECT(n)                   \
   inp -= n;                           \
   code = CP_CODE_CONF_REJ;            \
   rejlen += cilen;                    \
   while (cilen--) *rejp++ = *inp++

#define CI_NAK                               \
   if (code != CP_CODE_CONF_REJ) {           \
      code = CP_CODE_CONF_NAK;               \
      if (reject) {                          \
         inp -= cilen;                       \
         naklen += cilen;                    \
         while (cilen--) *nakp++ = *inp++;   \
      } else {                               \
         apneg = FALSE;

#define CI_ENDNAK                            \
      } /* Endif */                          \
   } /* Endif */

#define CI_NAKAP(n)                          \
   if (code != CP_CODE_CONF_REJ) {           \
      code = CP_CODE_CONF_NAK;               \
      if (reject) {                          \
         inp -= n;                           \
         naklen += cilen;                    \
         while (cilen--) *nakp++ = *inp++;   \
      } else {                               \
         apneg = TRUE;                       \
         inp += cilen - n;                   \
      } /* Endif */                          \
   } else {                                  \
      inp += cilen - n;                      \
   } /* Endif */

   /*
   ** Process all requested codes
   */

   rejp = nakp = inp;
   rejlen = naklen = 0;
   code = CP_CODE_CONF_ACK;

   while (sizeleft) {
         /* check remaining length */
      if (sizeleft < inp[1] || inp[1] < 2) {
         code = CP_CODE_CONF_REJ;
         rejlen += sizeleft;
         while (sizeleft--) *rejp++ = *inp++;
         break;
      } /* Endif */

      cicode = *inp++;
      sizeleft -= cilen = *inp++;

      switch (cicode) {
      case LCP_CI_MRU:
         if (cilen != 4) {
            CI_REJECT(2);
            break;
         } /* Endif */

            /* Accept any MRU no smaller than 68 bytes */
         req_opt.MRU = mqx_ntohs(inp); inp += 2;
         if (req_opt.MRU > DEFAULT_MRU) {
            req_opt.MRU = DEFAULT_MRU;
         } else if (req_opt.MRU < MINIMUM_MRU) {
            CI_NAK {
               *nakp++ = LCP_CI_MRU;
               naklen += *nakp++ = 4;
               req_opt.MRU = MINIMUM_MRU;
               mqx_htons(nakp, req_opt.MRU); nakp += 2;
            } CI_ENDNAK;
         } /* Endif */
         break;

      case LCP_CI_ACCM:
         if (cilen != 6) {
            CI_REJECT(2);
            break;
         } /* Endif */

            /* If we want any characters not in their ACCM, nak it */
         req_opt.ACCM = mqx_ntohl(inp); inp += 4;
         if ((req_opt.ACCM & _PPP_ACCM) != _PPP_ACCM) {
            CI_NAK {
               *nakp++ = LCP_CI_ACCM;
               naklen += *nakp++ = 6;
               req_opt.ACCM |= _PPP_ACCM;
               mqx_htonl(nakp, req_opt.ACCM); nakp += 4;
            } CI_ENDNAK;
         } /* Endif */
         break;

         /*
         ** AP is unusual in that it is a variable length
         ** option.  Thus it is possible that we may want
         ** to nak AP and make a suggestion longer than
         ** the peer's request.
         **
         ** This is bad.
         **
         ** It's bad because this function wants to reuse
         ** the incoming ConfReq to build the reply, and
         ** in this case, it is possible for nakp to
         ** overtake inp, thus overwriting an option not
         ** yet parsed.
         **
         ** So we do the following:  If we decide to nak
         ** the requested AP, we just set apneg=TRUE and
         ** append the nak'd AP at the end of our ConfNak
         ** after we've completed parsing the ConfReq.
         **
         ** Note that we won't nak AP if we generate
         ** nak's for other options afterward, because
         ** the RFC states that nak'd options MUST be in
         ** the same order that they were in the ConfReq.
         */

      case LCP_CI_AP:
         if (cilen < 4) {
            CI_REJECT(2);
            break;
         } /* Endif */

            /* If we don't have any secrets, reject AP */
/* Start CR 2207 */
         if (!(PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET) || PPP_SECRET(ppp_ptr,_PPP_CHAP_LSECRETS))) {
/* End CR 2207 */
            CI_REJECT(2);
            break;
         } /* Endif */

            /* Check the desired authentication protocol */
         req_opt.AP = mqx_ntohs(inp); inp += 2;
         switch (req_opt.AP) {

            /* Accept PAP only if we have a secret */
         case PPP_PROT_PAP:
            if (cilen != 4) {
               CI_REJECT(4);
               break;
/* Start CR 2207 */
            } else if (PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET) == NULL) {
/* End CR 2207 */
               CI_NAKAP(4);
               break;
            } /* Endif */
            req_opt.AP_Start = PAP_send;
            break;

            /* Accept CHAP only if we have a secrets table */
         case PPP_PROT_CHAP:
            if (cilen != 5) {
               CI_REJECT(4);
               break;
/* Start CR 2207 */
            } else if (PPP_SECRET(ppp_ptr,_PPP_CHAP_LSECRETS) == NULL) {
/* End CR 2207 */
               CI_NAKAP(4);
               break;
            } else if (*inp++ != 5) {     /* Only MD5 supported */
               CI_NAKAP(5);
               break;
            } /* Endif */
            req_opt.AP_Start = CHAP_open;
            break;

         default:
            CI_NAKAP(4);
            break;
         } /* Endswitch */
         break;

      case LCP_CI_MAGIC:
         if (cilen != 6) {
            CI_REJECT(2);
            break;
         } /* Endif */

         inp += 4;
         break;

      case LCP_CI_PFC:
         if (cilen != 2) {
            CI_REJECT(2);
            break;
         } /* Endif */

         req_opt.PFC = TRUE;
         break;

      case LCP_CI_ACFC:
         if (cilen != 2) {
            CI_REJECT(2);
            break;
         } /* Endif */

         req_opt.ACFC = TRUE;
         break;

      default:
         CI_REJECT(2);
         break;
      } /* Endswitch */
Beispiel #8
0
static bool LCP_recvconfnak
   (
      PPPFSM_CFG_PTR    fsm
            /* [IN] - State Machine */
   )
{ /* Body */
   LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
   unsigned char   *inp = fsm->DATA;
   uint32_t     sizeleft = fsm->LENGTH;
   LCP_NEG     req_neg = lcp_ptr->RECV_NEG;
   unsigned char       code;
/* Start CR 2207 */
#if PPP_SECRETS_NOT_SHARED
   PPP_CFG_PTR    ppp_ptr = lcp_ptr->HANDLE;
#endif
/* End CR 2207 */

#define LCP_RNAK(len) \
      if (sizeleft < len) goto badnak; \
      if (*inp++ != len)  goto badnak; \
      sizeleft -= len

   /*
   ** Nak'd codes must be in the same order as they were in the ConfReq
   */

   code = *inp++;

   if (sizeleft && req_neg.NEG_MRU && code == LCP_CI_MRU) {
      LCP_RNAK(4);

         /* We are prepared to accept maximum MRU of 1500 */
      req_neg.MRU = mqx_ntohs(inp); inp += 2;
      if (req_neg.MRU > DEFAULT_MRU) {
         req_neg.MRU = DEFAULT_MRU;
      } /* Endif */

      code = *inp++;
   } /* Endif */

   if (sizeleft && req_neg.NEG_ACCM && code == LCP_CI_ACCM) {
      LCP_RNAK(6);

         /* Add any characters they want to our ACCM */
      req_neg.ACCM |= mqx_ntohl(inp); inp += 4;

      code = *inp++;
   } /* Endif */

   if (sizeleft && req_neg.NEG_AP && code == LCP_CI_AP) {
      if (sizeleft < *inp || *inp < 4) goto badnak;
      sizeleft -= *inp;

         /*
         ** If AP is nak'd, we don't care what they want --
         ** we choose the next most desirable protocol.  If there
         ** aren't any more to choose, we keep the last one we tried.
         */
      inp += *inp - 1;
      
      if (PPP_SECRET(ppp_ptr,_PPP_CHAP_RSECRETS)) {
          req_neg.AP = PPP_PROT_CHAP;
      } else {
        switch (req_neg.AP) {
        case PPP_PROT_CHAP:
             /* CHAP was NAKed, try PAP */ 
             if (PPP_SECRET(ppp_ptr,_PPP_PAP_RSECRETS)) {
                req_neg.AP = PPP_PROT_PAP;            
             } /* Endif */
             break;
        
        case PPP_PROT_PAP:
           /* no other authentication protocols known */
           break;
           
        default:
            /* Unknown protocol NAKed, try CHAP */
            if (PPP_SECRET(ppp_ptr,_PPP_CHAP_RSECRETS)) {
                req_neg.AP = PPP_PROT_CHAP;
            }
            break;

        } /* Endswitch */
      }
      code = *inp++;
   } /* Endif */

   /*
   ** If we advertised PFC and/or ACFC and the peer doesn't
   ** want it, they should send a ConfRej rather than a ConfNak,
   ** so we're not going to check for them here (if they are
   ** here, the switch statement below will catch it).
   */


#define LCP_RNAK_ADD(ci,len) \
         if (req_neg.NEG_ ## ci || sizeleft < len || *inp++ != len) goto badnak; \
         sizeleft -= len;                                                        \
         req_neg.NEG_ ## ci = 1

   /*
   ** There may be remaining codes if the peer wants us to
   ** negotiate an option we didn't include.
   */

   while (sizeleft) {
      switch (code) {
      case LCP_CI_MRU:
         LCP_RNAK_ADD(MRU,4);
         req_neg.MRU = mqx_ntohs(inp); inp += 2;
         if (req_neg.MRU > DEFAULT_MRU) {
            req_neg.MRU = DEFAULT_MRU;
         } /* Endif */
         break;
      case LCP_CI_ACCM:
         LCP_RNAK_ADD(ACCM,6);
         req_neg.ACCM |= mqx_ntohl(inp); inp += 4;
         break;
      case LCP_CI_AP:
         if (req_neg.NEG_AP || sizeleft < *inp || *inp < 4) goto badnak;
         sizeleft -= *inp;
            /*
            ** If AP is nak'd, we don't care what they want --
            ** we still don't negotiate
            */
         inp += *inp - 1;
         break;
      case LCP_CI_PFC:
         LCP_RNAK_ADD(PFC,2);
         break;
      case LCP_CI_ACFC:
         LCP_RNAK_ADD(ACFC,2);
         break;
      default:
         if (sizeleft < *inp || *inp < 2) goto badnak;
         sizeleft -= *inp;
         inp += *inp - 1;
      } /* Endswtich */
      code = *inp++;
   } /* Endwhile */

   if (fsm->STATE < PPP_STATE_OPENED) {
      lcp_ptr->RECV_NEG = req_neg;
   } /* Endif */
   return TRUE;

badnak:
   return FALSE;

} /* Endbody */
Beispiel #9
0
void CHAP_input
   (
      PCB_PTR        pcb,
            /* [IN] - CHAP packet */
      _ppp_handle    handle
            /* [IN] - the PPP state structure */
   )
{ /* Body */
   PPP_CFG_PTR    ppp_ptr = handle;
   CHAP_DATA_PTR  chap_ptr = &ppp_ptr->CHAP_STATE;
   PPP_SECRET_PTR secret;
   uchar_ptr      inp = pcb->FRAG[0].FRAGMENT + 2;
   uchar_ptr      valp, idp;
   uchar          code, id;
   uchar          vallen, idlen, namelen;
   uint_16        len;
   boolean        delay = FALSE;

   /*
   ** Parse header (code, id and length).
   ** If packet too short, drop it.
   */
   if (pcb->FRAG[0].LENGTH < 2 + CHAP_HDR_LEN) {
      chap_ptr->ST_CHAP_SHORT++;
      PCB_free(pcb);
      return;
   } /* Endif */

   code = *inp++;
   id = *inp++;
   len = *inp++ << 8;
   len += *inp++;

   if ((len < CHAP_HDR_LEN) || (len > pcb->FRAG[0].LENGTH - 2)) {
      chap_ptr->ST_CHAP_SHORT++;
      PCB_free(pcb);
      return;
   } /* Endif */
   len -= CHAP_HDR_LEN;

   /*
   ** For Challenge and Response packets, also parse the
   ** value and name fields.
   */
   if ((code == CHAP_CODE_CHALLENGE) || (code == CHAP_CODE_RESPONSE)) {

      if (len < 1) {
         chap_ptr->ST_CHAP_SHORT++;
         PCB_free(pcb);
         return;
      } /* Endif */
      valp = inp;
      vallen = *valp++;
      len--;

      if (len < vallen) {
         chap_ptr->ST_CHAP_SHORT++;
         PCB_free(pcb);
         return;
      } /* Endif */
      idp = valp + vallen;
      idlen = len - vallen;

   } /* Endif */

   switch (code) {

   case CHAP_CODE_CHALLENGE:

      if (chap_ptr->CLIENT_STATE != CHAP_STATE_INITIAL) {
         chap_ptr->ST_CHAP_NOAUTH++;
         PCB_free(pcb);
         break;
      } /* Endif */

      /* OK -- Generate a Response packet */
      /* Start CR 2207 */
      secret = PPP_SECRET(ppp_ptr,_PPP_CHAP_LSECRETS);
      /* End CR 2207 */
      inp = pcb->FRAG[0].FRAGMENT + 2;
      *inp++ = CHAP_CODE_RESPONSE;
      inp++;                           /* Keep same ID */
      /* Start CR 2207 */
      namelen = strlen(PPP_SECRET(ppp_ptr,_PPP_CHAP_LNAME));
      /* End CR 2207 */
      len = CHAP_HDR_LEN + 1 + 16 + namelen;
      *inp++ = (len >> 8) & 0xFF;
      *inp++ =  len       & 0xFF;
      *inp++ = 16;
      for (;;) {
         if ((secret->PPP_ID_LENGTH == 0)
          && (secret->PPP_PW_LENGTH == 0)) {
            /* Couldn't find a secret for this peer */
            chap_ptr->ST_CHAP_NOPW++;
            PPP_MD5(inp, (uint_32)1, &id,       /* id */
                         (uint_32)vallen, valp, /* challenge */
                         (uint_32)0);
            break;
         } /* Endif */
         if ((secret->PPP_ID_LENGTH == idlen)
          && (memcmp(secret->PPP_ID_PTR, idp, idlen) == 0)) {
            /* Found a secret; send response */
            PPP_MD5(inp, (uint_32)1, &id,                /* id */
                         (uint_32)secret->PPP_PW_LENGTH, /* secret */
                         secret->PPP_PW_PTR,
                         (uint_32)vallen, valp,          /* challenge */
                         (uint_32)0);
            break;
         } /* Endif */
         secret++;
      } /* Endfor */
      inp += 16;
      /* Start CR 2207 */
      PPP_memcopy(PPP_SECRET(ppp_ptr,_PPP_CHAP_LNAME), inp, namelen);
      /* End CR 2207 */
      pcb->FRAG[0].LENGTH = len + 2;
      PPP_send_one(ppp_ptr, PPP_PROT_CHAP, pcb);
      break;

   case CHAP_CODE_RESPONSE:

      switch (chap_ptr->SERVER_STATE) {
      case CHAP_STATE_INITIAL:

         /* Check the ID against our last challenge */
         if (id != chap_ptr->CURID) {
            chap_ptr->ST_CHAP_ID++;
            PCB_free(pcb);
            break;
         } /* Endif */

         /* Stop the challenge, whether or not the response is correct */
         PPP_send_stop(ppp_ptr, PPP_PROT_CHAP);

         chap_ptr->SERVER_STATE = CHAP_STATE_FAILURE;

         if (vallen != 16) {
            delay = TRUE;
            CHAP_fail(handle);

         } else {
            /* Search for name in the secrets table */
            /* Start CR 2207 */
            secret = PPP_SECRET(ppp_ptr,_PPP_CHAP_RSECRETS);
            /* End CR 2207 */
            for (;;) {
               if ((secret->PPP_ID_LENGTH == 0)
                && (secret->PPP_PW_LENGTH == 0)) {
                     /* Couldn't find a secret for this peer */
                  delay = TRUE;
                  CHAP_fail(handle);
                  break;
               } /* Endif */
               if ((secret->PPP_ID_LENGTH == idlen)
                && (memcmp(secret->PPP_ID_PTR, idp, idlen) == 0)) {
                     /* Found a secret; compute hash */
                  uchar digest[16];

                  PPP_MD5(digest, (uint_32)1, &id,                /* id */
                                  (uint_32)secret->PPP_PW_LENGTH, /* secret */
                                  secret->PPP_PW_PTR,
                                  (uint_32)CHAP_CHALLENGE_LEN,    /* challenge */
                                  chap_ptr->MD5,
                                  (uint_32)0);

                  if (memcmp(digest, valp, vallen) == 0) {
                     chap_ptr->SERVER_STATE = CHAP_STATE_SUCCESS;
                     CHAP_up(handle);
                  } else {
                     delay = TRUE;
                     CHAP_fail(handle);
                  } /* Endif */
                  break;
               } /* Endif */
               secret++;
            } /* Endfor */
         } /* Endif */

         /* fall through */
      case CHAP_STATE_SUCCESS:
      case CHAP_STATE_FAILURE:
         /* Build a Success or Failure reply */
         inp = pcb->FRAG[0].FRAGMENT + 2;
         *inp++ = chap_ptr->SERVER_STATE;
         inp++;                              /* Keep same ID */
         *inp++ = 0;
         *inp++ = 4;
         pcb->FRAG[0].LENGTH = 6;
         if (delay) {
            PPP_send_rexmit(ppp_ptr, PPP_PROT_CHAP, pcb, 1, CHAP_close, handle);
         } else {
            PPP_send_one(ppp_ptr, PPP_PROT_CHAP, pcb);
         } /* Endif */
         break;

      default:
         chap_ptr->ST_CHAP_NOCHAL++;
         PCB_free(pcb);
         break;
      } /* Endswitch */
      break;

   case CHAP_CODE_SUCCESS:
       /* Authentication success */
       chap_ptr->CLIENT_STATE = CHAP_STATE_SUCCESS;
       CHAP_up(handle);
   case CHAP_CODE_FAILURE:
       /* Authentication failure */
      if (chap_ptr->CLIENT_STATE != CHAP_STATE_SUCCESS)
      {
          /* Change client state when authenticate failure */
          chap_ptr->CLIENT_STATE = CHAP_STATE_FAILURE;
          if (chap_ptr->CLIENT_STATE != CHAP_STATE_INITIAL)
          {
             chap_ptr->ST_CHAP_NOAUTH++;
          }
          CHAP_fail(handle);
      } /* Endif */
      PCB_free(pcb);
      break;

   default:
      chap_ptr->ST_CHAP_CODE++;
      PCB_free(pcb);
      break;
   } /* Endswitch */

} /* Endbody */