Exemple #1
0
void NAT_ALG_TCP_checksum
   (
      IP_HEADER_PTR    ip_header_ptr    /* [IN]  pointer to IP header */
   )
{ /* Body */
   TRANSPORT_UNION    transport;
   uint16_t           checksum;
   uint16_t           protocol;
   uint16_t           iplen = IPH_LEN(ip_header_ptr);
   uint16_t           len = mqx_ntohs(ip_header_ptr->LENGTH) - iplen; 
   
   /* Get TCP header */
   transport.PTR = TRANSPORT_PTR(ip_header_ptr);

   mqx_htons(transport.TCP_PTR->checksum, 0);    /* Clear checksum field */
   protocol = mqx_ntohc(ip_header_ptr->PROTOCOL); /* PROTOCOL */
   checksum = (uint16_t) _mem_sum_ip(protocol, 8, ip_header_ptr->SOURCE);  /* IP SRC and DST ADDR */
   checksum = (uint16_t) _mem_sum_ip(checksum, len, transport.PTR);

   /* TCP LENGTH */
   checksum = IP_Sum_immediate(checksum, len);
   
   checksum = IP_Sum_invert(checksum);
   mqx_htons(transport.TCP_PTR->checksum, checksum);   

} /* Endbody */
void TFTPSRV_build_ACK
   (
      TFTP_TRANS_STRUCT_PTR   trans_ptr
         /* [IN/OUT] The transaction state */
   )
{ /* Body */
   mqx_htons(trans_ptr->SND.HEAD.OP,    trans_ptr->SEND_OP);
   mqx_htons(trans_ptr->SND.HEAD.BLOCK, trans_ptr->BLOCK);
   trans_ptr->BLOCK++;
   trans_ptr->SEND_SIZE = sizeof(TFTP_HEADER);
   trans_ptr->NUM_RETRIES = 0;
} /* Endbody */
Exemple #3
0
void LCP_sendprotrej
   (
      PCB_PTR           pcb,
            /* [IN] - packet to reject */
      PPPFSM_CFG_PTR    fsm
            /* [IN/OUT] - State Machine */
   )
{ /* Body */

#if RTCSCFG_ENABLE_IP4

   PPP_CFG_PTR ppp_ptr = fsm->HANDLE;
   LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
   unsigned char   *packet, *src, *dst;
   uint16_t     length;
   uint16_t     size = ppp_ptr->SEND_OPTIONS->MRU - CP_HDR_LEN;

   length = pcb->FRAG[0].LENGTH;
   packet = pcb->FRAG[0].FRAGMENT;

   /* Truncate the packet if necessary */
   if (length > size) {
      length = size;
   } /* Endif */

   /* Make room for a Code-Reject header */
   size = length + CP_HDR_LEN;

   /* Copy the received packet (including protocol field) to the */
   /* data portion of the Protocol-Reject                        */
   src = packet + length;
   dst = src + 2 + CP_HDR_LEN;
   while (length--) *--dst = *--src;

   /* Build a Code-Reject packet */
   mqx_htons(packet, PPP_PROT_LCP); packet += 2;
   *packet++ = LCP_CODE_PROT_REJ;
   *packet++ = fsm->CURID;
   fsm->CURID = (fsm->CURID + 1) & 0xFF;
   mqx_htons(packet, size); packet += 2;
   pcb->FRAG[0].LENGTH = size + 2;

   lcp_ptr->ST_LCP_TX_REJECT++;
   PPP_send_one(ppp_ptr, PPP_PROT_LCP, pcb);

#else

    PCB_free(pcb);

#endif /* RTCSCFG_ENABLE_IP4  */

} /* Endbody */
Exemple #4
0
PCB_PTR PPP_pcballoc
   (
      uint16_t protocol,
            /* [IN] - PPP protocol */
      uint32_t size
            /* [IN] - max size of packet, excluding protocol */
   )
{ /* Body */
   PCB_FRAGMENT      *pcb_frag_ptr;
   PCB_PTR packet;

   packet = _mem_alloc_system(sizeof(PCB) + sizeof(PCB_FRAGMENT) + 2 + size);
   if (packet)
   {
      packet->FREE = (void (_CODE_PTR_)(PCB_PTR))_mem_free;
      pcb_frag_ptr = packet->FRAG;
      pcb_frag_ptr->LENGTH   = size + 2;
      pcb_frag_ptr->FRAGMENT = (unsigned char *)packet + sizeof(PCB) + sizeof(PCB_FRAGMENT);
      mqx_htons(pcb_frag_ptr->FRAGMENT, protocol);
      pcb_frag_ptr++;
      pcb_frag_ptr->LENGTH   = 0;
      pcb_frag_ptr->FRAGMENT = NULL;
   } /* Endif */

   return packet;

} /* Endbody */
void TFTPSRV_build_DATA
   (
      TFTP_TRANS_STRUCT_PTR   trans_ptr
         /* [IN/OUT] The transaction state */
   )
{ /* Body */
   int32_t datalen;

   datalen = RTCS_io_read(trans_ptr->TRANS_FILE_PTR, (char *)trans_ptr->SND.DATA, TFTP_DATA_SIZE);
   if (datalen < 0) {
      datalen = 0;
   } /* Endif */

   trans_ptr->BLOCK++;
   mqx_htons(trans_ptr->SND.HEAD.OP,    trans_ptr->SEND_OP);
   mqx_htons(trans_ptr->SND.HEAD.BLOCK, trans_ptr->BLOCK);
   trans_ptr->SEND_SIZE = sizeof(TFTP_HEADER) + datalen;
   trans_ptr->NUM_RETRIES = 0;
   trans_ptr->EXIT = (trans_ptr->SEND_SIZE < sizeof(TFTP_PACKET));
} /* Endbody */
Exemple #6
0
static void RIP_build_header(
    unsigned char   *buf,        /* [OUT] the rip header */
    uint8_t      cmd,        /* [IN] the commande */
    uint8_t      version     /* [IN] the version */
)
{ /* Body */
    RIP_HEADER_PTR  hd = (RIP_HEADER_PTR)buf;
    _mem_zero(buf, sizeof(RIP_HEADER));
    mqx_htonc(hd->COMMAND, cmd);
    mqx_htonc(hd->VERSION, version);
    mqx_htons(hd->MBZ, 0);
} /* Endbody */
Exemple #7
0
static void RIP_build_rte(
    unsigned char   *buf,    /* [OUT] the route entry */
    uint16_t     family,
    uint16_t     rt_tag,
    _ip_address net_addr,
    _ip_address net_mask,
    _ip_address next_hop,
    uint32_t     metric,
    uint32_t     rip_vers
)
{ /* Body */
    RIP_ENTRY_PTR   rte = (RIP_ENTRY_PTR)buf;
    if (rip_vers == RIP_V2){
        mqx_htons(rte->RT_TAG, rt_tag);
        mqx_htonl(rte->NETMASK, net_mask);
        mqx_htonl(rte->NEXTHOP, next_hop);
    }else{
        _mem_zero(buf, sizeof(RIP_ENTRY));
    }
    mqx_htons(rte->FAMILY, family);
    mqx_htonl(rte->NETADDR, net_addr);
    mqx_htonl(rte->METRIC, metric);
} /* Endbody */
Exemple #8
0
void BOOTP_open
   (
      TCPIP_PARM_BOOTP  *parms
   )
{ /* Body */
   IP_IF_PTR      if_ptr = (IP_IF_PTR)parms->handle;
   BOOTP_CFG_PTR  bootp = (BOOTP_CFG_PTR) &parms->config;
   uint32_t        error;

   error = BOOT_open(BOOT_service);
   if (error) {
      RTCSCMD_complete(parms, error);
      return;
   } /* Endif */

   if_ptr->BOOTFN = BOOTP_service;

   /* Pick a random transaction ID */
   bootp->XID = RTCS_rand();

   /* Set initial timeout */
   bootp->TIMEOUT = BOOTP_TIMEOUT_MIN;
   bootp->SECS = 0;

   /* Build a BOOTREQUEST packet */
   mqx_htonc(bootp->PACKET.OP,    BOOTPOP_BOOTREQUEST);
   mqx_htonc(bootp->PACKET.HTYPE, if_ptr->DEV_TYPE);
   mqx_htonc(bootp->PACKET.HLEN,  if_ptr->DEV_ADDRLEN);
   mqx_htonc(bootp->PACKET.HOPS,  0);
   mqx_htonl(bootp->PACKET.XID,   bootp->XID);
   mqx_htons(bootp->PACKET.FLAGS, 0x8000);
   mqx_htonl(bootp->PACKET.CIADDR, INADDR_ANY);
   mqx_htonl(bootp->PACKET.YIADDR, INADDR_ANY);
   mqx_htonl(bootp->PACKET.SIADDR, INADDR_ANY);
   mqx_htonl(bootp->PACKET.GIADDR, INADDR_ANY);

   _mem_zero(bootp->PACKET.CHADDR, sizeof(bootp->PACKET.CHADDR));
   _mem_copy(if_ptr->DEV_ADDR, bootp->PACKET.CHADDR, if_ptr->DEV_ADDRLEN);

   /* Start the retransmission timer to start sending immediately */
   bootp->RESEND.TIME    = 0;
   bootp->RESEND.EVENT   = BOOTP_send;
   bootp->RESEND.PRIVATE = if_ptr;
   TCPIP_Event_add(&bootp->RESEND);

   if_ptr->BOOT = (void *)parms;

} /* Endbody */
Exemple #9
0
bool BOOTP_send
   (
      TCPIP_EVENT_PTR   event
         /* [IN/OUT] the resend event */
   )
{ /* Body */
   IP_IF_PTR               if_ptr = (IP_IF_PTR)event->PRIVATE;
   TCPIP_PARM_BOOTP       *parms = (TCPIP_PARM_BOOTP *)if_ptr->BOOT;
   BOOTP_CFG_PTR           bootp = (BOOTP_CFG_PTR) &parms->config;
   RTCSPCB_PTR             pcb_ptr;

   /* Set the event to trigger for the next retransmission (+/- 1 sec) */
   bootp->RESEND.TIME = bootp->TIMEOUT + (RTCS_rand() & 0x7FF) - 0x400;

   /* Allocate a PCB */
   pcb_ptr = RTCSPCB_alloc_send();
   if (pcb_ptr == NULL) {
      return TRUE;
   } /* Endif */

   //RTCSLOG_PCB_ALLOC(pcb_ptr);

   /* The only field that changes in BOOTREQUEST packets is 'secs' */
   mqx_htons(bootp->PACKET.SECS, bootp->SECS);
   bootp->SECS += bootp->RESEND.TIME >> 10;     /* approx. divide by 1000 */

   /* Double the timeout */
   bootp->TIMEOUT <<= 1;
   if (bootp->TIMEOUT > BOOTP_TIMEOUT_MAX) {
      bootp->TIMEOUT = BOOTP_TIMEOUT_MAX;
   } /* Endif */

   /* Put the BOOTREQUEST in the PCB */
   RTCSPCB_append_fragment(pcb_ptr, sizeof(BOOTP_HEADER), (unsigned char *)&bootp->PACKET);
   RTCSPCB_append_fragment(pcb_ptr, sizeof(BOOTP_DATA),   parms->data->SNAME);

   RTCSLOG_PCB_WRITE(pcb_ptr, RTCS_LOGCTRL_PORT(IPPORT_BOOTPC), 0);

   /* Send the datagram */
   BOOT_send(pcb_ptr, if_ptr);

   /* Always retransmit */
   return TRUE;

} /* Endbody */
bool DHCP_option_int16
(
    unsigned char   * *optptr,
    uint32_t      *optlen,
    unsigned char             opttype,
    uint16_t           optval
)
{   /* Body */
    unsigned char *opt = *optptr;

    if ((*optlen) < 4) return FALSE;

    mqx_htonc(opt, opttype);
    opt++;
    mqx_htonc(opt, 2);
    opt++;
    mqx_htons(opt, optval);
    opt += 2;

    *optlen -= 4;
    *optptr = opt;
    return TRUE;

} /* Endbody */
Exemple #11
0
unsigned char *TFTP_read
   (
      uint32_t    *size
         /* [OUT] number of bytes read, or error code */
   )
{ /* Body */
   uint32_t        sock;
   sockaddr_in    remote_addr;
   uint16_t        remote_size;
   uint16_t        ack_block;
   uint16_t        pkt_op, pkt_block;
   uint32_t        pkt_size;
   uint32_t        time_left;
   bool        expired;
#if TFTP_TIMEOUT_RETRIES
   uint32_t        retries = 0;
#endif

   ack_block = mqx_ntohs(TFTP_config.ACK.BLOCK);
   TFTP_timeout_restart(&TFTP_config.TIMEOUT);

   for (;;) {

      /* Check for timeout */
      time_left = TFTP_timeout_left(&TFTP_config.TIMEOUT, &expired);
      if (expired) {
#if TFTP_TIMEOUT_RETRIES
         retries++;
         if (retries > TFTP_TIMEOUT_RETRIES) {
            *size = RTCSERR_TFTP_TIMEOUT;
            TFTP_close();
            return NULL;
         } /* Endif */
#endif
         /* Retransmit the last packet */
         TFTP_RESEND();
      } /* Endif */

      /* Wait for a packet */
      sock = TFTP_WAIT(time_left);

      /* Timeout -- retransmit last packet */
      if (sock != TFTP_config.SOCK) {
         continue;
      } /* Endif */

      remote_size = sizeof(remote_addr);
      pkt_size = TFTP_RECV(TFTP_config.PACKET);

      pkt_op    = mqx_ntohs(TFTP_config.PACKET.HEAD.OP);
      pkt_block = mqx_ntohs(TFTP_config.PACKET.HEAD.BLOCK);

      /* Check source address of received packet */
      if (remote_addr.sin_addr.s_addr != TFTP_config.SADDR.sin_addr.s_addr) {
         continue;
      } /* Endif */

      /* Validate source port */
      if (ack_block && remote_addr.sin_port != TFTP_config.SADDR.sin_port) {
         TFTP_SEND(TFTP_config.SOCK, _tftp_error_tid, remote_addr);
         continue;
      } /* Endif */

      /* Check size of received packet */
      if (pkt_size < sizeof(TFTP_HEADER)) {
         TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr);
         *size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP;
         TFTP_close();
         return NULL;
      } /* Endif */

      /* Check for error packet */
      if (pkt_op == TFTPOP_ERROR) {
         *size = RTCSERR_TFTP_ERROR + pkt_block;
         TFTP_close();
         return NULL;
      } /* Endif */

      /* Check for data packet */
      if ((pkt_op != TFTPOP_DATA)
       || (pkt_size > sizeof(TFTP_PACKET))) {
         TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr);
         *size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP;
         TFTP_close();
         return NULL;
      } /* Endif */

      /* Check for retransmitted packet */
      if (pkt_block == ack_block) {
         TFTP_timeout_restart(&TFTP_config.TIMEOUT);
         TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR);
         continue;
      } /* Endif */

      /* Aknowledge also packets with lower id, some servers do retransmit them until they get an ack */
      if (pkt_block < ack_block) {
         TFTP_timeout_restart(&TFTP_config.TIMEOUT);
         mqx_htons(TFTP_config.ACK.BLOCK, pkt_block);
         TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR);
         mqx_htons(TFTP_config.ACK.BLOCK, ack_block); /* Restore id of last acknowledged packet */
         continue;
      } /* Endif */

      /* Drop unexpected packets */
      if (pkt_block > ack_block+1) {
         /* Some server do send more than one packet at a time, these will eventually retransmitted */
         continue;
      }

      /* We have the next packet */
      break;
   } /* Endfor */

   /* Update the adaptive timeout */
   TFTP_timeout_update(&TFTP_config.TIMEOUT);

   /* Free the original RRQ */
   if (!ack_block) {
      TFTP_config.SADDR.sin_port = remote_addr.sin_port;
      _mem_free(TFTP_config.RRQ_PTR);
      TFTP_config.RRQ_PTR = NULL;
   } /* Endif */

   /* ACK it */
   ack_block++;
   mqx_htons(TFTP_config.ACK.BLOCK, ack_block);
   TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR);
   TFTP_config.LAST = (pkt_size < sizeof(TFTP_PACKET));

   /* Return the data */
   *size = pkt_size - sizeof(TFTP_HEADER);
   return TFTP_config.PACKET.DATA;

} /* Endbody */
Exemple #12
0
HOSTENT_STRUCT  *DNS_query_resolver_task
   (
   unsigned char  *name,
   uint16_t     query_type
   )

{  /* Body */

   DNS_MESSAGE_HEADER_STRUCT        *message_head_ptr;
   DNS_MESSAGE_TAIL_STRUCT          *message_tail_ptr;
   HOSTENT_STRUCT                   *host_ptr = NULL;
   sockaddr_in                       addr;
   uint32_t                           local_sock;
   uint32_t                           qname_size;
   uint32_t                           buffer_size;
   uint16_t                           rlen;
   int32_t                            temp_size;
   int32_t                            error;
   unsigned char                            *temp_ptr;
   unsigned char                            *qname_ptr;
   unsigned char                            *buffer_ptr;



   /*
   ** If the size of this buffer is changed, also change the buffer size
   ** in the recvfrom() call near the bottom of this function
   */
   buffer_ptr = RTCS_mem_alloc_zero( DNS_MAX_UDP_MESSAGE_SIZE );
   if ( buffer_ptr == NULL ) {
      RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_ALLOCATE_MEMORY,
                     0, 0, 0);
      return( NULL );
   }/* Endif */
   _mem_set_type(buffer_ptr, MEM_TYPE_DNS_UDP_MESSAGE);
   qname_ptr = buffer_ptr + sizeof( DNS_MESSAGE_HEADER_STRUCT );

   if ( query_type == DNS_A ) {
       error = DNS_is_dotted_domain_name( name, qname_ptr );
       if ( error == RTCSERR_DNS_INVALID_NAME ||
            error == RTCSERR_DNS_INVALID_LOCAL_NAME ) {
          _mem_free(buffer_ptr);
          return( NULL );
       }/* Endif */
   } else {
      if ( query_type == DNS_PTR ) {
         error = DNS_insert_IP_query( name, qname_ptr );
         if ( error == RTCSERR_DNS_INVALID_IP_ADDR ) {
            _mem_free(buffer_ptr);
            return( NULL );
         }/* Endif */
      } else {
         _mem_free(buffer_ptr);
         return( NULL );
      } /* Endif */
   } /* Endif */

   local_sock = socket(AF_INET, SOCK_DGRAM, 0);

   if ( local_sock == RTCS_HANDLE_ERROR ) {
      RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_OPEN_SOCKET,
                     0, 0, 0);
      _mem_free(buffer_ptr);
      return( NULL );
   }/* Endif */

   /* Local address  */
   addr.sin_family       = AF_INET;
   addr.sin_port         = 0;
   addr.sin_addr.s_addr  = INADDR_ANY;

   error =  bind(local_sock, &addr, sizeof(addr));
   if (error != RTCS_OK) {
      RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_BIND_SOCKET,
                     0, 0, 0);
      _mem_free(buffer_ptr);
      return( NULL );
   } /* Endif */

   /* set up buffer for sending query.   */
   message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT *)buffer_ptr;

   mqx_htons(message_head_ptr->ID, 0);
   mqx_htons(message_head_ptr->CONTROL, DNS_STANDARD_QUERY);
   mqx_htons(message_head_ptr->QDCOUNT, DNS_SINGLE_QUERY);
   mqx_htons(message_head_ptr->NSCOUNT, 0);
   mqx_htons(message_head_ptr->ARCOUNT, 0);
   mqx_htons(message_head_ptr->ANCOUNT, 0);

   qname_size = strlen((char *)qname_ptr );
   /* Need to include the last '\0' character as well */
   qname_size++;

   temp_ptr = buffer_ptr + sizeof( DNS_MESSAGE_HEADER_STRUCT )
                          + qname_size;

   message_tail_ptr = (DNS_MESSAGE_TAIL_STRUCT *)temp_ptr;

   mqx_htons(message_tail_ptr->QTYPE, query_type);
   mqx_htons(message_tail_ptr->QCLASS, DNS_IN);

   buffer_size = sizeof(DNS_MESSAGE_HEADER_STRUCT) + qname_size
                 + sizeof(DNS_MESSAGE_TAIL_STRUCT);

    /* Remote address, DNS_Resolver currently uses port 1024 */
   addr.sin_port        = DNS_RESOLVER_PORT;
   addr.sin_addr.s_addr = DNS_RESOLVER_IP_ADDR;

   rlen = sizeof(addr);

   /* Send the buffer to the resolver for making a query */
   error = sendto(local_sock, buffer_ptr, buffer_size, 0, &addr, rlen);
   if (error == RTCS_ERROR) {
      shutdown(local_sock, FLAG_ABORT_CONNECTION);
      RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_SEND_QUERY,
                     0, 0, 0);
      _mem_free(buffer_ptr);
      return( NULL );
   }/* Endif */

   /* Get the response from the resolver, if none received, return NULL */
   error = (uint32_t)RTCS_selectset( &local_sock, 1, DNS_QUERY_TIMEOUT );
   if ( !error || error == RTCS_ERROR ) {
      shutdown(local_sock, FLAG_ABORT_CONNECTION);
      RTCS_log_error(ERROR_DNS, RTCSERR_DNS_NO_RESPONSE_FROM_RESOLVER,
                     0, 0, 0);
      _mem_free(buffer_ptr);
      return( NULL );
   } /* Endif */

   temp_size = recvfrom(local_sock, buffer_ptr, DNS_MAX_UDP_MESSAGE_SIZE,
                        0, &addr, &rlen);
   if ( temp_size == RTCS_ERROR ) {
     shutdown(local_sock, FLAG_ABORT_CONNECTION);
     RTCS_log_error(ERROR_DNS, RTCSERR_DNS_PACKET_RECEPTION_ERROR,
                    0, 0, 0);
     _mem_free(buffer_ptr);
     return( NULL );
   }/* Endif */

   host_ptr = DNS_parse_UDP_response(buffer_ptr, name, query_type);
   shutdown(local_sock, FLAG_ABORT_CONNECTION);
   _mem_free(buffer_ptr);
   return( host_ptr );

} /* Endbody */
Exemple #13
0
bool IGMP_send_report
   (
      ip_mreq  *igrp,
      uint16_t  type
   )
{ /* Body */
   IGMP_CFG_STRUCT_PTR  IGMP_cfg_ptr = RTCS_getcfg(IGMP);
   uint32_t              error;
   uint16_t              checksum;
   RTCSPCB_PTR          pcb;
   IGMP_HEADER_PTR      header;
   IP_IF_PTR            ipif;
   _ip_address          ipdst;

   IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++);

   /* never send a report for the local groups */
   if (IN_LOCAL_MULTICAST(igrp->imr_multiaddr.s_addr)) {
      return TRUE;
   } /* Endif */

   /* get the interface with its ip address */
   ipif = IP_find_if(igrp->imr_interface.s_addr);
   if (ipif == NULL) {
      IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
      return FALSE;
   } /* Endif */

   pcb = RTCSPCB_alloc_send();
   if (pcb == NULL) {
      IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
      return FALSE;
   } /* Endif */

   //RTCSLOG_PCB_ALLOC(pcb);

   error = RTCSPCB_insert_header(pcb, sizeof(IGMP_HEADER));
   if (error) {
      RTCSLOG_PCB_FREE(pcb, error);
      RTCSPCB_free(pcb);
      IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
      return FALSE;
   } /* Endif */

   RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_IGMP), 1);

#ifdef IGMP_V2
   /* check if routers igmpv1 are present or not */
   if (type == IGMPTYPE_V2_REPORT && ipif->IGMP_V1_ROUTER_FLAG) {
      uint32_t curTime = RTCS_time_get();
      /* WORK: handle the overflow (see tcp seq) */
      if (curTime < ipif->IGMP_V1_ROUTER_TIMEOUT) {
         type = IGMPTYPE_V1_REPORT;
      } else {
         /* if the timeout expired, clear the flag */
         ipif->IGMP_V1_ROUTER_FLAG = 0;
      } /* Endif */
   } /* Endif */
#endif   /* IGMP_V2 */

   /* build the igmp packet */
   header = (IGMP_HEADER_PTR)RTCSPCB_DATA(pcb);
   mqx_htonc(header->TYPE, type);
   mqx_htonc(header->MAX_RESP_TIME, 0);
   mqx_htons(header->CHECKSUM, 0);
   mqx_htonl(header->GROUP_ADDRESS, igrp->imr_multiaddr.s_addr);
   checksum = _mem_sum_ip(0, sizeof(IGMP_HEADER), header);
   checksum = IP_Sum_invert(checksum);
   mqx_htons(header->CHECKSUM, checksum);

   /* WORK: for IGMP_V2, add a router alert option but currently ip layer doesnt support ip options */

   /* send the igmp packet */
   ipdst = igrp->imr_multiaddr.s_addr;
#ifdef IGMP_V2
   if (type == IGMPTYPE_LEAVE) {
      ipdst = INADDR_ALLROUTERS_GROUP;
   } /* Endif */
#endif

   IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_TX_REPORT++);    /* WORK: not always true for IGMP_V2 */
   error = IP_send(pcb, IPPROTO_IGMP | IPTTL(1), igrp->imr_interface.s_addr, ipdst, RTCS_MSG_NOLOOP);

   return TRUE;
} /* Endbody */
Exemple #14
0
uint32_t ENET_send
   (
      /* [IN] the Ethernet state structure */
      _enet_handle   handle,

      /* [IN] the packet to send */
      PCB_PTR        packet,

      /* [IN] the protocol */
      uint16_t        type,

      /* [IN] the destination Ethernet address */
      _enet_address  dest,

      /* [IN] optional flags, zero = default */
      uint32_t        flags
   )
{ 
   ENET_CONTEXT_STRUCT_PTR  enet_ptr = (ENET_CONTEXT_STRUCT_PTR)handle;
   ENET_HEADER_PTR         packet_ptr;
   unsigned char               *type_ptr;
   PCB_FRAGMENT_PTR        frag_ptr;
   uint32_t                 swhdr, size, frags;
   uint32_t                 error;
   _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data);
   
   _KLOGM(_GET_KERNEL_DATA(kernel_data));
   _KLOGE6(KLOG_ENET_send, handle, packet, type, dest, flags);

   if (flags & ENET_OPT_8021QTAG) {
       swhdr = ENET_FRAMESIZE_HEAD_VLAN;
   } else {
       swhdr = ENET_FRAMESIZE_HEAD;
   } 

   /*
   ** Make sure the first fragment is long enough for the Ethernet
   ** frame header.  This isn't strictly necessary, but it's impractical
   ** to split a 14-26 byte header over multiple fragments.
   */
#if MQX_CHECK_ERRORS
   if (packet->FRAG[0].LENGTH < swhdr) {
      ENET_INC_STATS(COMMON.ST_TX_DISCARDED);
      error = ENETERR_SEND_SHORT;
      goto ERROR;
   }
#endif

   /*
   ** Make sure that no fragment exceeds a maximum packet length.
   ** We check every fragment because we want to prevent something
   ** like FRAG[0].LENGTH = 2000, FRAG[1].LENGTH = -1000.  This
   ** situation would not be detected if we only check the total
   ** length.
   */
   size = frags = 0;
   for (frag_ptr = packet->FRAG; frag_ptr->LENGTH; frag_ptr++) {
#if MQX_CHECK_ERRORS
      if (frag_ptr->LENGTH > enet_ptr->MaxTxFrameSize) {   
         ENET_INC_STATS(COMMON.ST_TX_DISCARDED);
         error = ENETERR_SEND_LONG;
         goto ERROR;
      } 
#endif
      size += frag_ptr->LENGTH;
      frags++;
   } 

   /*
   ** Make sure that the total sum of the fragments doesn't exceed
   ** a maximum packet length.
   */
#if MQX_CHECK_ERRORS
   if (size > enet_ptr->MaxTxFrameSize) {
      ENET_INC_STATS(COMMON.ST_TX_DISCARDED);
      error = ENETERR_SEND_LONG;
      goto ERROR;
   } 
#endif

   /*
   ** Everything checks out -- fill in the header.
   */
   packet_ptr = (ENET_HEADER_PTR)packet->FRAG[0].FRAGMENT;
   htone(packet_ptr->DEST, dest);
   htone(packet_ptr->SOURCE, enet_ptr->ADDRESS);
   type_ptr = packet_ptr->TYPE;

   if (flags & ENET_OPT_8021QTAG) {
      ENET_8021QTAG_HEADER_PTR tag_ptr = (ENET_8021QTAG_HEADER_PTR)(type_ptr+2);
      uint16_t tag;
      tag = ENET_GETOPT_8021QPRIO(flags) << 13;
      mqx_htons(type_ptr, ENETPROT_8021Q);
      mqx_htons(tag_ptr->TAG, tag);
      type_ptr = tag_ptr->TYPE;
   } 

   if (flags & ENET_OPT_8023) {
      ENET_8022_HEADER_PTR llc_ptr = (ENET_8022_HEADER_PTR)(type_ptr+2);
      (void)mqx_htons(type_ptr, size - swhdr);
      mqx_htonc(llc_ptr->DSAP, 0xAA);
      mqx_htonc(llc_ptr->SSAP, 0xAA);
      mqx_htonc(llc_ptr->COMMAND, 0x03);
      mqx_htonc(&llc_ptr->OUI[0], 0x00);
      mqx_htonc(&llc_ptr->OUI[1], 0x00);
      mqx_htonc(&llc_ptr->OUI[2], 0x00);
      type_ptr = llc_ptr->TYPE;
   } 

   mqx_htons(type_ptr, type);

   /*
   ** This function can be called from any context, and it needs mutual
   ** exclusion with itself, and with ENET_ISR().
   */
   ENET_lock_context(enet_ptr);
   error = (*enet_ptr->PARAM_PTR->ENET_IF->MAC_IF->SEND)(handle, packet, size, frags, flags);
   ENET_unlock_context(enet_ptr);

   if (error) {
   ERROR:
      PCB_free(packet);
   }
   
   _KLOGX4(KLOG_ENET_send, handle, packet, error);
   
   return error;
}  
static RTCSPCB_PTR IPREASM_reasm_dgram
   (
      IP_DGRAM_PTR   dgram    /* [IN] the dgram descriptor */
   )
{ /* Body */
   RTCSPCB_PTR outpcb;
   PCB_PTR     bpcb;
   PCB_FRAGMENT      *pcb_frag_ptr;
   unsigned char   *data;
   uint32_t     iphlen  = (mqx_ntohc(dgram->header.IP4.IPH.VERSLEN) & 0xF) << 2;
   uint32_t     ip_totlen = iphlen + dgram->TOTLEN;

   bpcb = RTCS_mem_alloc_system(sizeof(PCB) + sizeof(PCB_FRAGMENT) + ip_totlen);
   if (!bpcb) {
      return NULL;
   } /* Endif */

   data = (unsigned char *)bpcb + sizeof(PCB) + sizeof(PCB_FRAGMENT);
   bpcb->FREE    = (void(_CODE_PTR_)(PCB_PTR))_mem_free;
   bpcb->PRIVATE = NULL;
 
   pcb_frag_ptr = bpcb->FRAG;
   pcb_frag_ptr->LENGTH   = ip_totlen;
   pcb_frag_ptr->FRAGMENT = data;
   pcb_frag_ptr++;
   pcb_frag_ptr->LENGTH   = 0;
   pcb_frag_ptr->FRAGMENT = NULL;

   /* Copy the IP header with options */
   mqx_htons(dgram->header.IP4.IPH.FRAGMENT, 0);
   _mem_copy(&dgram->header.IP4.IPH, data, iphlen);
   data += iphlen;

   /*
   ** At this point, we really should update the LENGTH
   ** and CHECKSUM fields in the new IP header, but we
   ** don't actually need to, because this datagram is
   ** going straight to IPLOCAL_service, which doesn't
   ** check these things.
   */

   /* Copy the stored data in the new packet */
   IPREASM_blk_read_all(dgram, data, dgram->TOTLEN);

   /* Put it in an RTCSPCB */
   outpcb = RTCSPCB_alloc_recv(bpcb);
   if (outpcb == NULL) {
      PCB_free(bpcb);
      return NULL;
   } /* Endif */
   //RTCSLOG_PCB_ALLOC(bpcb);
   outpcb->IFSRC           = dgram->IFSRC;
   outpcb->TYPE            = dgram->TYPE;
   outpcb->LINK_OPTIONS.RX = dgram->LINKOPT;
   RTCSPCB_DATA_NETWORK(outpcb) = RTCSPCB_DATA(outpcb);
   RTCSPCB_SET_TRANS_PROTL(outpcb, dgram->header.IP4.PROTO);
   RTCSPCB_SET_TRANS_DELTA(outpcb, iphlen);

   /* Delete the local structure */
   IPREASM_del_dgram(dgram);

   return outpcb;

} /* Endbody */
Exemple #16
0
uint32_t PPP_send
   (
      _ppp_handle    handle,
            /* [IN] - the PPP state structure */
      uint16_t        protocol,
            /* [IN] - protocol for the packet */
      PCB_PTR        pcb
            /* [IN] - the packet to send */
   )
{ /* Body */

#if RTCSCFG_ENABLE_IP4

   PPP_CFG_PTR       ppp_ptr = handle;
   PCB_FRAGMENT_PTR  frag_ptr;
   uint32_t           size, mru;
   uint32_t           error;

   /* Do some error checking */
   if (ppp_ptr->VALID != PPP_VALID) {
      PCB_free(pcb);
      return RTCSERR_PPP_INVALID_HANDLE;
   } else if (!(protocol&1) || (protocol&0x100)) {
      PCB_free(pcb);
      return RTCSERR_PPP_INVALID_PROTOCOL;
   } /* Endif */

   error = PPP_OK;
   PPP_mutex_lock(&ppp_ptr->MUTEX);
   if (!ppp_ptr->LINK_STATE) {
      error = RTCSERR_PPP_LINK_NOT_OPEN;
   } else {
      /* SPR P122-0371-01 */
      /* PCB includes 2-byte protocol field, but negotiated MRU doesn't */
      mru = ppp_ptr->SEND_OPTIONS->MRU + 2;
      /* End SPR P122-0371-01 */
   } /* Endif */
   PPP_mutex_unlock(&ppp_ptr->MUTEX);
   if (error) {
      PCB_free(pcb);
      return error;
   } /* Endif */

   /*
   ** Make sure the first fragment is long enough for the PPP protocol
   ** field.  This isn't strictly necessary, but it's impractical
   ** to split a 2 byte field over multiple fragments.
   */
   if (pcb->FRAG[0].LENGTH < 2) {
      PCB_free(pcb);
      return RTCSERR_PPP_PACKET_TOO_SHORT;
   } /* Endif */

   /*
   ** Make sure that no fragment exceeds a maximum packet length.
   ** We check every fragment because we want to prevent something
   ** like FRAG[0].LENGTH = 2000, FRAG[1].LENGTH = -1000.  This
   ** situation would not be detected if we only check the total
   ** length.
   */
   size = 0;
   for (frag_ptr = pcb->FRAG; frag_ptr->LENGTH; frag_ptr++) {
      if (frag_ptr->LENGTH > mru) {
         PCB_free(pcb);
         return RTCSERR_PPP_PACKET_TOO_LONG;
      } /* Endif */
      size += frag_ptr->LENGTH;
   } /* Endfor */

   /*
   ** Make sure that the total sum of the fragments doesn't exceed
   ** a maximum packet length.
   */
   if (size > mru) {
      PCB_free(pcb);
      return RTCSERR_PPP_PACKET_TOO_LONG;
   } /* Endif */

   /*
   ** Everything checks out -- send the packet to the Tx task.
   */
   mqx_htons(pcb->FRAG[0].FRAGMENT, protocol);
   return PPP_send_one(ppp_ptr, protocol, pcb);

#else

    return RTCSERR_IP_IS_DISABLED;    

#endif /* RTCSCFG_ENABLE_IP4 */     

} /* Endbody */
Exemple #17
0
uint32_t TFTP_open
   (
      void    *ft_data
         /* [IN] the address and filename of the bootimage */
   )
{ /* Body */
   TFTP_DATA_STRUCT_PTR    tftp;
   sockaddr_in             local_addr;
   char                *str_ptr;
   unsigned char               *packet;
   uint32_t                 sock;
   uint32_t                 error;
   uint32_t                 fn_len, fm_len;
   uint32_t                 pkt_len;

   tftp = (TFTP_DATA_STRUCT_PTR) ft_data;

   /* Get a socket */
   sock = socket(AF_INET, SOCK_DGRAM, 0);
   if (sock == RTCS_SOCKET_ERROR) {
      return RTCSERR_TFTP_SOCKET;
   } /* Endif */

   /* Must be initialized in order for TFTP_close to be able to release socket and memory */
   TFTP_config.SOCK = sock;  
   TFTP_config.RRQ_PTR = NULL;  

   /* Bind it */
   local_addr.sin_family      = AF_INET;
   local_addr.sin_port        = 0;
   local_addr.sin_addr.s_addr = INADDR_ANY;
   error = bind(sock, (const sockaddr *)&local_addr, sizeof(local_addr));
   if (error != RTCS_OK) {
      TFTP_close();
      return error;
   } /* Endif */

   if ( (tftp->FILENAME == NULL) || (tftp->FILEMODE == NULL) ){      
      TFTP_close();
      return TFTPERR_FILE_NOT_FOUND;
   } /* Endif */

   /* Prepare a read request (RRQ) */
   str_ptr = tftp->FILENAME;
   while (*str_ptr++) {};
   fn_len = str_ptr - tftp->FILENAME;
   str_ptr = tftp->FILEMODE;
   while (*str_ptr++) {};
   fm_len = str_ptr - tftp->FILEMODE;
   pkt_len = 2 + fn_len + fm_len;
   packet = RTCS_mem_alloc(pkt_len);
   if (packet == NULL) {
      TFTP_close();
      return RTCSERR_TFTP_RRQ_ALLOC;
   } /* Endif */
   _mem_set_type(packet, MEM_TYPE_TFTP_PACKET);
   TFTP_config.RRQ_PTR = packet;  
   mqx_htons(packet, TFTPOP_RRQ);
   _mem_copy(tftp->FILENAME, &packet[       2], fn_len);
   _mem_copy(tftp->FILEMODE, &packet[fn_len+2], fm_len);

   /* Send the RRQ */
   TFTP_config.SOCK = sock;
   TFTP_config.SADDR.sin_family      = AF_INET;
   TFTP_config.SADDR.sin_port        = IPPORT_TFTP;
   TFTP_config.SADDR.sin_addr.s_addr = tftp->SERVER;
   TFTP_timeout_init(&TFTP_config.TIMEOUT);
   error = sendto(sock, packet, pkt_len, 0,
                  (sockaddr *)(&TFTP_config.SADDR), sizeof(TFTP_config.SADDR));
   if (error != pkt_len) {
      TFTP_close();
      return RTCSERR_TFTP_RRQ_SEND;
   } /* Endif */

   /* Initialize the TFTP client */
   TFTP_config.RRQ_PTR = packet;
   TFTP_config.RRQ_LEN = pkt_len;
   TFTP_config.LAST    = FALSE;
   mqx_htons(TFTP_config.ACK.OP,    TFTPOP_ACK);
   mqx_htons(TFTP_config.ACK.BLOCK, 0);
   return RTCS_OK;

} /* Endbody */
Exemple #18
0
void ICMP_service
   (
      RTCSPCB_PTR    pcb,        /* [IN/OUT] incoming packet */
      void          *dummy       /* [IN]     not used        */
   )
{ /* Body */
   ICMP_CFG_STRUCT_PTR  ICMP_cfg_ptr;
   ICMP_HEADER_PTR      packet;
   _ip_address          source, dest;
   uint32_t              error;
   uint16_t              chksum;
   unsigned char                type;

#if BSPCFG_ENET_HW_TX_PROTOCOL_CHECKSUM
    _ip_address         if_addr;
    IP_IF_PTR           if_ptr;
#endif


   ICMP_cfg_ptr = RTCS_getcfg(ICMP);

   IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_TOTAL++);
   packet = (ICMP_HEADER_PTR)RTCSPCB_DATA(pcb);
   source = IP_source(pcb);
   dest   = IP_dest(pcb);
   type = mqx_ntohc(packet->TYPE);

   /*
   ** Make sure that
   **    sizeof(ICMP_HEADER) <= RTCSPCB_SIZE(pcb)
   */
   if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_HEADER)) {
      IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
      IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++);
      RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER);
      RTCSPCB_free(pcb);
      return;
   } /* Endif */


#if BSPCFG_ENET_HW_RX_PROTOCOL_CHECKSUM
    /* HW-offload.*/
    if( ((pcb->TYPE & RTCSPCB_TYPE_HW_PROTOCOL_CHECKSUM)==0) 
    #if RTCSCFG_LINKOPT_8023
        ||(pcb->LINK_OPTIONS.RX.OPT_8023 == 1)
    #endif
      )
#endif
    {
        /* Verify the checksum */
        if (IP_Sum_PCB(0, pcb) != 0xFFFF)
        {
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_BAD_CHECKSUM++);
            RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_CHECKSUM);
            RTCSPCB_free(pcb);
            return;
        }
    }

   RTCSLOG_PCB_READ(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMP), 0);

   switch (type) {

   case ICMPTYPE_REDIRECT:
#if RTCSCFG_ENABLE_GATEWAYS

      { /* Scope */
         _ip_address          origdest, gateway;
         ICMP_ERR_HEADER_PTR  rdpacket = (ICMP_ERR_HEADER_PTR)packet;
         IPIF_PARM            parms;

         /*
         ** Make sure that
         **    sizeof(ICMP_ERR_HEADER) <= RTCSPCB_SIZE(pcb)
         */
         if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_ERR_HEADER)) {
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++);
            RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER);
            RTCSPCB_free(pcb);
            return;
         } /* Endif */

         gateway  = mqx_ntohl(rdpacket->DATA);
         origdest = mqx_ntohl(rdpacket->IP.DEST);

        /* If we receive a redirect to ourselves, silently discard it.*/
        /* Ignore unasigned address.*/
        if( IP_is_local(NULL, gateway) || (gateway == INADDR_ANY))
        {
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
        }
        else  if(IP_is_gate(source, origdest))
        {
            parms.address = gateway;
            parms.network = origdest;
            parms.netmask = 0xFFFFFFFFL;
            parms.locmask = 0;
            RTCSCMD_internal(parms, IPIF_gate_add_redirect);
        }
        else
        {
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_RD_NOTGATE++);
        } /* Endif */
        
    } /* Endscope */
#else
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
#endif
      break;

    case ICMPTYPE_ECHO_REQ:
        /* RFC1122: An ICMP Echo Request destined to an IP broadcast or IP
         * multicast address MAY be silently discarded.*/
        if((dest == INADDR_BROADCAST) || (IN_MULTICAST(dest) && (ip_if_is_joined(pcb->IFSRC, dest) == false)) )
        {
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
        }
        else
        {
            error = RTCSPCB_next(pcb, sizeof(ICMP_HEADER));
            if (error) {
                IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_ERRORS++);
                IF_ICMP_STATS_ENABLED(RTCS_seterror(&ICMP_cfg_ptr->STATS.ERR_RX, error, (uint32_t)pcb));
                RTCSLOG_PCB_FREE(pcb, error);
                RTCSPCB_free(pcb);
                return;
            } /* Endif */

            /*
            ** RTCSPCB_fork() failing isn't a serious error, so we don't check
            ** the error code
            */
            RTCSPCB_fork(pcb);

            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++);
            RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMP), 0);

            error = RTCSPCB_insert_header(pcb, sizeof(ICMP_HEADER));
            if (error) {
                IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_ECHO_REQ++);
                IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
                IF_ICMP_STATS_ENABLED(RTCS_seterror(&ICMP_cfg_ptr->STATS.ERR_TX, error, (uint32_t)pcb));
                RTCSLOG_PCB_FREE(pcb, error);
                RTCSPCB_free(pcb);
                return;
            }

            /* Change type from Echo to Echo Reply and recalculate checksum */
            packet = (ICMP_HEADER_PTR)RTCSPCB_DATA(pcb);
            mqx_htonc(packet->TYPE, ICMPTYPE_ECHO_REPLY);
            mqx_htonc(packet->CODE, 0);
            mqx_htons(packet->CHECKSUM, 0);
            pcb->IP_SUM_PTR = NULL;


    #if BSPCFG_ENET_HW_TX_PROTOCOL_CHECKSUM
            /* HW-offload.*/
            if_addr = IP_route_find(source /* Destination*/, 1);
            if_ptr = IP_find_if(if_addr);
            if( (if_ptr 
                && (if_ptr->FEATURES & IP_IF_FEATURE_HW_TX_PROTOCOL_CHECKSUM)
                && (IP_will_fragment(if_ptr, RTCSPCB_SIZE(pcb)) == FALSE))
            #if RTCSCFG_LINKOPT_8023
                && (pcb->LINK_OPTIONS.TX.OPT_8023 == 0)
            #endif
                )
            {
                pcb->TYPE |= RTCSPCB_TYPE_HW_PROTOCOL_CHECKSUM;
            }
            else
    #endif
            {
                chksum = IP_Sum_PCB(0, pcb);
                chksum = IP_Sum_invert(chksum);
                mqx_htons(packet->CHECKSUM, chksum);
                
                pcb->TYPE &= ~RTCSPCB_TYPE_HW_PROTOCOL_CHECKSUM;
            }

            if(IN_MULTICAST(dest) || IP_addr_is_broadcast(pcb, dest) )
            {
                dest = IP_get_ipif_addr(pcb->IFSRC);
            }

            /* Send the Echo Reply whence came the Echo */
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_TX_ECHO_REPLY++);
            IP_send(pcb, IPPROTO_ICMP, dest /* Source*/, source /* Destination*/, 0);
            pcb = NULL;
        }
        break;

   case ICMPTYPE_ECHO_REPLY:
      { /* Scope */
         ICMP_ECHO_HEADER_PTR echopacket = (ICMP_ECHO_HEADER_PTR)packet;
         ICMP_ECHO_PARAM_PTR        parms;
         uint16_t              id, seq;

         /*
         ** Make sure that
         **    sizeof(ICMP_ECHO_HEADER) <= RTCSPCB_SIZE(pcb)
         */
         if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_ECHO_HEADER)) {
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++);
            RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER);
            RTCSPCB_free(pcb);
            return;
         } /* Endif */

         /*
         ** get the ID and Sequence number from the packet
         */
         id  = mqx_ntohs(echopacket->ID);
         seq = mqx_ntohs(echopacket->SEQ);

         /*
         ** Find a match for the ID and sequence number
         */
         for (parms=ICMP_cfg_ptr->ECHO_PARAM_HEAD; parms; parms=parms->NEXT) {

            if ((parms->ping_param->id == id) && (parms->seq == seq)) {
               /*  received reply for the ping request */

               if (parms->NEXT) {
                  parms->NEXT->PREV = parms->PREV;
               }
               *parms->PREV = parms->NEXT;

               TCPIP_Event_cancel(&parms->EXPIRE);

               /* Calculate round trip time */
               parms->ping_param->round_trip_time = RTCS_timer_get_interval(parms->start_time, RTCS_time_get());
               
                /* IP address of echo-reply message.*/
                {
                    IP_HEADER_PTR iphead = (IP_HEADER_PTR)RTCSPCB_DATA_NETWORK(pcb);
                   
                    memset(&parms->ping_param->addr, 0, sizeof(parms->ping_param->addr));
                    parms->ping_param->addr.sa_family = AF_INET;
                    ((sockaddr_in*)(&parms->ping_param->addr))->sin_addr.s_addr = mqx_ntohl(iphead->SOURCE);
                }

               RTCSCMD_complete(parms, RTCS_OK);
               break;
            } /* Endif */
         } /* Endfor */
      } /* Endscope */
      break;

   case ICMPTYPE_DESTUNREACH:
   case ICMPTYPE_TIMEEXCEED:
      { /* Scope */
         IP_HEADER_PTR       ip;
         ICMP_ERR_HEADER_PTR icmp_err = (ICMP_ERR_HEADER_PTR)packet;
         uint32_t             len, remain;
         bool             discard = TRUE;
         unsigned char               code;

         /*
         ** Check if the attached IP header is IP over IP, and if so, strip IP
         ** headers until we find one whose source address is not local. Then we
         ** forward the ICMP error to that IP address
         */

         remain = RTCSPCB_SIZE(pcb);

         /* Make sure we have at least a full IP header */
         if (remain >= sizeof(ICMP_HEADER) + 4 + sizeof(IP_HEADER)) {
            ip = (IP_HEADER_PTR)((unsigned char *)packet + sizeof(ICMP_HEADER) + 4);
            remain -= sizeof(ICMP_HEADER) + 4;

            do {
               /* Make sure the IP header is IP over IP */
               if (mqx_ntohc(ip->PROTOCOL) != IPPROTO_IPIP) {
                  break;
               } /* Endif */

               /* Make sure we have a full IP header + 8 bytes */
               len = (mqx_ntohc(ip->VERSLEN) & 0x0F) << 2;
               if (remain < len + sizeof(IP_HEADER)) {
                  break;
               } /* Endif */

               /* Get next header */
               ip = (IP_HEADER_PTR)((unsigned char *)(ip) + len);
               remain -= len;
               source = mqx_ntohl(ip->SOURCE);

               discard = IP_is_local(NULL, source);

            } while(discard);

            len = (mqx_ntohc(ip->VERSLEN) & 0x0F) << 2;

            /*
            ** discard is true if we are the originator of the IP packet
            ** in error, or if there was not enough information to find the
            ** originator. We make sure discard is false, and there is at
            ** least a full IP header + 8 bytes of data left
            */
            if (!discard && (len + 8 <= remain)) {
               if (type == ICMPTYPE_DESTUNREACH) {
                  code = mqx_ntohc(packet->CODE);
                  switch (code) {
                  case ICMPCODE_DU_PROTO_UNREACH:
                     /*
                     ** If we are sending back to the originator, and the
                     ** originator did not use IP over IP, the protocol
                     ** unreachable error is useless.
                     */
                     code = ICMPCODE_DU_NET_UNREACH;
                     break;
                  case ICMPCODE_DU_PORT_UNREACH:
                     /* It doesn't make sense to receive this */
                     discard = TRUE;
                     break;
                  case ICMPCODE_DU_SRCROUTE:
                     discard = TRUE;
                     break;
                  } /* Endswitch */
               } else {
                  /*
                  ** Type is ICMPTYPE_TIMEEXCEED
                  **
                  ** Problem with routing loops within tunnel. Originator
                  ** does not need to know about tunnel.
                  */
                  type = ICMPTYPE_DESTUNREACH;
                  code = ICMPCODE_DU_HOST_UNREACH;
               } /* Endif */

               if (!discard) {
                  ICMP_send_error_internal(type, code, mqx_ntohl(icmp_err->DATA),
                     ip, NULL, remain);
               } /* Endif */
            } /* Endif */
         } /* Endif */
      } /* Endscope */
      break;
   } /* End Switch */

#if RTCSCFG_ENABLE_ICMP_STATS
   /* Update the statistics */
   switch (type) {
   case ICMPTYPE_DESTUNREACH: ICMP_cfg_ptr->STATS.ST_RX_DESTUNREACH++; break;
   case ICMPTYPE_TIMEEXCEED:  ICMP_cfg_ptr->STATS.ST_RX_TIMEEXCEED++;  break;
   case ICMPTYPE_PARMPROB:    ICMP_cfg_ptr->STATS.ST_RX_PARMPROB++;    break;
   case ICMPTYPE_SRCQUENCH:   ICMP_cfg_ptr->STATS.ST_RX_SRCQUENCH++;   break;
   case ICMPTYPE_REDIRECT:    ICMP_cfg_ptr->STATS.ST_RX_REDIRECT++;    break;
   case ICMPTYPE_ECHO_REQ:    ICMP_cfg_ptr->STATS.ST_RX_ECHO_REQ++;    break;
   case ICMPTYPE_ECHO_REPLY:  ICMP_cfg_ptr->STATS.ST_RX_ECHO_REPLY++;  break;
   case ICMPTYPE_TIME_REQ:    ICMP_cfg_ptr->STATS.ST_RX_TIME_REQ++;    break;
   case ICMPTYPE_TIME_REPLY:  ICMP_cfg_ptr->STATS.ST_RX_TIME_REPLY++;  break;
   case ICMPTYPE_INFO_REQ:    ICMP_cfg_ptr->STATS.ST_RX_INFO_REQ++;    break;
   case ICMPTYPE_INFO_REPLY:  ICMP_cfg_ptr->STATS.ST_RX_INFO_REPLY++;  break;
   default:                   
      ICMP_cfg_ptr->STATS.ST_RX_OTHER++;       
      ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++;
      break;
   } /* Endswitch */
#endif

   if (pcb) {
      RTCSLOG_PCB_FREE(pcb, RTCS_OK);
      RTCSPCB_free(pcb);
   } /* Endif */

} /* Endbody */
Exemple #19
0
void ICMP_send_error_internal
   (
      uint8_t         type,    /* [IN] the type to send */
      uint8_t         code,    /* [IN] the code to send */
      uint32_t        param,   /* [IN] a parameter */
      IP_HEADER_PTR  iph,     /* [IN] the IP header */
      RTCSPCB_PTR    origpcb, /* [IN] pcb with bad packet */
      uint32_t        maxlen   /* [IN] the max data len to send, 0 = default */
   )
{ /* Body */
   ICMP_CFG_STRUCT_PTR  ICMP_cfg_ptr = RTCS_getcfg(ICMP);
   RTCSPCB_PTR          pcb;
   ICMP_ERR_HEADER_PTR  icmph;
   _ip_address          ipsrc = mqx_ntohl(iph->SOURCE);
   _ip_address          ipdst = mqx_ntohl(iph->DEST);
   uint16_t              iphdrlen = (mqx_ntohc(iph->VERSLEN) & 0x0F) << 2;
   uint16_t              ippktlen = mqx_ntohs(iph->LENGTH) - iphdrlen;
   uint16_t              checksum;
   _ip_address          icmpsrc = IP_is_local(NULL,ipdst) ? ipdst : INADDR_ANY;
   uint32_t              error;
   unsigned char            *buffer;
   uint32_t              temp;
#if RTCSCFG_ENABLE_NAT   
   TCP_HEADER_PTR       tcp_hdr;
   UDP_HEADER_PTR       udp_hdr;
   IP_HEADER_PTR        ip_hdr;
   uint32_t              protocol;
   uint16_t              src_port, dest_port;
   uint32_t (_CODE_PTR_   *nat_exec)(RTCSPCB_PTR *);
#endif 
#if BSPCFG_ENET_HW_TX_PROTOCOL_CHECKSUM
    _ip_address         if_addr;
    IP_IF_PTR           if_ptr;
#endif
   
   /*
   ** Only include up to a maximum of maxlen bytes of data from the
   ** original IP datagram
   */
   if (!maxlen) {
      maxlen = IP_DEFAULT_MTU - sizeof(IP_HEADER) - sizeof(ICMP_HEADER) - 4;
   } /* Endif */

   if (origpcb) {
      temp = RTCSPCB_DATA(origpcb) - RTCSPCB_DATA_NETWORK(origpcb);
      if (maxlen >  origpcb->HEADER_FRAG_USED + temp) {
         maxlen = origpcb->HEADER_FRAG_USED + temp;
      } /* Endif */   
   } /* Endif */

   if (ippktlen + iphdrlen > maxlen) {
      ippktlen = maxlen - iphdrlen;
   } /* Endif */

   /* Don't send an error in response to an ICMP error */
   if (mqx_ntohc(iph->PROTOCOL) == IPPROTO_ICMP) {
      /* Make sure the packet has at least a 'TYPE' field */
      if (ippktlen == 0) {
         return;
      } /* Endif */
      icmph = (ICMP_ERR_HEADER_PTR)((unsigned char *)iph + iphdrlen);
      if (!ICMPTYPE_ISQUERY(mqx_ntohc(icmph->HEAD.TYPE))) {
         return;
      } /* Endif */
   } /* Endif */

   IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++);

   /* Allocate a PCB */
   pcb = RTCSPCB_alloc_send();
   if (pcb == NULL) {
      IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
      return;
   } /* Endif */

   //RTCSLOG_PCB_ALLOC(pcb);

   if (origpcb) {

      /* Add a dependency and a pointer to the ICMP data */
      RTCSPCB_depend(pcb, origpcb);
      error = RTCSPCB_append_fragment(pcb, iphdrlen + ippktlen, (unsigned char *)iph);

   } else {
      /* Reserve space for the ICMP data */
      buffer = RTCS_mem_alloc_system(iphdrlen + ippktlen);
      if (!buffer) {
         IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
         IF_ICMP_STATS_ENABLED(RTCS_seterror(&ICMP_cfg_ptr->STATS.ERR_TX, RTCSERR_OUT_OF_MEMORY, (uint32_t)pcb));
         RTCSLOG_PCB_FREE(pcb, RTCSERR_OUT_OF_MEMORY);
         RTCSPCB_free(pcb);
         return;
      } /* Endif */
   
      _mem_set_type(buffer, MEM_TYPE_ICMP_DATA);

      _mem_copy(iph, buffer, iphdrlen + ippktlen);
      error = RTCSPCB_append_fragment_autofree(pcb, iphdrlen + ippktlen, buffer);
      if (error) {
         _mem_free(buffer);
      } /* Endif */

   } /* Endif */

   if (!error) {
      error = RTCSPCB_insert_header(pcb, sizeof(ICMP_HEADER) + 4);
   } /* Endif */

   if (error) {
      IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++);
      IF_ICMP_STATS_ENABLED(RTCS_seterror(&ICMP_cfg_ptr->STATS.ERR_TX, error, (uint32_t)pcb));
      RTCSLOG_PCB_FREE(pcb, error);
      RTCSPCB_free(pcb);
      return;
   } /* Endif */

   RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMP), 0);

   /* Build the header */
   icmph = (ICMP_ERR_HEADER_PTR)RTCSPCB_DATA(pcb);
   mqx_htonc(icmph->HEAD.TYPE,     type);
   mqx_htonc(icmph->HEAD.CODE,     code);
   mqx_htons(icmph->HEAD.CHECKSUM, 0);
   mqx_htonl(icmph->DATA,          param);


#if BSPCFG_ENET_HW_TX_PROTOCOL_CHECKSUM
    /* HW-offload.*/
    if_addr = IP_route_find(ipsrc /* Destination*/, 1);
    if_ptr = IP_find_if(if_addr);
    if( (if_ptr 
        && (if_ptr->FEATURES & IP_IF_FEATURE_HW_TX_PROTOCOL_CHECKSUM)
        && (IP_will_fragment(if_ptr, RTCSPCB_SIZE(pcb)) == FALSE))
    #if RTCSCFG_LINKOPT_8023
        && (pcb->LINK_OPTIONS.TX.OPT_8023 == 0)
    #endif
        )
    {
        pcb->TYPE |= RTCSPCB_TYPE_HW_PROTOCOL_CHECKSUM;
    }
    else
#endif
    {
        checksum = IP_Sum_PCB (0, pcb);
        checksum = IP_Sum_invert(checksum);
        mqx_htons(icmph->HEAD.CHECKSUM, checksum);

        pcb->TYPE &= ~RTCSPCB_TYPE_HW_PROTOCOL_CHECKSUM;
    }

