예제 #1
0
static void PPPFSM_recvcoderej
   (
      PPPFSM_CFG_PTR    fsm
            /* [IN/OUT] - State Machine */
   )
{ /* Body */

   if (fsm->LENGTH < CP_HDR_LEN) {
      ++fsm->ST_CP_SHORT;
      PCB_free(fsm->PACKET);
      return;
   } /* Endif */

   /*
   ** Check if Code-Reject is catastrophic
   **
   ** !! Packet consumed here !!
   */
   if (!fsm->CALL->testcode || !fsm->CALL->testcode(fsm)) {
      if (fsm->STATE == PPP_STATE_ACK_RCVD) {
         fsm->STATE = PPP_STATE_REQ_SENT;
      } /* Endif */
      PCB_free(fsm->PACKET);

   } else {

      switch (fsm->STATE) {
      case PPP_STATE_CLOSING:
         PCB_free(fsm->PACKET);
         PPP_send_stop(fsm->HANDLE, fsm->CALL->PROTOCOL);
         fsm->STATE = PPP_STATE_CLOSED;
         break;

      case PPP_STATE_STOPPING:
      case PPP_STATE_REQ_SENT:
      case PPP_STATE_ACK_RCVD:
      case PPP_STATE_ACK_SENT:
         PCB_free(fsm->PACKET);
         PPP_send_stop(fsm->HANDLE, fsm->CALL->PROTOCOL);
         fsm->STATE = PPP_STATE_STOPPED;
         break;

      case PPP_STATE_OPENED:
         if (fsm->CALL->linkdown) {
            fsm->CALL->linkdown(fsm);
         } /* Endif */
         PPPFSM_sendtermreq(fsm, fsm->PACKET);
         fsm->STATE = PPP_STATE_STOPPING;
         break;

      default:
         PCB_free(fsm->PACKET);
         break;
      } /* Endswitch */
   } /* Endif */

} /* Endbody */
예제 #2
0
void PPPFSM_lowerdown
   (
      PPPFSM_CFG_PTR    fsm
         /* [IN/OUT] - State Machine */
   )
{ /* Body */

#if RTCSCFG_ENABLE_IP4

   PPP_CFG_PTR    ppp_ptr = fsm->HANDLE;

   PPP_mutex_lock(&fsm->MUTEX);

   switch(fsm->STATE)  {
   case PPP_STATE_CLOSED:
      fsm->STATE = PPP_STATE_INITIAL;
      break;

   case PPP_STATE_STOPPED:
      fsm->STATE = PPP_STATE_STARTING;
      break;

   case PPP_STATE_CLOSING:
      fsm->STATE = PPP_STATE_INITIAL;
      PPP_send_stop(ppp_ptr, fsm->CALL->PROTOCOL);
      break;

   case PPP_STATE_STOPPING:
   case PPP_STATE_REQ_SENT:
   case PPP_STATE_ACK_RCVD:
   case PPP_STATE_ACK_SENT:
      fsm->STATE = PPP_STATE_STARTING;
      PPP_send_stop(ppp_ptr, fsm->CALL->PROTOCOL);
      break;

   case PPP_STATE_OPENED:
      if (fsm->CALL->linkdown) {
         fsm->CALL->linkdown(fsm);
      } /* Endif */
      fsm->STATE = PPP_STATE_STARTING;
      break;
   } /* Endswitch */

   PPP_mutex_unlock(&fsm->MUTEX);

#endif /* RTCSCFG_ENABLE_IP4 */
   
} /* Endbody */
예제 #3
0
static void PPPFSM_recvtermack
   (
      PPPFSM_CFG_PTR    fsm
            /* [IN/OUT] - State Machine */
   )
{ /* Body */

   switch (fsm->STATE) {
   case PPP_STATE_CLOSING:
   case PPP_STATE_STOPPING:
      PCB_free(fsm->PACKET);
      PPP_send_stop(fsm->HANDLE, fsm->CALL->PROTOCOL);
      fsm->STATE -= 2;  /* Stopping/Closing -> Stopped/Closed */
      break;

   case PPP_STATE_ACK_RCVD:
      PCB_free(fsm->PACKET);
      fsm->STATE = PPP_STATE_REQ_SENT;
      break;

   case PPP_STATE_OPENED:
      if (fsm->CALL->linkdown) {
         fsm->CALL->linkdown(fsm);
      } /* Endif */
      PPPFSM_sendconfreq(fsm, fsm->PACKET);
      fsm->STATE = PPP_STATE_REQ_SENT;
      break;

   default:
      PCB_free(fsm->PACKET);
      break;
   } /* Endswitch */

} /* Endbody */
예제 #4
0
static void PPPFSM_sendtermreq
   (
      PPPFSM_CFG_PTR    fsm,
            /* [IN/OUT] - State Machine */
      PCB_PTR           packet
            /* [IN] - free packet */
   )
{ /* Body */
   PPP_CFG_PTR    ppp_ptr = fsm->HANDLE;

   /* Stop the retransmission timer if necessary */
   if (fsm->STATE > PPP_STATE_STOPPED && fsm->STATE < PPP_STATE_OPENED) {
      PPP_send_stop(ppp_ptr, fsm->CALL->PROTOCOL);
   } /* Endif */

   /* Allocate a packet if necessary */
   if (!packet) {
      packet = PPP_pcballoc(fsm->CALL->PROTOCOL, CP_HDR_LEN);
      if (!packet) {
         ++fsm->ST_CP_NOBUFS;    /* Nonfatal error */
         return;
      } /* Endif */
   } /* Endif */

   PPPFSM_buildheader(fsm, packet, CP_CODE_TERM_REQ, FALSE, 0);

   PPP_send_rexmit(ppp_ptr, fsm->CALL->PROTOCOL, packet,
                   _PPP_MAX_TERM_RETRIES, PPPFSM_timeout, fsm);

} /* Endbody */
예제 #5
0
static void PPPFSM_sendconfreq
   (
      PPPFSM_CFG_PTR    fsm,
            /* [IN/OUT] - State Machine */
      PCB_PTR           packet
            /* [IN] - free packet */
   )
{ /* Body */
   PPP_CFG_PTR    ppp_ptr = fsm->HANDLE;
   unsigned char      *outp;
   uint32_t        size;

   if (fsm->STATE <= PPP_STATE_STOPPING || fsm->STATE >= PPP_STATE_OPENED) {
      /* Not currently negotiating -- reset options */
      if (fsm->CALL->resetreq) {
         fsm->CALL->resetreq(fsm);
      } /* Endif */
      fsm->NAKS = 0;
   } /* Endif */

   /* Stop the retransmission timer if necessary */
   if (fsm->STATE > PPP_STATE_STOPPED && fsm->STATE < PPP_STATE_OPENED) {
      PPP_send_stop(ppp_ptr, fsm->CALL->PROTOCOL);
   } /* Endif */

   /* Allocate a packet if necessary */
   if (!packet) {
      packet = PPP_pcballoc(fsm->CALL->PROTOCOL, ppp_ptr->SEND_OPTIONS->MRU);
      if (!packet) {
         ++fsm->ST_CP_NOBUFS;    /* Nonfatal error */
         return;
      } /* Endif */
   } /* Endif */

   /* Build the request packet */
   outp = packet->FRAG[0].FRAGMENT + 2;
   size = packet->FRAG[0].LENGTH - 2 - CP_HDR_LEN;

   if (fsm->CALL->buildreq) {
      size = fsm->CALL->buildreq(fsm, outp + CP_HDR_LEN, size);
   } /* Endif */

   fsm->REQID = fsm->CURID;
   PPPFSM_buildheader(fsm, packet, CP_CODE_CONF_REQ, FALSE, size);

   /* Send the request */
   PPP_send_rexmit(ppp_ptr, fsm->CALL->PROTOCOL, packet,
                   _PPP_MAX_CONF_RETRIES, PPPFSM_timeout, fsm);

} /* Endbody */
예제 #6
0
파일: pap.c 프로젝트: jewlenchow/MQX_3.8.1
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 */
예제 #7
0
static bool LCP_recvextcode
   (
      PPPFSM_CFG_PTR    fsm
            /* [IN] - State Machine */
   )
{ /* Body */
   PPP_CFG_PTR ppp_ptr = fsm->HANDLE;
   LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
   PPP_CALL_INTERNAL_PTR call_ptr = &ppp_ptr->LCP_CALL[PPP_CALL_ECHO_REPLY];

   switch (fsm->CODE) {
   case LCP_CODE_PROT_REJ:
      lcp_ptr->ST_LCP_RX_REJECT++;

      /*
      ** We should notify the rejected protocol, but there
      ** currently isn't any way to do this.  What we'll do
      ** instead is to send a STOP message to the Tx task on
      ** behalf of the protocol.
      **
      ** This will usually be sufficient, since the rejected
      ** protocol isn't likely to send another packet until
      ** either it receives a packet (in which case it's OK to
      ** reply) or the retransmission timer kicks in (which
      ** we're about to disable).
      **
      ** Thus, this will effectively stop the rejected protocol.
      */

      if (fsm->LENGTH >= 2) {
         uint16_t protocol = mqx_ntohs(fsm->DATA);
         PPP_send_stop(ppp_ptr, protocol);
      } /* Endif */
      PCB_free(fsm->PACKET);
      break;

   case LCP_CODE_ECHO_REQ:
      lcp_ptr->ST_LCP_RX_ECHO++;
      if (fsm->STATE < PPP_STATE_OPENED) {
         PCB_free(fsm->PACKET);
      } else {
         mqx_htonc(fsm->DATA - CP_HDR_LEN, LCP_CODE_ECHO_REP);
         mqx_htonl(fsm->DATA, 0);                      /* Set magic field to 0 */
         lcp_ptr->ST_LCP_TX_REPLY++;
         PPP_send_one(ppp_ptr, PPP_PROT_LCP, fsm->PACKET);
      } /* Endif */
      break;

   case LCP_CODE_ECHO_REP:
      lcp_ptr->ST_LCP_RX_REPLY++;
      if (call_ptr->CALLBACK) {
         call_ptr->CALLBACK(call_ptr->PARAM, fsm->ID, fsm->PACKET);
      } /* Endif */
      PCB_free(fsm->PACKET);
      break;

   case LCP_CODE_DISC_REQ:
      lcp_ptr->ST_LCP_RX_DISCARD++;
      PCB_free(fsm->PACKET);
      break;

   default:
      return FALSE;
   } /* Endswitch */

   return TRUE;
} /* Endbody */
예제 #8
0
static void PPPFSM_recvconfack
   (
      PPPFSM_CFG_PTR    fsm
            /* [IN/OUT] - State Machine */
   )
{ /* Body */

   /* Verify the packet */
   if (fsm->ID != fsm->REQID) {
      PCB_free(fsm->PACKET);
      return;
   } else if (fsm->CALL->recvack) {
      if (!fsm->CALL->recvack(fsm)) {
         ++fsm->ST_CP_BAD_ACK;
         PCB_free(fsm->PACKET);
         return;
      } /* Endif */
   } else if (fsm->LENGTH) {
      ++fsm->ST_CP_BAD_ACK;
      PCB_free(fsm->PACKET);
      return;
   } /* Endif */

   /*
   ** !! Packet consumed here !!
   */
   switch (fsm->STATE) {
   case PPP_STATE_CLOSED:
   case PPP_STATE_STOPPED:
      
      PPPFSM_sendtermack(fsm, FALSE);
      break;

   case PPP_STATE_REQ_SENT:
      /* Restart retransmissions */
      fsm->STATE = PPP_STATE_ACK_RCVD;
      PCB_free(fsm->PACKET);
      PPP_send_restart(fsm->HANDLE, fsm->CALL->PROTOCOL);
      break;

   case PPP_STATE_ACK_RCVD:
      PPPFSM_sendconfreq(fsm, fsm->PACKET);
      fsm->STATE = PPP_STATE_REQ_SENT;
      break;

   case PPP_STATE_ACK_SENT:
      /* Inform upper layers */
      if (fsm->CALL->linkup) {
         if (!fsm->CALL->linkup(fsm)) {
            PPPFSM_sendtermreq(fsm, fsm->PACKET);
            fsm->STATE = PPP_STATE_CLOSING;
            return;
         } /* Endif */
      } /* Endif */
      fsm->STATE = PPP_STATE_OPENED;
      PCB_free(fsm->PACKET);
      PPP_send_stop(fsm->HANDLE, fsm->CALL->PROTOCOL);
      break;

   case PPP_STATE_OPENED:
      /* Restart negotiation */
      if (fsm->CALL->linkdown) {
         fsm->CALL->linkdown(fsm);
      } /* Endif */
      PPPFSM_sendconfreq(fsm, fsm->PACKET);
      fsm->STATE = PPP_STATE_REQ_SENT;
      break;

   default:
      PCB_free(fsm->PACKET);
      break;
   } /* Endswitch */

} /* Endbody */
예제 #9
0
static void PPPFSM_recvconfreq
   (
      PPPFSM_CFG_PTR    fsm,
            /* [IN/OUT] - State Machine */
      _ppp_handle       handle
            /* [IN] - the PPP state structure */
   )
{ /* Body */
   PPP_CFG_PTR    ppp_ptr = handle;
   uint32_t        size;

   switch (fsm->STATE) {
   case PPP_STATE_CLOSED:
      PPPFSM_sendtermack(fsm, FALSE);
      return;
   case PPP_STATE_CLOSING:
   case PPP_STATE_STOPPING:
      PCB_free(fsm->PACKET);
      return;

   case PPP_STATE_OPENED:
      /* Go down and restart negotiation */
      if (fsm->CALL->linkdown) {
         fsm->CALL->linkdown(fsm);
      } /* Endif */
      PPPFSM_sendconfreq(fsm, NULL);
      fsm->STATE = PPP_STATE_REQ_SENT;
      break;

   case PPP_STATE_STOPPED:
      /* Negotiation started by our peer */
      PPPFSM_sendconfreq(fsm, NULL);
      fsm->STATE = PPP_STATE_REQ_SENT;
      break;
   } /* Endswitch */

   /*
   ** Pass the requested configuration options
   ** to protocol-specific code for checking.
   **
   ** !! Packet consumed here !!
   */
   if (fsm->CALL->recvreq) {    /* Check CI */
      size = fsm->CALL->recvreq(fsm, fsm->NAKS >= _PPP_MAX_CONF_NAKS);
      PPPFSM_buildheader(fsm, fsm->PACKET, 0, TRUE, size);
      PPP_send_one(ppp_ptr, fsm->CALL->PROTOCOL, fsm->PACKET);
   } else if (fsm->LENGTH) {
      PPPFSM_sendconfrep(fsm, CP_CODE_CONF_REJ);
   } else {
      PPPFSM_sendconfrep(fsm, CP_CODE_CONF_ACK);
   } /* Endif */

   if (fsm->CODE == CP_CODE_CONF_ACK) {
      if (fsm->STATE == PPP_STATE_ACK_RCVD) {
         /* Inform upper layers */
         if (fsm->CALL->linkup) {
            if (!fsm->CALL->linkup(fsm)) {
               PPPFSM_sendtermreq(fsm, NULL);
               fsm->STATE = PPP_STATE_CLOSING;
               return;
            } /* Endif */
         } /* Endif */
         fsm->STATE = PPP_STATE_OPENED;
         PPP_send_stop(ppp_ptr, fsm->CALL->PROTOCOL);
      } else {
         fsm->STATE = PPP_STATE_ACK_SENT;
      } /* Endif */
      fsm->NAKS = 0;

   } else { /* We sent a NAK or a REJ */
      if (fsm->STATE != PPP_STATE_ACK_RCVD) {
         fsm->STATE = PPP_STATE_REQ_SENT;
      } /* Endif */
      if (fsm->CODE == CP_CODE_CONF_NAK ) {
         ++fsm->NAKS;
      } /* Endif */
   } /* Endif */
} /* Endbody */
예제 #10
0
파일: chap.c 프로젝트: jewlenchow/MQX_3.8.1
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 */