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