#if RTCSCFG_ENABLE_ICMP_STATS
   /* Update the statistics */
   switch (type) {
   case ICMPTYPE_DESTUNREACH: ICMP_cfg_ptr->STATS.ST_TX_DESTUNREACH++; break;
   case ICMPTYPE_TIMEEXCEED:  ICMP_cfg_ptr->STATS.ST_TX_TIMEEXCEED++;  break;
   case ICMPTYPE_PARMPROB:    ICMP_cfg_ptr->STATS.ST_TX_PARMPROB++;    break;
   case ICMPTYPE_SRCQUENCH:   ICMP_cfg_ptr->STATS.ST_TX_SRCQUENCH++;   break;
   case ICMPTYPE_REDIRECT:    ICMP_cfg_ptr->STATS.ST_TX_REDIRECT++;    break;
   case ICMPTYPE_ECHO_REQ:    ICMP_cfg_ptr->STATS.ST_TX_ECHO_REQ++;    break;
   case ICMPTYPE_ECHO_REPLY:  ICMP_cfg_ptr->STATS.ST_TX_ECHO_REPLY++;  break;
   case ICMPTYPE_TIME_REQ:    ICMP_cfg_ptr->STATS.ST_TX_TIME_REQ++;    break;
   case ICMPTYPE_TIME_REPLY:  ICMP_cfg_ptr->STATS.ST_TX_TIME_REPLY++;  break;
   case ICMPTYPE_INFO_REQ:    ICMP_cfg_ptr->STATS.ST_TX_INFO_REQ++;    break;
   case ICMPTYPE_INFO_REPLY:  ICMP_cfg_ptr->STATS.ST_TX_INFO_REPLY++;  break;
   default:                   ICMP_cfg_ptr->STATS.ST_TX_OTHER++;       break;
   } /* Endswitch */
#endif


#if RTCSCFG_ENABLE_NAT
   /* Reverse NAT (if it is installed) on the origpcb,
      otherwise the icmp error will not get sent to the
      original src */
   nat_exec = RTCS_getcfg(NAT);
   if (origpcb && nat_exec && *nat_exec) {
      // swap src and dst IPs and ports so NAT_apply
      // will process the pcb
      ip_hdr = (IP_HEADER_PTR)RTCSPCB_DATA(origpcb);
      protocol = mqx_ntohc(ip_hdr->PROTOCOL);
      // Swap ports if it is udp or tcp
      if ((protocol == IPPROTO_TCP) || (protocol == IPPROTO_UDP)) {
         switch(protocol)
         {
            case IPPROTO_TCP:
               tcp_hdr = (TCP_HEADER_PTR)((unsigned char *)ip_hdr + IPH_LEN(ip_hdr));
               dest_port = mqx_ntohs(tcp_hdr->dest_port);
               src_port  = mqx_ntohs(tcp_hdr->source_port);
               mqx_htons(tcp_hdr->dest_port, src_port);
               mqx_htons(tcp_hdr->source_port, dest_port);
               break;
            case IPPROTO_UDP:
               udp_hdr = (UDP_HEADER_PTR)((unsigned char *)ip_hdr + IPH_LEN(ip_hdr));
               dest_port = mqx_ntohs(udp_hdr->DEST_PORT);
               src_port  = mqx_ntohs(udp_hdr->SRC_PORT);
               mqx_htons(udp_hdr->DEST_PORT, src_port);
               mqx_htons(udp_hdr->SRC_PORT, dest_port);            
               break;
            default:
               // should not get here
               break;
         }
      }
      // swap IPs
      ipsrc = mqx_ntohl(ip_hdr->SOURCE);
      ipdst = mqx_ntohl(ip_hdr->DEST);
      mqx_htonl(ip_hdr->SOURCE, ipdst);
      mqx_htonl(ip_hdr->DEST,ipsrc);

      // call NAT
      error = (*nat_exec)(&origpcb);

      if (!error) {
         // swap IPs and ports back
         ip_hdr = (IP_HEADER_PTR)RTCSPCB_DATA(origpcb);
         protocol = mqx_ntohc(ip_hdr->PROTOCOL);
         // swap ports if it is udp or tcp
         if ((protocol == IPPROTO_TCP) || (protocol == IPPROTO_UDP)) {
            switch(protocol)
            {
               case IPPROTO_TCP:
                  tcp_hdr = (TCP_HEADER_PTR)((unsigned char *)ip_hdr + IPH_LEN(ip_hdr));
                  dest_port = mqx_ntohs(tcp_hdr->dest_port);
                  src_port  = mqx_ntohs(tcp_hdr->source_port);
                  mqx_htons(tcp_hdr->dest_port, src_port);
                  mqx_htons(tcp_hdr->source_port, dest_port);
                  break;
               case IPPROTO_UDP:
                  udp_hdr = (UDP_HEADER_PTR)((unsigned char *)ip_hdr + IPH_LEN(ip_hdr));
                  dest_port = mqx_ntohs(udp_hdr->DEST_PORT);
                  src_port  = mqx_ntohs(udp_hdr->SRC_PORT);
                  mqx_htons(udp_hdr->DEST_PORT, src_port);
                  mqx_htons(udp_hdr->SRC_PORT, dest_port);            
                  break;
               default:
                  // should not get here
                  break;
            }
         }
         // swap IPs
         ipsrc = mqx_ntohl(ip_hdr->SOURCE);
         ipdst = mqx_ntohl(ip_hdr->DEST);
         mqx_htonl(ip_hdr->SOURCE, ipdst);
         mqx_htonl(ip_hdr->DEST,ipsrc);   

         // Recalculate the cksum
         mqx_htons(icmph->HEAD.CHECKSUM, 0);
         checksum = IP_Sum_PCB (0, pcb);
         checksum = IP_Sum_invert(checksum);
         mqx_htons(icmph->HEAD.CHECKSUM, checksum);

         // recalculate icmpsrc, and use new ipsrc.
         ipdst = mqx_ntohl(ip_hdr->DEST);
         ipsrc = mqx_ntohl(ip_hdr->SOURCE);
         icmpsrc = IP_is_local(NULL,ipdst) ? ipdst : INADDR_ANY;
      }
   }
#endif
   
   /* Send it */
   IP_send(pcb, IPPROTO_ICMP, icmpsrc, ipsrc, 0);

} /* Endbody */
Exemple #20
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 */
Exemple #21
0
static uint32_t LCP_buildconfreq
   (
      PPPFSM_CFG_PTR    fsm,
            /* [IN] - State Machine */
      unsigned char         *outp,
            /* [IN] - free packet */
      uint32_t           sizeleft
            /* [IN] - size of packet */
   )
{ /* Body */
   LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
   uint32_t     totlen = 0;
   uint32_t     aplen;

#define LCP_BREQ(ci,len) \
         *outp++ = LCP_CI_ ## ci; \
         *outp++ = len;           \
         totlen += len

   /*
   ** Generate configuration information for each option
   ** we want to negotiate.
   */

   if (lcp_ptr->RECV_NEG.NEG_MRU) {
      if (sizeleft >= totlen+4) {
         LCP_BREQ(MRU,4);
         mqx_htons(outp, lcp_ptr->RECV_NEG.MRU); outp += 2;
      } /* Endif */
   } /* Endif */

   if (lcp_ptr->RECV_NEG.NEG_ACCM) {
      if (sizeleft >= totlen+6) {
         LCP_BREQ(ACCM,6);
         mqx_htonl(outp, lcp_ptr->RECV_NEG.ACCM); outp += 4;
      } /* Endif */
   } /* Endif */

   if (lcp_ptr->RECV_NEG.NEG_AP) {
      switch (lcp_ptr->RECV_NEG.AP) {
      case PPP_PROT_CHAP: aplen = 5; break;
      default:            aplen = 4; break;
      } /* Endswitch */
      if (sizeleft >= totlen+aplen) {
         LCP_BREQ(AP,aplen);
         mqx_htons(outp, lcp_ptr->RECV_NEG.AP); outp += 2;
         switch (lcp_ptr->RECV_NEG.AP) {
         case PPP_PROT_CHAP:
            mqx_htonc(outp, 5); outp++;          /* Only MD5 supported */
            break;
         } /* Endswitch */
      } /* Endif */
   } /* Endif */

   if (lcp_ptr->RECV_NEG.NEG_PFC) {
      if (sizeleft >= totlen+2) {
         LCP_BREQ(PFC,2);
      } /* Endif */
   } /* Endif */

   if (lcp_ptr->RECV_NEG.NEG_ACFC) {
      if (sizeleft >= totlen+2) {
         LCP_BREQ(ACFC,2);
      } /* Endif */
   } /* Endif */

   return totlen;

} /* Endbody */