Ejemplo n.º 1
0
static void IGMP_service
   (
      RTCSPCB_PTR    pcb,        /* [IN/OUT] incoming packet */
      pointer        dummy       /* [IN]     not used        */
   )
{ /* Body */
   IGMP_HEADER_PTR      header;
   IGMP_CFG_STRUCT_PTR  IGMP_cfg_ptr;

   IGMP_cfg_ptr = RTCS_getcfg(IGMP);
   IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_RX_TOTAL++);

   header = (IGMP_HEADER_PTR)RTCSPCB_DATA(pcb);

   /* check if length >= sizeof(IGMP_HEADER) */
   if (RTCSPCB_SIZE(pcb) < sizeof(IGMP_HEADER)) {
      IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
      IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++);
      RTCSLOG_PCB_FREE(pcb, RTCSERR_IGMP_BAD_HEADER);
      RTCSPCB_free(pcb);
      return;
   } /* Endif */

   /* Verify the checksum */
   if (IP_Sum_PCB(0, pcb) != 0xFFFF) {
      IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
      IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_RX_BAD_CHECKSUM++);
      RTCSLOG_PCB_FREE(pcb, RTCSERR_IGMP_BAD_CHECKSUM);
      RTCSPCB_free(pcb);
      return;
   } /* Endif */

   if (ntohc(header->TYPE) == IGMPTYPE_V2_REPORT) {
      RTCSLOG_PCB_READ(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_IGMP), 2);
   } else {
      RTCSLOG_PCB_READ(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_IGMP), 1);
   } /* Endif */

   switch (ntohc(header->TYPE)) {
   case IGMPTYPE_QUERY:
      IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_RX_QUERY++);
      IGMP_rcv_query(pcb->IFSRC, ntohl(header->GROUP_ADDRESS), ntohc(header->MAX_RESP_TIME));
      break;
   case IGMPTYPE_V1_REPORT:
   case IGMPTYPE_V2_REPORT:
      IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_RX_REPORT++);
      IGMP_rcv_report(pcb->IFSRC, ntohl(header->GROUP_ADDRESS));
      break;
   default:
      IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_RX_BAD_TYPE++);
   } /* Endswitch */

   RTCSLOG_PCB_FREE(pcb, RTCS_OK);
   RTCSPCB_free(pcb);

} /* Endbody */
Ejemplo n.º 2
0
static void DHCPSRV_write_options
   (
      DHCPSRV_STATE_STRUCT_PTR   state,
      DHCPSRV_ADDR_STRUCT_PTR    lease_ptr
   )
{ /* Body */
   uchar_ptr   inp, outp, scanptr;
   int_32      scanlen;
   uint_32     copylen;
   volatile uchar       optval, optlen;

   outp = state->SND_BUFFER + state->SND_BUFFER_LEN;
   inp  = lease_ptr->OPTIONS->OPTION_PTR;

   scanptr = inp;
   scanlen = sizeof(state->SND_BUFFER) - state->SND_BUFFER_LEN - 1;
   if (scanlen > lease_ptr->OPTIONS->OPTION_LEN) {
      scanlen = lease_ptr->OPTIONS->OPTION_LEN;
   } /* Endif */
   copylen = 0;

   for (;;) {

      if (scanlen < 1) break;
      optval = ntohc(scanptr);
      scanptr++;
      scanlen--;

      if (optval == DHCPOPT_END) {
         break;
      } /* Endif */
      if (optval == DHCPOPT_PAD) {
         copylen++;
         continue;
      } /* Endif */

      if (scanlen < 1) break;
      optlen = ntohc(scanptr);
      scanptr++;
      scanlen--;

      if (scanlen < optlen) break;

      scanptr += optlen;
      scanlen -= optlen;
      copylen += optlen + 2;

   } /* Endfor */

   _mem_copy(inp, outp, copylen);
   state->SND_BUFFER_LEN += copylen;

} /* Endbody */
Ejemplo n.º 3
0
static uchar_ptr DHCPSRV_find_option
   (
      uchar_ptr   msgptr,
      uint_32     msglen,
      uchar       option
   )
{ /* Body */
   uchar optype;
   uchar oplen;

   for (;;) {

      /* Get the next option code */
      if (msglen == 0) {
         return NULL;
      } /* Endif */
      optype = ntohc(msgptr);
      msgptr++;
      msglen--;

      if (optype == DHCPOPT_END) {
         return NULL;
      } /* Endif */
      if (optype == DHCPOPT_PAD) {
         continue;
      } /* Endif */

      /* Get the option length */
      if (msglen == 0) {
         return NULL;
      } /* Endif */
      oplen = ntohc(msgptr);
      msgptr++;
      msglen--;

      if (msglen < oplen) {
         return NULL;
      } /* Endif */

      if (optype == option) {
         return msgptr-2;
      } /* Endif */

      msgptr += oplen;
      msglen -= oplen;

   } /* Endfor */

} /* Endbody */
Ejemplo n.º 4
0
static uchar DHCPSRV_find_msgtype
   (
      uchar_ptr   msgptr,
      uint_32     msglen
   )
{ /* Body */
   uchar msgtype = 0;

   msgptr = DHCPSRV_find_option(msgptr, msglen, DHCPOPT_MSGTYPE);
   if (msgptr != NULL) {
      msgptr++;
      if (ntohc(msgptr) == DHCPSIZE_MSGTYPE) {
         msgptr++;
         msgtype = ntohc(msgptr);
         if (!DHCPTYPE_ISVALID(msgtype)) {
            msgtype = 0;
         } /* Endif */
      } /* Endif */
   } /* Endif */

   return msgtype;

} /* Endbody */
Ejemplo n.º 5
0
static void NAT_IPREASM_add_frag
   (
      IP_DGRAM_PTR   dgram,   /* [IN] the dgram */
      RTCSPCB_PTR    inpcb    /* [IN] the received PCB */
   )
{ /* Body */
   IP_HEADER_PTR     iph     = (IP_HEADER_PTR)RTCSPCB_DATA(inpcb);
   uint_32           iphlen  = (ntohc(iph->VERSLEN) & 0xF) << 2;
   uint_32           totlen  = ntohs(iph->LENGTH);
   int_32            offset  = ntohs(iph->FRAGMENT);
   int_32            first   = (offset & IP_FRAG_MASK) << IP_FRAG_SHIFT;
   uint_32           datalen = totlen - iphlen;
   uchar_ptr         data    = (uchar_ptr)iph + iphlen;
   IPREASM_BLK_PTR   blk;
   uint_32           len;

   if (offset & IP_FRAG_MF) {

      /* Fragments (except the last) must be multiples of 8 bytes */
      if ((datalen & 0x07) != 0) {
         return;
      } /* Endif */

   } else {
      /* If this fragment is the last one, record the total length */
      dgram->TOTLEN = first + datalen;

   } /* Endif */

   /* Once we get the first fragment, record the IP header and 8 data bytes */
   if (first == 0) {
      _mem_copy(iph, &dgram->IPH, iphlen + 8);
      dgram->TYPE    = inpcb->TYPE;
      dgram->IFSRC   = inpcb->IFSRC;
      dgram->LINKOPT = inpcb->LINK_OPTIONS.RX;
   } /* Endif */

   while (datalen) {
      blk = NAT_IPREASM_blk_get(dgram, first);
      if (!blk) {
         return;
      } /* Endif */

      len = NAT_IPREASM_blk_write(dgram, blk, first, data, datalen);
      first   += len;
      data    += len;
      datalen -= len;
   } /* Endwhile */

} /* Endbody */
Ejemplo n.º 6
0
uint_32 NAT_IP_reasm
   (
      RTCSPCB_PTR       pcb,     /* [IN] the packet to deliver */
      RTCSPCB_PTR _PTR_ outpcb   /* [OUT] the reassembled packet or NULL */
   )
{ /* Body */
   IP_HEADER_PTR  iph    = (IP_HEADER_PTR)RTCSPCB_DATA(pcb);
   _ip_address    ipsrc  = ntohl(iph->SOURCE);
   _ip_address    ipdst  = ntohl(iph->DEST);
   uint_8         proto  = ntohc(iph->PROTOCOL);
   uint_16        id     = ntohs(iph->ID);
   IP_DGRAM_PTR   dgram;

   *outpcb = NULL;

   dgram = NAT_IPREASM_get_dgram(ipsrc, ipdst, proto, id);
   if (!dgram) {
      RTCSLOG_PCB_FREE(pcb, RTCSERR_OUT_OF_MEMORY);
      RTCSPCB_free(pcb);
      return RTCSERR_OUT_OF_MEMORY;
   } /* Endif */

   NAT_IPREASM_add_frag(dgram, pcb);

   /*
   ** We're done when:
   **    0 < TOTLEN = MAXLEN <= CURLEN
   **
   ** Note: we can get TOTLEN < CURLEN because CURLEN is
   ** always a multiple of eight, but TOTLEN may not be.
   */
   if (dgram->TOTLEN > 0
    && dgram->MAXLEN == dgram->TOTLEN
    && dgram->CURLEN >= dgram->MAXLEN) {
      *outpcb = NAT_IPREASM_reasm_dgram(dgram);
   } /* Endif */

   /* Free the old pcb */
   RTCSLOG_PCB_FREE(pcb, RTCS_OK);
   RTCSPCB_free(pcb);

   return RTCS_OK;
} /* Endbody */
Ejemplo n.º 7
0
static void DHCPSRV_service_request
   (
      DHCPSRV_STATE_STRUCT_PTR   state
   )
{ /* Body */
   uchar_ptr                     inp,   cid_ptr, sid_ptr, lease_ptr;
   uint_32                       inlen, cid_len;
   _ip_address                   serverid = 0;
   uint_32                       lease = 0;
   DHCPSRV_ADDR_STRUCT_PTR       addr;
   DHCPSRV_ADDR_STRUCT_PTR _PTR_ addrp;
   /* Start CR 1599 */
   boolean                       reply=FALSE;
   /* End CR 1599 */

   inp   = state->RCV_BUFFER     + sizeof(DHCP_HEADER) + 4;
   inlen = state->RCV_BUFFER_LEN - sizeof(DHCP_HEADER) - 4;

   /* Get the client ID; use CHADDR if none */
   cid_ptr = DHCPSRV_find_option(inp, inlen, DHCPOPT_CLIENTID);
   if (cid_ptr) {
      cid_ptr++;
      cid_len = ntohc(cid_ptr);
      cid_ptr++;
   } else {
      DHCP_HEADER_PTR pkt_ptr = (DHCP_HEADER_PTR)state->RCV_BUFFER;
      cid_ptr = pkt_ptr->CHADDR;
      cid_len = ntohc(pkt_ptr->HLEN);
      if (cid_len > sizeof(pkt_ptr->CHADDR)) {
         cid_len = sizeof(pkt_ptr->CHADDR);
      } /* Endif */
   } /* Endif */

   /* Get the server ID */
   sid_ptr = DHCPSRV_find_option(inp, inlen, DHCPOPT_SERVERID);
   if (sid_ptr && ntohc(sid_ptr+1) == DHCPSIZE_SERVERID) {
      sid_ptr += 2;
      serverid = ntohl(sid_ptr);
   } else {
      sid_ptr = NULL;
   } /* Endif */

   /* Get the requested lease */
   lease_ptr = DHCPSRV_find_option(inp, inlen, DHCPOPT_LEASE);
   if (lease_ptr && ntohc(lease_ptr+1) == DHCPSIZE_LEASE) {
      lease_ptr += 2;
      lease = ntohl(lease_ptr);
   } else {
      lease_ptr = NULL;
   } /* Endif */

   addrp = NULL;
   RTCS_mutex_lock(&state->IPLIST_SEM);

   if (!addrp) {
      addrp = DHCPSRV_find_clientid(&state->IP_LEASED,  cid_ptr, cid_len, NULL);
   } /* Endif */

   if (!addrp && sid_ptr) {
      addrp = DHCPSRV_find_clientid(&state->IP_OFFERED, cid_ptr, cid_len, NULL);
   } /* Endif */

   /* Start CR 2089 */
   /* check whether any available address was previously offered/leased to the client */   
   if (!addrp) {
      addrp = DHCPSRV_find_clientid(&state->IP_AVAIL, cid_ptr, cid_len, NULL);
   } /* Endif */    
   /* End CR 2089 */
      
   if (addrp) {

      if (sid_ptr && serverid != (*addrp)->OPTIONS->SERVERID) {

         reply = FALSE;

         addr = DHCPSRV_lease_stop(addrp);
         DHCPSRV_lease_start(&state->IP_AVAIL, addr, 0);

      } else if (lease_ptr && lease > (*addrp)->OPTIONS->LEASE) {

         DHCPSRV_write_header(state, NULL, 0, DHCPTYPE_DHCPNAK);
         DHCPSRV_write_end(state);
         reply = TRUE;

      } else {

         if (!lease_ptr) {
            lease = (*addrp)->OFFER;
         } /* Endif */

         DHCPSRV_write_header (state, *addrp, lease, DHCPTYPE_DHCPACK);
         DHCPSRV_write_options(state, *addrp);
         DHCPSRV_write_end    (state);
         reply = TRUE;

         addr = DHCPSRV_lease_stop(addrp);
         DHCPSRV_lease_start(&state->IP_LEASED, addr, lease);

      } /* Endif */
   } /* Endif */

   RTCS_mutex_unlock(&state->IPLIST_SEM);

   if (reply) {
      DHCPSRV_send(state);
   } /* Endif */

} /* Endbody */
Ejemplo n.º 8
0
static void DHCPSRV_service_discover
   (
      DHCPSRV_STATE_STRUCT_PTR   state
   )
{ /* Body */
   uchar_ptr                     inp,   cid_ptr, opt_ptr;
   uint_32                       inlen, cid_len;
   DHCPSRV_ADDR_STRUCT_PTR       addr;
   DHCPSRV_ADDR_STRUCT_PTR _PTR_ addrp;
   uint_32                       time, lease;
   boolean                       leased, avail, newcid;

   inp   = state->RCV_BUFFER     + sizeof(DHCP_HEADER) + 4;
   inlen = state->RCV_BUFFER_LEN - sizeof(DHCP_HEADER) - 4;

   /* Get the client ID; use CHADDR if none */
   cid_ptr = DHCPSRV_find_option(inp, inlen, DHCPOPT_CLIENTID);
   if (cid_ptr) {
      cid_ptr++;
      cid_len = ntohc(cid_ptr);
      cid_ptr++;
   } else {
      DHCP_HEADER_PTR pkt_ptr = (DHCP_HEADER_PTR)state->RCV_BUFFER;
      cid_ptr = pkt_ptr->CHADDR;
      cid_len = ntohc(pkt_ptr->HLEN);
      if (cid_len > sizeof(pkt_ptr->CHADDR)) {
         cid_len = sizeof(pkt_ptr->CHADDR);
      } /* Endif */
   } /* Endif */

   addrp = NULL;
   RTCS_mutex_lock(&state->IPLIST_SEM);

   /* First check whether the client already has a lease */
   if (!addrp) {
      addrp = DHCPSRV_find_clientid(&state->IP_LEASED,  cid_ptr, cid_len, &time);
      leased = TRUE;
      avail  = FALSE;
      newcid = FALSE;
   } /* Endif */

   /* Next check whether the client has been offered a lease */
   if (!addrp) {
      addrp = DHCPSRV_find_clientid(&state->IP_OFFERED, cid_ptr, cid_len, &time);
      leased = FALSE;
      avail  = FALSE;
      newcid = FALSE;
   } /* Endif */

   /* Next check whether any available address was previously offered/leased to the client */
   if (!addrp) {
      addrp = DHCPSRV_find_clientid(&state->IP_AVAIL,   cid_ptr, cid_len, NULL);
      leased = FALSE;
      avail  = TRUE;
      newcid = FALSE;
   } /* Endif */

   /* Next check whether the client's requested address is available */
   if (!addrp) {
      _ip_address reqaddr;

      opt_ptr = DHCPSRV_find_option(inp, inlen, DHCPOPT_ADDRESS);
      if (opt_ptr && ntohc(opt_ptr+1) == DHCPSIZE_ADDRESS) {
         reqaddr = ntohl(opt_ptr+2);
      } else {
         DHCP_HEADER_PTR pkt_ptr = (DHCP_HEADER_PTR)state->RCV_BUFFER;
         reqaddr = ntohl(pkt_ptr->CIADDR);
      } /* Endif */

      addrp = DHCPSRV_find_addr(&state->IP_AVAIL, reqaddr);
      leased = FALSE;
      avail  = TRUE;
      newcid = TRUE;
   } /* Endif */

   /* Finally, offer the first available address */
   if (!addrp) {
      if (state->IP_AVAIL) {
         addrp = &state->IP_AVAIL;
      } /* Endif */
      leased = FALSE;
      avail  = TRUE;
      newcid = TRUE;
   } /* Endif */

   if (newcid && addrp) {
      addrp = DHCPSRV_update_clientid(addrp, cid_ptr, cid_len);
   } /* Endif */

   if (addrp) {

      /* Determine length of offer */
      opt_ptr = DHCPSRV_find_option(inp, inlen, DHCPOPT_LEASE);
      if (opt_ptr && ntohc(opt_ptr+1) == DHCPSIZE_LEASE) {
         lease = ntohl(opt_ptr+2);
         if (lease > (*addrp)->OPTIONS->LEASE) {
            lease = (*addrp)->OPTIONS->LEASE;
         } /* Endif */
      } else if (leased) {
         lease = time;
      } else {
         lease = (*addrp)->OPTIONS->LEASE;
      } /* Endif */
      (*addrp)->OFFER = lease;

      DHCPSRV_write_header (state, *addrp, lease, DHCPTYPE_DHCPOFFER);
      DHCPSRV_write_options(state, *addrp);
      DHCPSRV_write_end    (state);

      /* Start CR 1547 */
      /* probe the address to see if it is already taken (if so configured) */
  
  
      if (addrp && DHCPSRV_cfg->FLAGS & DHCPSVR_FLAG_DO_PROBE) {
          uint_32   timeout = 50; /* miliseconds */
          uint_32   error;
          
          /* note: this will hang the dhserver application while we await the probe result */
          error = RTCS_ping((*addrp)->IP_ADDR, &timeout, 0xFACE);
          
          if (error == RTCS_OK) {
             /* bad news: someone answered this ping, we can't use this address */
             addr = DHCPSRV_lease_stop(addrp);
             DHCPSRV_lease_start(&state->IP_TAKEN, addr, DHCPTIME_OFFER);
             avail = FALSE;
             
             /* nak this discover, client will send us another */
             DHCPSRV_write_header(state, NULL, 0, DHCPTYPE_DHCPNAK);
             DHCPSRV_write_end(state);
             
          }
      }
     /* End CR 1547 */ 
      
      /* Reserve the offer for at least DHCPTIME_OFFER */
      if (avail) {
         addr = DHCPSRV_lease_stop(addrp);
         DHCPSRV_lease_start(&state->IP_OFFERED, addr, DHCPTIME_OFFER);
      } else if (time < DHCPTIME_OFFER) {
         DHCPSRV_lease_extend(addrp, DHCPTIME_OFFER - time);
      } /* Endif */

   } else {
      DHCPSRV_write_header(state, NULL, 0, DHCPTYPE_DHCPNAK);
      DHCPSRV_write_end(state);
   } /* Endif */

   RTCS_mutex_unlock(&state->IPLIST_SEM);

   DHCPSRV_send(state);

} /* Endbody */
Ejemplo n.º 9
0
static void DHCPSRV_write_header
   (
      DHCPSRV_STATE_STRUCT_PTR   state,
      DHCPSRV_ADDR_STRUCT_PTR    lease_ptr,
      uint_32                    lease_time,
      uchar                      msgtype
   )
{ /* Body */
   DHCP_HEADER_PTR   outp;
   DHCP_HEADER_PTR   inp;
   uchar_ptr         optptr;
   volatile uint_32           optlen;
   uint_32           temp_long;
   uint_16           temp_short;
   uchar             temp_char;

   outp = (DHCP_HEADER_PTR)state->SND_BUFFER;
   inp  = (DHCP_HEADER_PTR)state->RCV_BUFFER;

   /* Build a DHCPOFFER, DHCPACK, or DHCPNAK packet */
   htonc(outp->OP, DHCPOP_BOOTREPLY);
   htonc(outp->HTYPE, ARPLINK_ETHERNET);
   temp_char = ntohc(inp->HLEN);
   htonc(outp->HLEN, temp_char);
   htonc(outp->HOPS, 0);

   /* Use client's existing transaction ID */
   temp_long = ntohl(inp->XID);
   htonl(outp->XID, temp_long);

   htons(outp->SECS, 0);

   if (ntohl(inp->GIADDR) == 0) {
      htons(outp->FLAGS, 0);
   } else {
      temp_short = ntohs(inp->FLAGS);
      htons(outp->FLAGS, temp_short);
   } /* Endif */

   if (msgtype == DHCPTYPE_DHCPOFFER) {
      htonl(outp->CIADDR, 0);
   } else {
      temp_long = ntohl(inp->CIADDR);
      htonl(outp->CIADDR, temp_long);
   } /* Endif */

   if (msgtype == DHCPTYPE_DHCPNAK) {
      htonl(outp->YIADDR, 0);
      htonl(outp->SIADDR, 0);
   } else {
      htonl(outp->YIADDR, lease_ptr->IP_ADDR);
      htonl(outp->SIADDR, lease_ptr->OPTIONS->SADDR);
   } /* Endif */

   htonl(outp->GIADDR, 0);

   _mem_copy(inp->CHADDR, outp->CHADDR, sizeof(outp->CHADDR));

   if (msgtype == DHCPTYPE_DHCPNAK) {
      _mem_zero(outp->SNAME, sizeof(outp->SNAME));
      _mem_zero(outp->FILE,  sizeof(outp->FILE));
   } else {
      _mem_copy(lease_ptr->OPTIONS->SNAME, outp->SNAME, sizeof(outp->SNAME));
      _mem_copy(lease_ptr->OPTIONS->FILE,  outp->FILE,  sizeof(outp->FILE));
   } /* Endif */

   /*
   ** Fill in the required response options. These are message type,
   ** subnet mask, and server id.
   */

   optlen = sizeof(DHCP_HEADER);
   optptr = state->SND_BUFFER + optlen;

   /* The Magic Cookie must always be the first thing in the OPTIONS */
   htonl(optptr, DHCP_MAGIC);
   optptr += DHCPSIZE_MAGIC;
   optlen += DHCPSIZE_MAGIC;

#define DHCP_OPTION(type,len,val) \
            htonc(optptr, DHCPOPT_  ## type); optptr++; optlen++; \
            htonc(optptr, DHCPSIZE_ ## type); optptr++; optlen++; \
            hton ## len(optptr, val);                             \
            optptr += DHCPSIZE_ ## type;                          \
            optlen += DHCPSIZE_ ## type

   DHCP_OPTION(MSGTYPE,  c, msgtype);
   if (msgtype != DHCPTYPE_DHCPNAK) {
      DHCP_OPTION(SERVERID, l, lease_ptr->OPTIONS->SERVERID);
      DHCP_OPTION(MASK,     l, lease_ptr->OPTIONS->MASK);
      DHCP_OPTION(LEASE,    l, lease_time);
   } /* Endif */

   state->SND_BUFFER_LEN = optlen;

} /* Endbody */
Ejemplo n.º 10
0
static RTCSPCB_PTR NAT_IPREASM_reasm_dgram
   (
      IP_DGRAM_PTR   dgram    /* [IN] the dgram descriptor */
   )
{ /* Body */
   RTCSPCB_PTR outpcb;
   PCB_PTR     bpcb;
   PCB_FRAGMENT _PTR_ pcb_frag_ptr;
   uchar_ptr   data;
   uint_32     iphlen  = (ntohc(dgram->IPH.VERSLEN) & 0xF) << 2;
   uint_32     ip_totlen = iphlen + dgram->TOTLEN;

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

   data = (uchar_ptr)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 */
   htons(dgram->IPH.FRAGMENT, 0);
   _mem_copy(&dgram->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 */
   NAT_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->PROTO);
   RTCSPCB_SET_TRANS_DELTA(outpcb, iphlen);

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

   return outpcb;

} /* Endbody */
Ejemplo n.º 11
0
uint_32 NAT_ALG_tftp_apply
   (
      RTCSPCB_PTR _PTR_    pcb_ptr_ptr,               /* [IN/OUT] PCB containing packet   */
      boolean              pub_to_prv,                /* [IN] Direction of packet         */
      pointer              alg_cfg_ptr,               /* [IN] Pointer to TFTP config      */
      pointer _PTR_        session_ptr_ptr   /* [OUT] Pointer to session         */
   )
{ /* Body */
   NAT_SESSION_STRUCT_PTR  nat_session_ptr = *((NAT_SESSION_STRUCT_PTR *)session_ptr_ptr);
   uchar_ptr               data_ptr = (pointer)RTCSPCB_DATA(*pcb_ptr_ptr);
   IP_HEADER_PTR           ip_header_ptr = (IP_HEADER_PTR)(pointer)data_ptr;
   TRANSPORT_UNION         transport;
   TFTP_HEADER_PTR         tftp_header_ptr;
   uint_16                 opcode, block;
 
   if (nat_session_ptr == NULL) {
      return RTCS_OK;
   } /* Endif */
   
   
   /* TFTP uses UDP */
   if (ntohc(ip_header_ptr->PROTOCOL) != IPPROTO_UDP) {
      return RTCS_OK;
   } /* Endif */
      
   transport.PTR = TRANSPORT_PTR(ip_header_ptr);
   
   /* The UDP length should be long enough to contain a TFTP header */
   if (ntohs(transport.UDP_PTR->LENGTH) < sizeof(UDP_HEADER) + sizeof(TFTP_HEADER)) {
      return RTCS_OK;
   } /* Endif */         
   
   tftp_header_ptr = (TFTP_HEADER_PTR)(pointer)(transport.UDP_PTR + 1);

   opcode = ntohs(tftp_header_ptr->OP);
   block = ntohs(tftp_header_ptr->BLOCK);
   
   /*
   ** A normal reply should have:  OP 3 (DATA) and BLOCK 1 (first block) or
   ** an OP 4 and BLOCK 0. Error replies should have: OP 5, and a variable 
   ** error code 
   */
   if ((opcode != 3 || block != 1) &&
       (opcode != 4 || block != 0) &&
       (opcode != 5))   
   {
      return RTCS_OK;
   } /* Endif */      

   if (nat_session_ptr->SNAT_OR_DNAT == SNAT) {
      /* We only need to consider the first packet returned by the server */
      if (!pub_to_prv) {
         return RTCS_OK;
      } /* Endif */

      /* Make sure port number is the TFTP port number */
      if (nat_session_ptr->PUB_PORT != IPPORT_TFTP) {
         return RTCS_OK;
      } /* Endif */
      
      /* Set new server port number */
      nat_session_ptr->PUB_PORT = ntohs(transport.UDP_PTR->SRC_PORT);
   } else {
      /* We only need to consider the first packet returned by the server */
      if (pub_to_prv){
         return RTCS_OK;
      } /* Endif */

      /* Make sure port number is the TFTP port number */
      if (nat_session_ptr->PRV_PORT != IPPORT_TFTP) {
         return RTCS_OK;
      } /* Endif */
      
      /* Set new server port number */
      nat_session_ptr->PRV_PORT = ntohs(transport.UDP_PTR->SRC_PORT);       
   } /* Endif */
   
   return RTCS_OK;   
} /* Endbody */
Ejemplo n.º 12
0
DNAT_RULE_STRUCT_PTR DNAT_lookup_rule
   (
      NAT_CFG_STRUCT_PTR      nat_cfg_ptr,
      IP_HEADER_PTR           ip_header_ptr,
      boolean                 pub_to_prv
    )
{ /* Body */
   TRANSPORT_UNION            transport;
   DNAT_ELEMENT_STRUCT_PTR    element_ptr;
   _ip_address                source_ip = ntohl(ip_header_ptr->SOURCE);
   _ip_address                target_ip = ntohl(ip_header_ptr->DEST);
   uint_32                    ip_protocol;
   uint_16                    source_port, destination_port; /* source port and destination port */
 
   transport.PTR = TRANSPORT_PTR(ip_header_ptr);
   
   ip_protocol = ntohc(ip_header_ptr->PROTOCOL);

   /* NAT spports ICMP, UDP and TCP transport layer protocols */
   switch (ip_protocol) {
      case IPPROTO_TCP:
          destination_port = ntohs(transport.TCP_PTR->dest_port);
          source_port = ntohs(transport.TCP_PTR->source_port);
          break;
      
      case IPPROTO_UDP:
          destination_port = ntohs(transport.UDP_PTR->DEST_PORT);
          source_port = ntohs(transport.UDP_PTR->SRC_PORT);
          break;
      
      case IPPROTO_ICMP:
          /* Allow all ICMP request/reply */
          return NULL;
   } /* Endswitch */
     
     
   element_ptr = (DNAT_ELEMENT_STRUCT_PTR) _queue_head(&nat_cfg_ptr->RULE_QUEUE);  

   /*
   ** Check for the target port and then forward the packet to the corresponding 
   ** DNAT rule target ip.
   */
   while (element_ptr != NULL) {
      if (element_ptr->RULE.IP_PROTOCOL == ip_protocol) {
         if (pub_to_prv) {
            if ((destination_port >= element_ptr->RULE.PUBLIC_START_PORT) &&
                (destination_port <= element_ptr->RULE.PUBLIC_END_PORT)) {
               break;
            }
         } else {
            if ((source_ip == element_ptr->RULE.PRIVATE_IP) &&
                (source_port >= element_ptr->RULE.PRIVATE_START_PORT) &&  
                (source_port <= element_ptr->RULE.PRIVATE_END_PORT)) {
               break;  
            }
         }
      }
      element_ptr = (DNAT_ELEMENT_STRUCT_PTR)  _queue_next(&nat_cfg_ptr->RULE_QUEUE, &element_ptr->ELEMENT);
   } /* Endwhile */
   
   if (element_ptr!=NULL) {
      return &element_ptr->RULE;
   } else {
      return NULL;
   }
}/* Endbody */
Ejemplo n.º 13
0
void BOOTP_service
   (
      RTCSPCB_PTR    rtcs_pcb     /* [IN] BOOTREPLY packet */
   )
{ /* Body */
   IP_IF_PTR               if_ptr = (IP_IF_PTR)rtcs_pcb->IFSRC;
   TCPIP_PARM_BOOTP _PTR_  parms = (TCPIP_PARM_BOOTP _PTR_)if_ptr->BOOT;
   BOOTP_CFG_PTR           bootp = (BOOTP_CFG_PTR) &parms->config;
   BOOTP_PACKET_PTR        bootreply;
   IPIF_PARM               parms_bind;
   uint_32                 error;

   uchar_ptr   opt;
   uchar       len, optval, optlen;

   /* Make sure the datagram is large enough */
   bootreply = (BOOTP_PACKET_PTR)RTCSPCB_DATA(rtcs_pcb);
   if (RTCSPCB_SIZE(rtcs_pcb) < sizeof(BOOTP_PACKET)) {
      RTCSLOG_PCB_FREE(rtcs_pcb, RTCS_OK);
      RTCSPCB_free(rtcs_pcb);
      return;
   } /* Endif */

   /* Make sure the XID matches */
   if (ntohl(bootreply->HEAD.XID) != bootp->XID) {
      RTCSLOG_PCB_FREE(rtcs_pcb, RTCS_OK);
      RTCSPCB_free(rtcs_pcb);
      return;
   } /* Endif */

   RTCSLOG_PCB_READ(rtcs_pcb, RTCS_LOGCTRL_PORT(IPPORT_BOOTPC), 0);

   /* OK, assume this reply is for us */
   BOOTP_close(if_ptr);

   /* Get our IP address, and pick the default netmask */
   parms_bind.ihandle = if_ptr;
   parms_bind.address = ntohl(bootreply->HEAD.YIADDR);
   parms_bind.locmask = 0xFFFFFFFFL;
   parms_bind.netmask = IN_DEFAULT_NET(parms_bind.address);
   parms_bind.probe = FALSE;

   parms->data->SADDR = ntohl(bootreply->HEAD.SIADDR);
#if RTCSCFG_BOOTP_RETURN_YIADDR
   parms->data->CLIENTADDR = ntohl(bootreply->HEAD.YIADDR);
#endif
   _mem_copy(bootreply->DATA.SNAME, parms->data->SNAME, sizeof(BOOTP_DATA));
   RTCSLOG_PCB_FREE(rtcs_pcb, RTCS_OK);
   RTCSPCB_free(rtcs_pcb);

   /* Parse the vend field for recognized options */
   opt = parms->data->OPTIONS;
   len = sizeof(parms->data->OPTIONS);
   if (ntohl(opt) == BOOTP_MAGIC) {
      opt += 4;
      len -= 4;

#define BOOTP_NEXTOPT   opt += optlen; \
                        break

      while (len) {

         /* Get the next option code */
         optval = ntohc(opt);
         opt++;
         len--;

         /* Interpret the pad and end options */
         if (optval == BOOTPOPT_END) break;
         if (optval == BOOTPOPT_PAD) continue;

         /* All other codes have a length byte */
         if (len == 0) break;
         optlen = ntohc(opt);
         opt++;
         len--;
         if (len < optlen) break;
         len -= optlen;

         switch (optval) {

         case BOOTPOPT_MASK:
            if (optlen != 4) {BOOTP_NEXTOPT;}
            parms_bind.netmask = ntohl(opt);
            opt += 4;
            break;

         default:
            BOOTP_NEXTOPT;
         } /* Endswitch */

      } /* Endwhile */
   } /* Endif */

   /* Bind the received IP address to this interface */
   error = RTCSCMD_internal(parms_bind, IPIF_bind);

   /* Done -- unblock the application */
   RTCSCMD_complete(parms, error);

} /* Endbody */
Ejemplo n.º 14
0
void ICMP_service
   (
      RTCSPCB_PTR    pcb,        /* [IN/OUT] incoming packet */
      pointer        dummy       /* [IN]     not used        */
   )
{ /* Body */
   ICMP_CFG_STRUCT_PTR  ICMP_cfg_ptr;
   ICMP_HEADER_PTR      packet;
   _ip_address          source, dest;
   uint_32              error;
   uint_16              chksum;
   uchar                type;


   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 = 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 */

   /*
   ** 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;
   } /* Endif */

   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  = ntohl(rdpacket->DATA);
         origdest = ntohl(rdpacket->IP.DEST);

         // If we receive a redirect to ourselves, silently discard it
         if (IP_is_local(NULL, gateway)) {
            IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++);
            // Might want to add a counter here

         } 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:

      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, (uint_32)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, (uint_32)pcb));
         RTCSLOG_PCB_FREE(pcb, error);
         RTCSPCB_free(pcb);
         return;
      } /* Endif */

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

      /* 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, 0);
      pcb = NULL;
      break;

   case ICMPTYPE_ECHO_REPLY:
      { /* Scope */
         ICMP_ECHO_HEADER_PTR echopacket = (ICMP_ECHO_HEADER_PTR)packet;
         ICMP_PARM_PTR        parms;
         uint_16              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  = ntohs(echopacket->ID);
         seq = ntohs(echopacket->SEQ);

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

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

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

               TCPIP_Event_cancel(&parms->EXPIRE);

               /* calculate round trip time */
               parms->timeout = RTCS_timer_get_interval(parms->timeout, RTCS_time_get());

               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;
         uint_32             len, remain;
         boolean             discard = TRUE;
         uchar               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)((uchar_ptr)packet + sizeof(ICMP_HEADER) + 4);
            remain -= sizeof(ICMP_HEADER) + 4;

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

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

               /* Get next header */
               ip = (IP_HEADER_PTR)((uchar_ptr)(ip) + len);
               remain -= len;
               source = ntohl(ip->SOURCE);

               discard = IP_is_local(NULL, source);

            } while(discard);

            len = (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 = 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, 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 */
Ejemplo n.º 15
0
void ICMP_send_error_internal
   (
      uint_8         type,    /* [IN] the type to send */
      uint_8         code,    /* [IN] the code to send */
      uint_32        param,   /* [IN] a parameter */
      IP_HEADER_PTR  iph,     /* [IN] the IP header */
      RTCSPCB_PTR    origpcb, /* [IN] pcb with bad packet */
      uint_32        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 = ntohl(iph->SOURCE);
   _ip_address          ipdst = ntohl(iph->DEST);
   uint_16              iphdrlen = (ntohc(iph->VERSLEN) & 0x0F) << 2;
   uint_16              ippktlen = ntohs(iph->LENGTH) - iphdrlen;
   uint_16              checksum;
   _ip_address          icmpsrc = IP_is_local(NULL,ipdst) ? ipdst : INADDR_ANY;
   uint_32              error;
   uchar_ptr            buffer;
   uint_32              temp;
#if RTCSCFG_ENABLE_NAT   
   TCP_HEADER_PTR       tcp_hdr;
   UDP_HEADER_PTR       udp_hdr;
   IP_HEADER_PTR        ip_hdr;
   uint_32              protocol;
   uint_16              src_port, dest_port;
   uint_32 (_CODE_PTR_ _PTR_  nat_exec)(RTCSPCB_PTR _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 (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)((uchar_ptr)iph + iphdrlen);
      if (!ICMPTYPE_ISQUERY(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, (uchar_ptr)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, (uint_32)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, (uint_32)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);
   htonc(icmph->HEAD.TYPE,     type);
   htonc(icmph->HEAD.CODE,     code);
   htons(icmph->HEAD.CHECKSUM, 0);
   htonl(icmph->DATA,          param);

   checksum = IP_Sum_PCB (0, pcb);
   checksum = IP_Sum_invert(checksum);
   htons(icmph->HEAD.CHECKSUM, 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 = 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)((uchar_ptr)ip_hdr + IPH_LEN(ip_hdr));
               dest_port = ntohs(tcp_hdr->dest_port);
               src_port  = ntohs(tcp_hdr->source_port);
               htons(tcp_hdr->dest_port, src_port);
               htons(tcp_hdr->source_port, dest_port);
               break;
            case IPPROTO_UDP:
               udp_hdr = (UDP_HEADER_PTR)((uchar_ptr)ip_hdr + IPH_LEN(ip_hdr));
               dest_port = ntohs(udp_hdr->DEST_PORT);
               src_port  = ntohs(udp_hdr->SRC_PORT);
               htons(udp_hdr->DEST_PORT, src_port);
               htons(udp_hdr->SRC_PORT, dest_port);            
               break;
            default:
               // should not get here
               break;
         }
      }
      // swap IPs
      ipsrc = ntohl(ip_hdr->SOURCE);
      ipdst = ntohl(ip_hdr->DEST);
      htonl(ip_hdr->SOURCE, ipdst);
      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 = 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)((uchar_ptr)ip_hdr + IPH_LEN(ip_hdr));
                  dest_port = ntohs(tcp_hdr->dest_port);
                  src_port  = ntohs(tcp_hdr->source_port);
                  htons(tcp_hdr->dest_port, src_port);
                  htons(tcp_hdr->source_port, dest_port);
                  break;
               case IPPROTO_UDP:
                  udp_hdr = (UDP_HEADER_PTR)((uchar_ptr)ip_hdr + IPH_LEN(ip_hdr));
                  dest_port = ntohs(udp_hdr->DEST_PORT);
                  src_port  = ntohs(udp_hdr->SRC_PORT);
                  htons(udp_hdr->DEST_PORT, src_port);
                  htons(udp_hdr->SRC_PORT, dest_port);            
                  break;
               default:
                  // should not get here
                  break;
            }
         }
         // swap IPs
         ipsrc = ntohl(ip_hdr->SOURCE);
         ipdst = ntohl(ip_hdr->DEST);
         htonl(ip_hdr->SOURCE, ipdst);
         htonl(ip_hdr->DEST,ipsrc);   

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

         // recalculate icmpsrc, and use new ipsrc.
         ipdst = ntohl(ip_hdr->DEST);
         ipsrc = 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 */
