📄 ip.c
字号:
/************************************************************************
*
* FUNCTION
*
* IP_Option_Copy
*
* DESCRIPTION
*
*
*
* INPUTS
*
* dip destination IP packet header
* sip source IP packet header
*
* OUTPUTS
*
* INT The length of the option data copied.
*
*************************************************************************/
INT IP_Option_Copy (IPLAYER *dip, IPLAYER *sip)
{
UINT8 *src, *dest;
INT cnt, opt, optlen;
/* Point to the first byte of option data in each of the IP packets. */
src = (UINT8 *) (sip + 1);
dest = (UINT8 *) (dip + 1);
cnt = ((GET8(sip, IP_VERSIONANDHDRLEN_OFFSET) & 0x0f) << 2) - sizeof(IPLAYER);
for (; cnt > 0; cnt -= optlen, src += optlen)
{
opt = src[0];
/* Stop when the EOL option is encountered. */
if (opt == IP_OPT_EOL)
break;
/* Copy NOPs to preserve alignment constraints. */
if (opt == IP_OPT_NOP)
{
*dest++ = IP_OPT_NOP;
optlen = 1;
continue;
}
else
optlen = src[IP_OPT_OLEN];
/* Truncate an option length that is too large. This should not occur. */
if (optlen > cnt)
optlen = cnt;
/* If the copied bit is set then copy the option. */
if (IP_OPT_COPIED(opt))
{
memcpy(dest, src, (unsigned int)optlen);
dest += optlen;
}
}
/* Pad the option list, if necessary, out to a 4-byte boundary. */
for (optlen = (INT)(dest - (UINT8 *)(dip + 1)); optlen & 0x3; optlen++)
*dest++ = IP_OPT_EOL;
return (optlen);
} /* IP_Option_Copy */
#endif /* INCLUDE_IP_FRAGMENT */
/***********************************************************************
*
* FUNCTION
*
* IP_Broadcast_Addr
*
* DESCRIPTION
*
* This function checks an IP address to see if it is a broadcast
* address.
*
* INPUTS
*
* dest The IP address to be checked.
* int_face Pointer to the interface the IP address is being
* used on.
*
* OUTPUTS
*
* 1 This is a broadcast address.
* 0 This is not a broadcast address.
*
*************************************************************************/
INT IP_Broadcast_Addr(UINT32 dest, DV_DEVICE_ENTRY *int_face)
{
if ( (dest == IP_ADDR_ANY) || (dest == IP_ADDR_BROADCAST) )
return 1;
if ( (int_face->dev_flags & DV_BROADCAST) == 0)
return 0;
if ( (int_face->dev_addr.dev_net == dest) ||
(int_face->dev_addr.dev_net_brdcast == dest) )
return 1;
return 0;
} /* IP_Broadcast_Addr */
/* Check to see if the route is still valid. */
/***********************************************************************
*
* FUNCTION
*
* IP_Find_Route
*
* DESCRIPTION
*
* This function checks to see if a route is still valid. If the
* route is not valid or if a route has never been allocated. A new
* route is found.
*
* INPUTS
*
* ro
*
* OUTPUTS
*
* None.
*
*************************************************************************/
VOID IP_Find_Route(RTAB_ROUTE *ro)
{
if ( ro->rt_route && ro->rt_route->rt_device &&
(ro->rt_route->rt_flags & RT_UP) )
return;
ro->rt_route = RTAB_Find_Route(&ro->rt_ip_dest);
} /* IP_Find_Route */
#if INCLUDE_IP_FORWARDING
/***********************************************************************
*
* FUNCTION
*
* IP_Forward
*
* DESCRIPTION
*
* This function checks attempts to forward an IP packet out of
* one of the network interfaces.
*
* INPUTS
*
* buf_ptr A buffer containing the datagram to forward.
*
* OUTPUTS
*
* NU_SUCCESS
* NU_INVALID_ADDRESS
* NU_HOST_UNREACHABLE
* -1 Packet not forwarded.
*
*************************************************************************/
STATUS IP_Forward(NET_BUFFER *buf_ptr)
{
SCK_SOCKADDR_IP *sin;
ROUTE_NODE *rt;
DEV_IF_ADDRESS *d_addr;
UINT32 src, dest;
INT type, code;
STATUS stat;
IPLAYER *ip_pkt;
INT hlen;
/* Initialize local variables. */
dest = 0;
ip_pkt = (IPLAYER *)buf_ptr->data_ptr;
if ( (buf_ptr->mem_flags & NET_BCAST) ||
IP_Canforward(GET32(ip_pkt, IP_DEST_OFFSET)) != NU_SUCCESS)
{
/* Deallocate the buffer. */
MEM_One_Buffer_Chain_Free (buf_ptr,buf_ptr->mem_dlist);
/* Increment the number of IP packets received with the wrong IP addr.*/
SNMP_ipInAddrErrors_Inc;
return (NU_INVALID_ADDRESS);
}
/* Check the time to live field. */
if (GET8(ip_pkt, IP_TTL_OFFSET) <= 1)
{
ICMP_Send_Error(buf_ptr, ICMP_TIMXCEED, ICMP_TIMXCEED_TTL, 0,
buf_ptr->mem_buf_device);
/* Deallocate the buffer. */
MEM_One_Buffer_Chain_Free (buf_ptr,buf_ptr->mem_dlist);
return -1;
}
/* Decrement the time to live. */
PUT8(ip_pkt, IP_TTL_OFFSET, (UINT8)(GET8(ip_pkt, IP_TTL_OFFSET) - 1));
/* Increment the number of packets that we attempted to find a route
and forward. */
SNMP_ipForwDatagrams_Inc;
sin = (SCK_SOCKADDR_IP *) &IP_Forward_Rt.rt_ip_dest;
/* Check to see if the cached route is still valid. */
if ( ((rt = IP_Forward_Rt.rt_route) == 0) ||
(GET32(ip_pkt, IP_DEST_OFFSET) != sin->sck_addr) )
{
/* We can not used the cached route. If there is one then free it. */
if (IP_Forward_Rt.rt_route)
{
RTAB_Free(IP_Forward_Rt.rt_route);
IP_Forward_Rt.rt_route = NU_NULL;
}
sin->sck_family = SK_FAM_IP;
sin->sck_len = sizeof (*sin);
sin->sck_addr = GET32(ip_pkt, IP_DEST_OFFSET);
IP_Find_Route(&IP_Forward_Rt);
/* Was a route found. */
if (IP_Forward_Rt.rt_route == 0)
{
/* Send ICMP host unreachable message. */
ICMP_Send_Error(buf_ptr, ICMP_UNREACH, ICMP_UNREACH_HOST, 0,
buf_ptr->mem_buf_device);
/* Deallocate the buffer. */
MEM_One_Buffer_Chain_Free (buf_ptr,buf_ptr->mem_dlist);
/* Increment the number of packets that could not be delivered
because a route could not be found. */
SNMP_ipOutNoRoutes_Inc;
return (NU_HOST_UNREACHABLE);
}
rt = IP_Forward_Rt.rt_route;
}
if ( (rt->rt_device == buf_ptr->mem_buf_device) &&
((rt->rt_flags & (RT_DYNAMIC | RT_MODIFIED)) == 00) &&
(*(UINT32 *)rt->rt_rip2->ip_addr != 0) && IP_Sendredirects )
{
src = GET32(ip_pkt, IP_SRC_OFFSET);
d_addr = &rt->rt_device->dev_addr;
if ( (src & d_addr->dev_netmask) == d_addr->dev_net)
{
if (rt->rt_flags & RT_GATEWAY)
dest = *(UINT32 *)rt->rt_gateway.sck_addr;
else
dest = GET32(ip_pkt, IP_DEST_OFFSET);
type = ICMP_REDIRECT;
code = ICMP_REDIRECT_HOST;
/* Send ICMP host unreachable message. */
ICMP_Send_Error(buf_ptr, type, code, dest, buf_ptr->mem_buf_device);
}
}
/* IP send expects the data pointer to point at the IP data not at the IP
header. So move the pointer forward. */
hlen = (GET8(ip_pkt, IP_VERSIONANDHDRLEN_OFFSET) & 0x0f) << 2;
buf_ptr->data_ptr += hlen;
buf_ptr->data_len -= hlen;
/* Forward the packet. Because this is a forward many of the parameters are
not required. Specifically the length, the ttl, the protocol, and tos.
NU_NULL is used for all of those parameters that will not be needed.
*/
stat = IP_Send( buf_ptr, &IP_Forward_Rt, GET32(ip_pkt, IP_DEST_OFFSET),
GET32(ip_pkt, IP_SRC_OFFSET), IP_FORWARDING | IP_ALLOWBROADCAST,
NU_NULL, NU_NULL, NU_NULL, NU_NULL);
if (stat != NU_SUCCESS)
{
if (stat == NU_HOST_UNREACHABLE)
{
type = ICMP_UNREACH;
code = ICMP_UNREACH_HOST;
/* Send ICMP host unreachable message. */
ICMP_Send_Error(buf_ptr, type, code, dest, buf_ptr->mem_buf_device);
}
MEM_One_Buffer_Chain_Free (buf_ptr, buf_ptr->mem_dlist);
/* Increment the number of IP packets received with the wrong IP addr.*/
SNMP_ipInAddrErrors_Inc;
}
return (stat);
} /* IP_Forward */
#endif
/************************************************************************
*
* FUNCTION
*
* IP_Canforward
*
* DESCRIPTION
*
* This function decides if an attempt should be made to forward
* an IP datagram.
*
* INPUTS
*
* dest
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -