Exemplo n.º 1
0
static uint32_t RIP_send_pkt(
   IP_IF_PTR   ipif,   /* [IN] the outgoing interface */
   _ip_address ipdst,  /* [IN] the destination ip */
   uint16_t     portdst,/* [IN] the destination port */
   unsigned char   *data,   /* [IN] the data to send */
   uint32_t     len /* [IN] the length of data to send */
)
{ /* Body */
   RTCSPCB_PTR         pcb;
   RIP_CFG_STRUCT_PTR  ripcfg = RTCS_getcfg(RIP);
   RIP_HEADER_PTR  hd = (RIP_HEADER_PTR)data;
   uint32_t         err;
   _ip_address     ipsrc = IP_get_ipif_addr(ipif);

   if (ipsrc == INADDR_ANY) {
       _mem_free(data);
       return RTCS_OK;
   } /* Endif */

   /* Allocate a PCB */
   pcb = RTCSPCB_alloc_send();
   if (pcb == NULL) {
       _mem_free(data);
       return RTCSERR_PCB_ALLOC;
   } /* Endif */

   //RTCSLOG_PCB_ALLOC(pcb);

   /* add my data in the pcb */
   err = RTCSPCB_append_fragment_autofree(pcb, len, data);
   if (err) {
       _mem_free(data);
       RTCSLOG_PCB_FREE(pcb, err);
       RTCSPCB_free(pcb);
       return err;
   } /* Endif */

   RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PORT(IPPORT_RIP), mqx_ntohc(hd->VERSION));

   /* dont advertize in limited broadcast but in ip broadcast */
   if (ipdst == INADDR_BROADCAST){
       _ip_address  netmask;

       ipdst = IP_get_ipif_addr(ipif);        /* Get IP address of interface */
       IP_get_netmask(ipif, ipdst, &netmask); /* Get netmask */

       ipdst = ipdst | ~netmask;
   } /* Endif */

   /* send it */
   /* use a flag to prevent the broadcast/multicast packet from
   ** looping back to us.
   */
   return UDP_send_internal(ripcfg->UCB, ipsrc, ipdst, portdst, pcb, RTCS_MSG_NOLOOP);
} /* Endbody */
Exemplo n.º 2
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 */