Ejemplo n.º 16
0
ENET_ECB_STRUCT_PTR ENET_find_receiver
   (
      /* [IN] the Ethernet state structure */
      ENET_CONTEXT_STRUCT_PTR  enet_ptr,

      /* [IN] the received packet */
      ENET_HEADER_PTR      packet_ptr,
      
      uint_32_ptr          length_ptr
   )
{ 
   ENET_ECB_STRUCT_PTR  ecb_ptr;
   ENET_MCB_STRUCT_PTR  mcb_ptr;
   uchar_ptr            type_ptr;
   uint_32              hdrlen;
   _enet_address        dest;
   uint_16              type;


   hdrlen = sizeof(ENET_HEADER);
   type_ptr = packet_ptr->TYPE;
   type = ntohs(type_ptr);

   if (type == ENETPROT_8021Q) {
      ENET_8021QTAG_HEADER_PTR tag_ptr = (ENET_8021QTAG_HEADER_PTR)(type_ptr+2);
      hdrlen += sizeof(ENET_8021QTAG_HEADER);
      type_ptr = tag_ptr->TYPE;
      type = ntohs(type_ptr);
   } 

   if (type <= ENETPROT_LENGTH_TYPE_BOUNDARY) {               
      ENET_8022_HEADER_PTR llc_ptr = (ENET_8022_HEADER_PTR)(type_ptr+2);
      if ((ntohc(llc_ptr->DSAP) != 0xAA)
       || (ntohc(llc_ptr->SSAP) != 0xAA)) {
         return NULL;
      } 
      if (*length_ptr < hdrlen + type) {
         return NULL;
      } 
      *length_ptr = hdrlen + type;
      type_ptr = llc_ptr->TYPE;
      type = ntohs(type_ptr);
   } 

   for (ecb_ptr = enet_ptr->ECB_HEAD; ecb_ptr; ecb_ptr = ecb_ptr->NEXT) {
      if (ecb_ptr->TYPE == type) {

         ntohe(packet_ptr->DEST, dest);
         if ((dest[0] & 1) && !((dest[0] == 0xFF)
                             && (dest[1] == 0xFF)
                             && (dest[2] == 0xFF)
                             && (dest[3] == 0xFF)
                             && (dest[4] == 0xFF)
                             && (dest[5] == 0xFF))) {

            /*
            ** The destination is a multicast address.
            ** Check the joined mulicast groups.
            */
            for (mcb_ptr = ecb_ptr->MCB_HEAD; mcb_ptr; mcb_ptr = mcb_ptr->NEXT) {
               if ((dest[0] == mcb_ptr->GROUP[0])
                && (dest[1] == mcb_ptr->GROUP[1])
                && (dest[2] == mcb_ptr->GROUP[2])
                && (dest[3] == mcb_ptr->GROUP[3])
                && (dest[4] == mcb_ptr->GROUP[4])
                && (dest[5] == mcb_ptr->GROUP[5])) {
                  break;
               } 
            } 

            if (!mcb_ptr) {
               /*
               ** We received a packet multicasted to a group we
               ** haven't joined.  Break out of the big for loop
               ** and discard the packet.  We don't continue the
               ** big for loop because there is only one ECB per
               ** type and we already found it.
               */
               ecb_ptr = NULL;
            } 
         } 

         break;
      } 
   } 

   return ecb_ptr;

}