/* *=========================================================================== * ipnet_udp_fast_deliver_data *=========================================================================== * Description: Deliver an UDP packet to a socket that is bound to a unicast * address. * Parameters: sock - The socket the packet will be delivered to. * pkt - The UDP packet to deliver. * nat_t - NAT_T processing. * Returns: IP_TRUE - The fast path processing was successful. * IP_FALSE - Need to use the normal receive path. * */ IP_STATIC Ip_bool ipnet_udp_fast_deliver_data(Ipnet_socket *sock, Ipcom_pkt *pkt, int *nat_t) { Ipnet_pkt_udp *udp_hdr; int original_start = pkt->start; Ipcom_socket_eventcb event_cb = sock->ipcom.event_cb; udp_hdr = (Ipnet_pkt_udp*) &pkt->data[pkt->tlstart]; if (IP_UNLIKELY(pkt->end - pkt->tlstart < IPNET_UDP_HDR_SIZE || pkt->end - pkt->tlstart < ip_ntohs(udp_hdr->ulen))) return IP_FALSE; if (udp_hdr->sum != 0 && IP_BIT_ISFALSE(pkt->flags, IPCOM_PKT_FLAG_LOOPED_BACK)) { Ip_u16 chksum; /* Only check packets that was not created locally */ #ifdef IPCOM_USE_HW_CHECKSUM_RX if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_HW_CHECKSUM)) chksum = 0; else if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_TL_CHECKSUM)) chksum = ipcom_in_checksum_finish(pkt->chk); else #endif /* IPCOM_USE_HW_CHECKSUM_RX */ { pkt->chk += ipcom_in_checksum_update(&pkt->data[pkt->tlstart], (Ip_size_t) ip_ntohs(udp_hdr->ulen)); chksum = ipcom_in_checksum_finish(pkt->chk); } if (IP_UNLIKELY(chksum != 0)) return IP_FALSE; } pkt->fd = sock->ipcom.fd; pkt->start = pkt->tlstart + IPNET_UDP_HDR_SIZE; if (IP_UNLIKELY(ipnet_udp_encapsulation(sock, pkt, nat_t))) { /* Continue processing */ ipcom_pkt_set_info(pkt, IPNET_PKT_INFO_ENCAP_UDP, sizeof(*udp_hdr), udp_hdr); pkt->start = original_start; return IP_FALSE; } if (ipnet_queue_received_packet(pkt, sock) != 0) { pkt->start = original_start; return IP_FALSE; } if (event_cb != IP_NULL) event_cb(&sock->ipcom, pkt, IP_SOEVENT_CB_INPKT); IPCOM_MIB2(udpInDatagrams++); IPCOM_MIB2_U64_INC(udpHCInDatagrams); return IP_TRUE; }
/* *=========================================================================== * ipnet_loopback_ip_output *=========================================================================== * Description: Updates statistics counter and add the link trailer. * Parameters: netif - The interface the packet was sent to. * rt - The route followed (ignored). * pkt - The packet to loopback. pkt->start is the offset to the * IP header. * Returns: 0 = success, 0< = error code. * */ IP_STATIC int ipnet_loopback_ip_output(Ipnet_netif *netif, Ipnet_route_entry *rt, Ipcom_pkt *pkt) { Ipnet_loopback_trailer_t *tr; IPCOM_UNUSED_ARG(rt); if (IP_UNLIKELY(IP_BIT_ISFALSE(netif->ipcom.flags, IP_IFF_UP))) { ipcom_pkt_free(pkt); return -IP_ERRNO_EHOSTDOWN; } #ifdef IPCOM_ZEROCOPY pkt = ipcom_pkt_make_linear(pkt); if (IP_UNLIKELY(pkt == IP_NULL)) /* Not enough packets to make this packet linear, not much to about it */ return 0; #endif /* IPCOM_ZEROCOPY */ IP_BIT_CLR(pkt->flags, IPCOM_PKT_FLAG_OUTPUT); #if defined(IPCOM_USE_INET) || defined(IPCOM_USE_INET6) ip_assert2((pkt->data[pkt->start] & 0xf0) == 0x40 || (pkt->data[pkt->start] & 0xf0) == 0x60); #elif defined(IPCOM_USE_INET) ip_assert2((pkt->data[pkt->start] & 0xf0) == 0x40); #else ip_assert2((pkt->data[pkt->start] & 0xf0) == 0x60); #endif tr = (Ipnet_loopback_trailer_t *) &pkt->data[pkt->end]; IP_SET_32ON8(&tr->scope_id, pkt->ifindex); pkt->ifindex = netif->ipcom.ifindex; return ipnet_if_output(netif, pkt); }
/* *=========================================================================== * ipnet_loopback_drv_output *=========================================================================== * Description: Loops back the packet. * Parameters: netif - The interface the packet was sent to. * pkt - The packet to loopback. pkt->start is the offset to the * IP header. * Returns: 0 = success, 0< = error code. * */ IP_STATIC int ipnet_loopback_drv_output(Ipcom_netif *netif, Ipcom_pkt *pkt) { int ret = 0; /* The ipcom_pkt_input_queue() frees the packet if it cannot be queued, add a reference so that packet is still allocated if that happens */ IPCOM_PKT_ADD_REF(pkt); IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_RX); IP_BIT_SET(pkt->flags, IPCOM_PKT_FLAG_LOOPED_BACK); ret = ipcom_pkt_input_queue(netif, pkt); if (IP_UNLIKELY(ret != -IP_ERRNO_EWOULDBLOCK)) { ip_assert(IPCOM_PKT_HAS_MULTIPLE_OWNERS(pkt)); ipcom_pkt_free(pkt); } return ret; }
/* *=========================================================================== * ipnet_loopback_input *=========================================================================== * Description: Handles loopback packets from the input daemon. * Parameters: netif - A loopback interface. * pkt - The incoming packet. * Returns: 0 = success, <0 = error code. * */ IP_STATIC int ipnet_loopback_input(Ipnet_netif *netif, Ipcom_pkt *pkt) { Ipnet_loopback_trailer_t *tr; ip_assert(IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_ALLOC)); tr = (Ipnet_loopback_trailer_t *) &pkt->data[pkt->end]; pkt->ifindex = IP_GET_32ON8(&tr->scope_id); /* Verify that the indicated netif exists */ if (IP_UNLIKELY(ipnet_if_indextonetif(pkt->vr_index, pkt->ifindex) == IP_NULL)) { ipcom_pkt_free(pkt); return -IP_ERRNO_EINVAL; } #ifndef IP_PORT_LKM IPCOM_PKT_ADD_REF(pkt); (void)ipcom_pkt_output_done(&netif->ipcom, pkt, IP_FLAG_FC_STACKCONTEXT); #endif switch (pkt->data[pkt->start] & 0xf0) { #ifdef IPCOM_USE_INET case 0x40: return ipnet_ip4_input(netif, pkt); #endif #ifdef IPCOM_USE_INET6 case 0x60: return ipnet_ip6_input(netif, pkt); #endif default: IP_PANIC2(); ipcom_pkt_free(pkt); return -IP_ERRNO_EINVAL; } }
/* *=========================================================================== * ipnet_usr_sock_tcp_pkts_from_iov *=========================================================================== * Description: Copies the user data into MSS sized packets. * Parameters: sock - The socket that will be use to send. * msg - 'msg_iov' contains the buffer(s) to send. * flags - IP_MSG_xxx flags. * offset - Number of bytes into the msg->msg_iov buffers * where the copy into packets should start. * total_buf_len - the sum of the length of all * msg->msg_iov buffers in 'msg'. * ppkt - Will point to the created packet(s) if the * operation is successfil. The (*ppkt)->next * points to the next packet in case of more than * one packet was allocated. * Returns: <0 = error code (-IPNET_ERRNO_xxx) * 0 = this operation released the socket lock, the * sendmsg operation must be restarted * >0 = number of bytes that has been allocated in the * socket send buffer and copied into the * packet(s) pointed to by *ppkt. */ IP_STATIC int ipnet_usr_sock_tcp_pkts_from_iov(Ipnet_socket *sock, IP_CONST struct Ip_msghdr *msg, int flags, int offset, int total_buf_len, Ipcom_pkt **ppkt) { Ipcom_pkt *pkt_head; Ipcom_pkt *pkt_tail; Iptcp_tcb *tcb = sock->tcb; int mss = tcb->mss; Ip_u8 *buf; int buf_len; int i = 0; int len = 0; int bytes_to_copy = total_buf_len - offset; Ip_bool non_blocking; Ip_bool urgent = IP_BIT_ISSET(flags, IP_MSG_OOB); *ppkt = IP_NULL; /* * If offset == total_buf_len, which can in particular happen * if both are zero, then the loop immediately below can * access beyond the end of the iovec array. Avoid this. */ if (offset == total_buf_len) return 0; for (buf_len = 0; buf_len <= 0; offset = - buf_len) { struct Ip_iovec *iov = &msg->msg_iov[i++]; buf = (Ip_u8 *) iov->iov_base + offset; buf_len = (int) iov->iov_len - offset; } if (IP_LIKELY(urgent == IP_FALSE)) { iptcp_partial_lock(tcb->send.partial_lock); if (tcb->send.partial != IP_NULL) { len = ipnet_sock_tcp_append_send_data(tcb->send.partial, &buf, &buf_len, mss); if (len > 0) ipcom_atomic_add(&sock->snd_bytes, len); } iptcp_partial_unlock(tcb->send.partial_lock); if (len == bytes_to_copy) /* All data that should be sent was queued to the end of the partial finished TCP segment */ return len; } /* else: urgent packet must be sent in a separate signal since the flag field must have IP_MSG_OOB set for correct processing. */ non_blocking = IP_BIT_ISSET(sock->flags, IPNET_SOCKET_FLAG_NONBLOCKING) || IP_BIT_ISSET(flags, IP_MSG_DONTWAIT); bytes_to_copy = 0; do { int bytes_to_alloc = IP_MIN(mss, buf_len - bytes_to_copy); if (ipcom_atomic_add_and_return(&sock->snd_bytes, bytes_to_alloc) < sock->send_max_bytes + bytes_to_alloc) { bytes_to_copy += bytes_to_alloc; } else { int lowat; ipcom_atomic_sub(&sock->snd_bytes, bytes_to_alloc); if (bytes_to_copy > 0 || non_blocking) break; lowat = IP_MAX(mss, (int) sock->tcb->send.lowat); lowat = IP_MIN(lowat, sock->send_max_bytes); (void)ipnet_usr_sock_wait_until_writable(sock, lowat, IP_NULL); if (sock->ipcom.so_errno) { ipcom_atomic_sub(&sock->snd_bytes, bytes_to_copy); return len > 0 && sock->ipcom.so_errno != IP_ERRNO_EINTR ? len : -sock->ipcom.so_errno; } } } while (bytes_to_copy < buf_len); pkt_head = IP_NULL; pkt_tail = IP_NULL; while (bytes_to_copy > 0) { Ipcom_pkt *pkt; int seg_len = IP_MIN(bytes_to_copy, mss); pkt = ipcom_pkt_malloc(mss + sock->max_hdrspace, IP_FLAG_FC_STACKCONTEXT | (non_blocking ? 0 : IP_FLAG_FC_BLOCKOK)); if (IP_UNLIKELY(pkt == IP_NULL)) break; pkt->start = (pkt->maxlen - mss) & ~0x3; pkt->end = pkt->start + seg_len; pkt->chk = ipnet_in_checksum_memcpy(&pkt->data[pkt->start], buf, seg_len); /* Add this packet to the list of packets that will be sent to ipnetd */ if (pkt_head == IP_NULL) pkt_head = pkt; else pkt_tail->next = pkt; pkt_tail = pkt; len += seg_len; buf += seg_len; bytes_to_copy -= seg_len; } if (IP_LIKELY(pkt_tail != IP_NULL)) { if (IP_UNLIKELY(urgent)) IPNET_MARK_PKT_AS_URGENT(pkt_tail); iptcp_partial_lock(tcb->send.partial_lock); tcb->send.partial = pkt_tail; iptcp_partial_unlock(tcb->send.partial_lock); } *ppkt = pkt_head; return (len == 0 ? -IP_ERRNO_EWOULDBLOCK : len); }
/* *=========================================================================== * ipcom_forwarder_get_fw_if *=========================================================================== * Context: fw * Description: Obtain forwarding interface index corresponding to 'msg' from fw cache * In case of a match the packet referred to by 'msg' is updated * with destination hw address and IP header info. * source MAC must be added before packet is sent. * Parameters: 'msg' : packet descriptor * Returns: index of interface, or -1 if no fw cache entry matches 'msg' * */ IP_STATIC __inline__ int ipcom_forwarder_get_fw_if(fw_msg_t *msg) { #ifdef IPCOM_USE_INET fw_cache_entry_v4_t *e4; Ip_u32 dst4; #endif #ifdef IPCOM_USE_INET6 fw_cache_entry_v6_t *e6; #endif #ifdef IPCOM_USE_FORWARDER_VLAN Ip_u16 vid; fw_cache_entry_vlan_t *ev; #endif #ifdef IPCOM_USE_FORWARDER_IPSEC fw_ipsec_replay_t fw_ipsec_replay; if (msg->ipsec_dec) { int offset = LL_ETH_HDR_SZ; #ifdef IPCOM_USE_FORWARDER_VLAN if (IP_UNLIKELY(msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN || msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN)) offset = LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD; #endif /* IPCOM_USE_FORWARDER_VLAN */ if (ipcom_forwarder_ipsec_decrypt_packet(msg, &fw_ipsec_replay, offset) < 0) { msg->tbl[0] = IPCOM_FORWARDER_PACKET_IPSEC_DROP_PKT; /* Drop packet */ return -1; } } #endif /* IPCOM_USE_FORWARDER_IPSEC */ if (IP_LIKELY(msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV4)) { #ifdef IPCOM_USE_INET /* IPv4 */ e4 = &ipcom_fw.fw_cache_tbl_v4[msg->fw_key]; dst4 = *(Ip_u32 *)(msg->packet + LL_ETH_HDR_SZ + 16); if (IP_UNLIKELY(dst4 != e4->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id)) { #if IPCOM_FORWARDER_CACHE_WAYS > 1 if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 2 if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 3 if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 4 if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 5 if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 6 if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 7 if (IP_UNLIKELY(dst4 != (++e4)->ip4.addr) || IP_UNLIKELY(e4->ip4.rci != *ipcom_fw.rt_cache_id)) #endif #endif #endif #endif #endif #endif #endif goto nomatch; } IP_INCREMENTAL_CHECKSUM(((Ipnet_pkt_ip *)(msg->packet + LL_ETH_HDR_SZ))); #ifdef IPCOM_USE_FORWARDER_IPSEC if (ipcom_forwarder_ipsec_encrypt_packet(msg, &e4->mac_if, &e4->ipsec, &fw_ipsec_replay, LL_ETH_HDR_SZ) <= 0) { Ipnet_pkt_ip *ip = (Ipnet_pkt_ip *)(msg->packet + LL_ETH_HDR_SZ); /* Restore IPv4 header */ ip->ttl++; ip->sum = 0; ip->sum = ipcom_in_checksum(ip, IPCOM_IP_HEADER_LENGTH); return -1; } #endif /* IPCOM_USE_FORWARDER_IPSEC */ *(Ip_u32 *)(msg->packet - 2) = e4->mac_if.dst_mac[0]; *(Ip_u32 *)(msg->packet + 2) = e4->mac_if.dst_mac[1]; *(Ip_u32 *)(msg->packet + 6) = ipcom_fw.fw_port[e4->mac_if.ix[0]].src_type[0]; *(Ip_u16 *)(msg->packet + 10) = ipcom_fw.fw_port[e4->mac_if.ix[0]].src_type[1]; #ifdef IPCOM_USE_FORWARDER_IPSEC *(Ip_u16 *)(msg->packet + 12) = ip_htons(IP_IPv4); #endif /* IPCOM_USE_FORWARDER_IPSEC */ return e4->mac_if.ix[0]; #endif /* IPCOM_USE_INET */ } else if (IP_LIKELY(msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV6)) { #ifdef IPCOM_USE_INET6 /* IPv6 */ e6 = &ipcom_fw.fw_cache_tbl_v6[msg->fw_key]; if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != e6->ip6.addr[0])) || IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) || IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id) #ifdef IPCOM_USE_FORWARDER_VLAN || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6 #endif ) { #if IPCOM_FORWARDER_CACHE_WAYS > 1 if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) || IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) || IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id) #ifdef IPCOM_USE_FORWARDER_VLAN || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6 #endif ) #if IPCOM_FORWARDER_CACHE_WAYS > 2 if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) || IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) || IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id) #ifdef IPCOM_USE_FORWARDER_VLAN || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6 #endif ) #if IPCOM_FORWARDER_CACHE_WAYS > 3 if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) || IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) || IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id) #ifdef IPCOM_USE_FORWARDER_VLAN || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6 #endif ) #if IPCOM_FORWARDER_CACHE_WAYS > 4 if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) || IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) || IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id) #ifdef IPCOM_USE_FORWARDER_VLAN || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6 #endif ) #if IPCOM_FORWARDER_CACHE_WAYS > 5 if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) || IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) || IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id) #ifdef IPCOM_USE_FORWARDER_VLAN || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6 #endif ) #if IPCOM_FORWARDER_CACHE_WAYS > 6 if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) || IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) || IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id) #ifdef IPCOM_USE_FORWARDER_VLAN || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6 #endif ) #if IPCOM_FORWARDER_CACHE_WAYS > 7 if (IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 24) != (++e6)->ip6.addr[0])) || IP_UNLIKELY((*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + 32) != e6->ip6.addr[1])) || IP_UNLIKELY(e6->ip6.rci != *ipcom_fw.rt_cache_id) #ifdef IPCOM_USE_FORWARDER_VLAN || e6->ip6.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6 #endif ) #endif #endif #endif #endif #endif #endif #endif goto nomatch; } SET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ), GET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ)) - 1); #ifdef IPCOM_USE_FORWARDER_IPSEC if (ipcom_forwarder_ipsec_encrypt_packet(msg, &e6->mac_if, &e6->ipsec, &fw_ipsec_replay, LL_ETH_HDR_SZ) <= 0) { /* Restore IPv6 header */ SET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ), GET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ)) + 1); return -1; } #endif /* IPCOM_USE_FORWARDER_IPSEC */ *(Ip_u64 *)(msg->packet - 2) = e6->mac_if.dst_mac64; *(Ip_u64 *)(msg->packet + 6) = *(Ip_u64 *)&ipcom_fw.fw_port[e6->mac_if.ix[0]].src_type[0]; return e6->mac_if.ix[0]; #endif /* IPCOM_USE_INET6 */ } #ifdef IPCOM_USE_FORWARDER_VLAN else if (IP_LIKELY(msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN)) { #ifdef IPCOM_USE_INET /* IPv6 table is also used for VLAN entries, both IPv4 and IPv6 */ ev = (fw_cache_entry_vlan_t *)&ipcom_fw.fw_cache_tbl_v6[msg->fw_key]; dst4 = *(Ip_u32 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 16); vid = *(Ip_u16 *)(msg->packet + LL_ETH_HDR_SZ); /* UP/CFI/VID word */ if (IP_UNLIKELY(ev->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN || dst4 != ev->ipvlan.a.addr_v4 || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) { #if IPCOM_FORWARDER_CACHE_WAYS > 1 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN || dst4 != ev->ipvlan.a.addr_v4 || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 2 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN || dst4 != ev->ipvlan.a.addr_v4 || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 3 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN || dst4 != ev->ipvlan.a.addr_v4 || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 4 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN || dst4 != ev->ipvlan.a.addr_v4 || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 5 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN || dst4 != ev->ipvlan.a.addr_v4 || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 6 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN || dst4 != ev->ipvlan.a.addr_v4 || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 7 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN || dst4 != ev->ipvlan.a.addr_v4 || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #endif #endif #endif #endif #endif #endif #endif goto nomatch; } IP_INCREMENTAL_CHECKSUM(((Ipnet_pkt_ip *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD))); #ifdef IPCOM_USE_FORWARDER_IPSEC if (ipcom_forwarder_ipsec_encrypt_packet(msg, &ev->mac_if, &ev->ipsec, &fw_ipsec_replay, LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD) <= 0) { Ipnet_pkt_ip *ip = (Ipnet_pkt_ip *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD); /* Restore IPv4 header */ ip->ttl--; ip->sum = 0; ip->sum = ipcom_in_checksum(ip, IPCOM_IP_HEADER_LENGTH); return -1; } #endif /* IPCOM_USE_FORWARDER_IPSEC */ *(Ip_u32 *)(msg->packet - 2) = ev->mac_if.dst_mac[0]; *(Ip_u32 *)(msg->packet + 2) = ev->mac_if.dst_mac[1]; *(Ip_u32 *)(msg->packet + 6) = ipcom_fw.fw_port[ev->mac_if.ix[0]].src_type[0]; *(Ip_u32 *)(msg->packet + 10) = ipcom_fw.fw_port[ev->mac_if.ix[0]].src_type[1]; *(Ip_u16 *)(msg->packet + 12) = ip_htons(IP_VLAN); *(Ip_u16 *)(msg->packet + 14) = ev->ipvlan.vlan_id; #ifdef IPCOM_USE_FORWARDER_IPSEC *(Ip_u16 *)(msg->packet + 16) = ip_htons(IP_IPv4); #endif return ev->mac_if.ix[0]; #endif /* IPCOM_USE_INET */ } else if (IP_LIKELY(msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN)) { #ifdef IPCOM_USE_INET6 /* IPv6 table is also used for VLAN entries, both IPv4 and IPv6 */ ev = (fw_cache_entry_vlan_t *)&ipcom_fw.fw_cache_tbl_v6[msg->fw_key]; vid = *(Ip_u16 *)(msg->packet + LL_ETH_HDR_SZ); /* UP/CFI/VID word */ if (IP_UNLIKELY(ev->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) { #if IPCOM_FORWARDER_CACHE_WAYS > 1 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 2 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 3 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 4 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 5 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 6 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #if IPCOM_FORWARDER_CACHE_WAYS > 7 if (IP_UNLIKELY((++ev)->ipvlan.type != IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 24) != ev->ipvlan.a.addr_v6[0]) || (*(Ip_u64 *)(msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD + 32) != ev->ipvlan.a.addr_v6[1]) || vid != ev->ipvlan.vlan_id || ev->ipvlan.rci != *ipcom_fw.rt_cache_id)) #endif #endif #endif #endif #endif #endif #endif goto nomatch; } SET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD), GET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD)) - 1); #ifdef IPCOM_USE_FORWARDER_IPSEC if (ipcom_forwarder_ipsec_encrypt_packet(msg, &ev->mac_if, &ev->ipsec, &fw_ipsec_replay, LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD) <= 0) { /* Restore IPv6 header */ SET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD), GET_V6_HOPL((msg->packet + LL_ETH_HDR_SZ + LL_ETH_VLAN_ADD)) + 1); return -1; } #endif /* IPCOM_USE_FORWARDER_IPSEC */ *(Ip_u32 *)(msg->packet - 2) = ev->mac_if.dst_mac[0]; *(Ip_u32 *)(msg->packet + 2) = ev->mac_if.dst_mac[1]; *(Ip_u32 *)(msg->packet + 6) = ipcom_fw.fw_port[ev->mac_if.ix[0]].src_type[0]; *(Ip_u32 *)(msg->packet + 10) = ipcom_fw.fw_port[ev->mac_if.ix[0]].src_type[1]; *(Ip_u16 *)(msg->packet + 12) = ip_htons(IP_VLAN); *(Ip_u16 *)(msg->packet + 14) = ev->ipvlan.vlan_id; #ifdef IPCOM_USE_FORWARDER_IPSEC *(Ip_u16 *)(msg->packet + 16) = ip_htons(IP_IPv6); #endif return ev->mac_if.ix[0]; #endif /* IPCOM_USE_INET6 */ } #endif /* IPCOM_USE_FORWARDER_VLAN */ nomatch: #ifdef IPCOM_USE_FORWARDER_IPSEC if (msg->ipsec_dec == 0xff) { int ret, offset = LL_ETH_HDR_SZ; if (msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV4_VLAN || msg->tbl[0] == IPCOM_FORWARDER_PACKET_TYPE_IPV6_VLAN) { offset += LL_ETH_VLAN_ADD; } #ifdef FW_IPSEC_DEBUG ipcom_printf("FW_IPSEC :: re-encrypt packet! offset=%d msg->fw_key: %x msg->len=%d(%d) msg->packet=%p(%p)\n", offset, msg->fw_key, msg->len, ipcom_forwarder_ipnet_msg_len(msg), msg->packet, ipcom_forwarder_ipnet_msg_packet(msg)); #endif /* Restore buffer pointer and length */ msg->len = ipcom_forwarder_ipnet_msg_len(msg); msg->packet = ipcom_forwarder_ipnet_msg_packet(msg); /* Re-encrypt packet */ ret = ipcom_forwarder_ipsec_recrypt(&msg->packet[offset], msg->len - offset); if (ret < 0) { #ifdef FW_IPSEC_DEBUG ipcom_printf("FW_IPSEC :: re-encrypt packet failed!!!\n"); #endif ipsec_recrypt_fail++; msg->tbl[0] = IPCOM_FORWARDER_PACKET_IPSEC_DROP_PKT; /* Drop packet */ return -1; } ipsec_recrypt_ok++; } #endif /* IPCOM_USE_FORWARDER_IPSEC */ return -1; }
/* *=========================================================================== * ipnet_udp_input *=========================================================================== * Description: Input handler for packet to UDP sockets. This function will * NOT free the packet if the operation fails. * Parameters: pkt - The received packet, must be freed by the called if * this function fails. * is_multicast - Set to IP_TRUE if the packet was sent to a * multicast address. * proto - The protocol number. * src_addr - The address (Ipv4 or IPv6) of the sender. * dst_addr - The address (Ipv4 or IPv6) of the receiver (this system). * socklookup - A pointer to a function that can return the socket * that is associated with this packet. * nat_t - NAT traversal; if used. * Returns: 0 >= number of matching sockets, <0 = error code * */ IP_GLOBAL int ipnet_udp_input(Ipcom_pkt *pkt, Ip_bool is_multicast, IP_CONST void* src_addr, IP_CONST void* dst_addr, Ipnet_sock_lookup_f socklookup, int *nat_t) { Ipnet_pkt_udp *udp_hdr; int retval; int ulen_h; Ipnet_socket *sock; Ip_u16 src_port; Ip_u16 dst_port; Ip_bool pkt_no_rx_cache; IPCOM_WV_MARKER_1 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_VERBOSE, 1, 3, IPCOM_WV_NETDEVENT_START, ipnet_udp_input, IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4); IPNET_STATS(udp_input++); IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_UDP_INPUT); if (IP_UNLIKELY(pkt->end - pkt->start < IPNET_UDP_HDR_SIZE)) { IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING, 1, 4, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV, ipnet_udp_input, IPCOM_WV_NETD_BADHLEN, IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4); IPNET_STATS(udp_input_hdr_trunc++); IPCOM_MIB2(udpInErrors++); return -IP_ERRNO_EINVAL; } udp_hdr = (Ipnet_pkt_udp*) &pkt->data[pkt->start]; ulen_h = ip_ntohs(udp_hdr->ulen); src_port = ip_ntohs(udp_hdr->sport); dst_port = ip_ntohs(udp_hdr->dport); if (IP_UNLIKELY(pkt->end - pkt->start < ulen_h)) { IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING, 1, 5, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV, ipnet_udp_input, IPCOM_WV_NETD_BADLEN, IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4); IPNET_STATS(udp_input_hdr_trunc++); IPCOM_MIB2(udpInErrors++); return -IP_ERRNO_EINVAL; } pkt->end = pkt->start + ulen_h; if (udp_hdr->sum != 0 && IP_BIT_ISFALSE(pkt->flags, IPCOM_PKT_FLAG_LOOPED_BACK)) { Ip_u16 chksum; /* Only check packets that was not created locally */ #ifdef IPCOM_USE_HW_CHECKSUM_RX if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_HW_CHECKSUM)) chksum = 0; else if (IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_TL_CHECKSUM)) chksum = ipcom_in_checksum_finish(pkt->chk); else #endif /* IPCOM_USE_HW_CHECKSUM_RX */ { pkt->chk += ipcom_in_checksum_update(&pkt->data[pkt->start], (Ip_size_t) ulen_h); chksum = ipcom_in_checksum_finish(pkt->chk); } if (IP_UNLIKELY(chksum != 0)) { /* Wrong checksum */ IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING, 1, 6, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV, ipnet_udp_input, IPCOM_WV_NETD_BADSUM, IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4); IPNET_STATS(udp_input_badchksum++); IPCOM_MIB2(udpInErrors++); return -IP_ERRNO_EINVAL; } } /* Move the start to beginning of application data */ pkt->start += IPNET_UDP_HDR_SIZE; if (is_multicast) { IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_INFO, 1, 7, IPCOM_WV_NETDEVENT_INFO, IPCOM_WV_NETD_RECV, ipnet_udp_input, IPCOM_WV_NETD_INFO_RECEIVE, IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4); IPNET_STATS(udp_input_multicast++); retval = ipnet_raw_input(pkt, IP_FALSE, IP_IPPROTO_UDP, src_addr, src_port, dst_addr, dst_port, socklookup); if (retval >= 0) { /* The packet must be freed unlesss an error occured */ ipcom_pkt_free(pkt); IPCOM_MIB2(udpInDatagrams++); IPCOM_MIB2_U64_INC(udpHCInDatagrams); } else { IPCOM_MIB2(udpInErrors++); } return retval; } sock = socklookup(pkt->vr_index, IP_IPPROTO_UDP, dst_addr, dst_port, src_addr, src_port); if (sock == IP_NULL) /* No matching socket, try the wildcard group */ sock = socklookup(IPCOM_VR_ANY, IP_IPPROTO_UDP, dst_addr, dst_port, src_addr, src_port); if (sock != IP_NULL) { Ipcom_socket_eventcb event_cb = sock->ipcom.event_cb; /* Verify NAT traversal */ if (IP_UNLIKELY(ipnet_udp_encapsulation(sock, pkt, nat_t))) { ipcom_pkt_set_info(pkt, IPNET_PKT_INFO_ENCAP_UDP, sizeof(*udp_hdr), udp_hdr); pkt->start -= IPNET_UDP_HDR_SIZE; return 0; } IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_INFO, 1, 8, IPCOM_WV_NETDEVENT_INFO, IPCOM_WV_NETD_RECV, ipnet_udp_input, IPCOM_WV_NETD_INFO_RECEIVE, IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4); IPNET_STATS(udp_input_sock_match++); pkt->fd = sock->ipcom.fd; pkt_no_rx_cache = IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_NO_RX_CACHE); retval = ipnet_queue_received_packet(pkt, sock); if (retval < 0) { IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING, 1, 9, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV, ipnet_udp_input, IPCOM_WV_NETD_INFO_QUEUE_FULL, IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4); IPNET_STATS(udp_input_queue_pkt_err++); IPCOM_MIB2(udpInErrors++); return retval; } IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_INFO, 1, 10, IPCOM_WV_NETDEVENT_INFO, IPCOM_WV_NETD_RECV, ipnet_udp_input, IPCOM_WV_NETD_INFO_RECEIVE, IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4); IPNET_STATS(udp_input_queue_pkt_ok++); if (event_cb != IP_NULL) event_cb(&sock->ipcom, pkt, IP_SOEVENT_CB_INPKT); IPCOM_MIB2(udpInDatagrams++); IPCOM_MIB2_U64_INC(udpHCInDatagrams); if (IP_BIT_ISFALSE(sock->flags, IPNET_SOCKET_FLAG_RX_CACHED) && !pkt_no_rx_cache) ipnet_sock_add_to_rx_cache(sock, src_addr, src_port, dst_addr, dst_port, ipnet_udp_fast_deliver_data); return 1; } else { IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING, 1, 13, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV, ipnet_udp_input, IPCOM_WV_NETD_NOPORT, IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4); IPNET_STATS(udp_input_sock_nomatch++); IPCOM_MIB2(udpNoPorts++); } IPCOM_WV_EVENT_2 (IPCOM_WV_NETD_IP4_DATAPATH_EVENT, IPCOM_WV_NETD_WARNING, 1, 14, IPCOM_WV_NETDEVENT_WARNING, IPCOM_WV_NETD_RECV, ipnet_udp_input, IPCOM_WV_NETD_NOPORT, IPCOM_WV_IPNET_UDP_MODULE, IPCOM_WV_NETD_UDP4); IPNET_STATS(udp_input_econnrefused++); return -IP_ERRNO_ECONNREFUSED; }
/* *=========================================================================== * ipnet_udp_nat_traversal *=========================================================================== * Description: Check if this packet should be processed by the NAT * traversal functionality. * Parameters: sock - The socket * pkt - The packet in question. * Returns: IP_FALSE; give to UDP socket. * IP_TRUE; Do NAT_T processing. * */ IP_STATIC Ip_bool ipnet_udp_encapsulation(Ipnet_socket *sock, Ipcom_pkt *pkt, int *nat_t) { /* Did we have any NAT-T's? */ if (IP_UNLIKELY(sock->udp_encapsulation != IP_UDP_NAT_T_DISABLED)) { #if defined(IPNET_USE_TUNNEL) && defined(IPCOM_USE_INET) /* NAT-T processing? */ if (sock->ipcom.domain == IP_AF_INET && sock->udp_encapsulation == IP_UDP_NAT_T_RFC3519) { Ip_u8 *data; Ip_u8 nproto; /* Sanity; There MUST be atleast 4 bytes available */ if ((pkt->end - pkt->start) < 4) { /* Give to UDP socket */ return IP_FALSE; } /* Grab the start */ data = (Ip_u8 *) &pkt->data[pkt->start]; /* NAT-T according to RFC3519 * IP HEADER <tunnel endpoint - tunnel endpoint> * UDP HEADER * 4 byte NAT-T header; * TYPE(1 byte) := 4 * NH(1 byte) := 4, 47 or 55 * RESERVED(2 bytes) := 0 */ /* Must be 4 */ if (data[0] != 4) { /* Give to UDP socket */ return IP_FALSE; } /* Verify that the tunnel protocol is correct */ nproto = data[1]; if (nproto == IP_IPPROTO_IPIP || nproto == IP_IPPROTO_GRE || nproto == IP_IPPROTO_MOBILE) { /* Correct UDP RFC3519 encap; do process */ *nat_t = IP_UDP_NAT_T_RFC3519; return IP_TRUE; } /* Feed to socket */ return IP_FALSE; } #else (void) pkt; (void) nat_t; #endif /* IPNET_USE_TUNNEL */ #if defined(IPIPSEC2) && defined(IPCOM_USE_INET) if (sock->ipcom.domain == IP_AF_INET && sock->udp_encapsulation == IP_UDP_NAT_T_RFC3948) { if ((pkt->end - pkt->start == 1) && (pkt->data[pkt->start] == 0xff)) { /* NAT-keepalive Packet; Give to socket */ return IP_FALSE; } if ((pkt->end - pkt->start > 4) && (IP_GET_32ON16(&pkt->data[pkt->start]) == 0)) { /* Non-ESP marker set; do give to socket - this is an IKE packet */ return IP_FALSE; } /* Deal with the NAT-T for IKE; IPSEC */ *nat_t = IP_UDP_NAT_T_RFC3948; /* Tell the world we need further processing */ return IP_TRUE; } #endif #ifdef IPNET_USE_TUNNEL /* NAT-T processing? */ if (sock->udp_encapsulation == IP_UDP_NAT_T_DSMIPV6) { /* Correct UDP RFC3519 encap; do process */ *nat_t = IP_UDP_NAT_T_DSMIPV6; return IP_TRUE; } #endif } return IP_FALSE; }