📄 ip.c
字号:
/* If this packet is small enough send it.*/
if (GET16(ip_dgram, IP_TLEN_OFFSET) <= int_face->dev_mtu)
{
/* Compute the IP checksum. Note that the length expected by TLS_IP_Check is
the length of the header in 16 bit half-words. */
PUT16(ip_dgram, IP_CHECK_OFFSET, 0);
PUT16(ip_dgram, IP_CHECK_OFFSET, TLS_IP_Check ((UINT16 *)ip_dgram, (UINT16)(hlen >> 1)) );
/* Set the packet type that is in the buffer. */
buf_ptr->mem_flags |= NET_IP;
/* Send the packet. */
status = (*(int_face->dev_output)) (buf_ptr, int_face, dest, ro);
}
else /* This packet must be fragmented. */
{
#if INCLUDE_IP_FRAGMENT
/* If the don't fragment bit is set return an error. */
if (GET16(ip_dgram, IP_FRAGS_OFFSET) & IP_DF)
{
/* Increment the number of IP packets that could not be
fragmented. In this case becuase the don't fragment
bit is set. */
SNMP_ipFragFails_Inc;
return(NU_MSGSIZE);
}
status = IP_Fragment (buf_ptr, ip_dgram, int_face, dest, ro);
#else
return(NU_MSGSIZE);
#endif
}
if ( (ro == &iproute) && ((flags & IP_ROUTETOIF) == 0) && ro->rt_route )
RTAB_Free(ro->rt_route);
return (status);
} /* IP_Send */
#if INCLUDE_IP_FRAGMENT
/***********************************************************************
*
* FUNCTION
*
* IP_Fragment
*
* DESCRIPTION
*
* Fragment an IP packet.
*
* INPUTS
*
* buf_ptr
* ip
* int_face
* dest
* ro
*
* OUTPUTS
*
* NU_SUCCESS
* NU_MSGSIZE
*
*************************************************************************/
STATUS IP_Fragment (NET_BUFFER *buf_ptr, IPLAYER *ip, DV_DEVICE_ENTRY *int_face,
SCK_SOCKADDR_IP *dest, RTAB_ROUTE *ro)
{
INT32 len, hlen, tlen, f_hlen, first_len, data_len, total_data_len;
INT32 off;
NET_BUFFER *work_buf;
NET_BUFFER *f_buf = buf_ptr;
NET_BUFFER **next = &buf_ptr->next;
STATUS err = NU_SUCCESS;
IPLAYER *f_ip;
INT32 aloc_len;
INT at_least_one_succeeded = 0;
/* Make sure this buffer is not pointing to any list. It should
not be at this point. */
buf_ptr->next = NU_NULL;
hlen = (GET8(ip, IP_VERSIONANDHDRLEN_OFFSET) & 0x0f) << 2;
/* len is the number of data bytes in each fragment. Computed as the mtu of
the interface less the size of the header and rounded down to an 8-byte
boundary by clearing the low-order 3 bits (& ~7).
*/
len = (int_face->dev_mtu - hlen) & ~7;
first_len = len;
/* Each fragment must be able to hold at least 8 bytes. */
if (len < 8)
return NU_MSGSIZE;
tlen = GET16(ip, IP_TLEN_OFFSET);
buf_ptr = f_buf;
f_hlen = sizeof(IPLAYER);
aloc_len = len;
/* Create the fragments. */
for (off = hlen + len; off < tlen; off += len)
{
if (off + len >= GET16(ip, IP_TLEN_OFFSET))
/* Shorten the length if this is the last fragment. */
aloc_len = GET16(ip, IP_TLEN_OFFSET) - off;
/* Allocate a buffer chain to build the fragment in. */
f_buf = MEM_Buffer_Chain_Dequeue(&MEM_Buffer_Freelist, aloc_len +
hlen + int_face->dev_hdrlen);
if (f_buf == NU_NULL)
{
err = NU_NOBUFS;
/* Increment the number of IP packets that could not be
fragmented. In this case becuase of no buffers. */
SNMP_ipFragFails_Inc;
break;
}
/* Initialize mem_dlist for deallocation */
f_buf->mem_dlist = &MEM_Buffer_Freelist;
/* Point to the location where the IP header will begin. */
f_buf->data_ptr = f_buf->mem_parent_packet + int_face->dev_hdrlen;
/* Overlay the IP header so we can access the individual fields. */
f_ip = (IPLAYER *)f_buf->data_ptr;
/* Copy the IP header over to the new packet. */
IP_HEADER_COPY(f_ip, ip);
/* If there are options in the original, packet copy them. */
if (hlen > sizeof(IPLAYER))
{
f_hlen = IP_Option_Copy(f_ip, ip) + sizeof(IPLAYER);
PUT8(f_ip, IP_VERSIONANDHDRLEN_OFFSET,
(UINT8)((f_hlen >> 2) | (IP_VERSION << 4)) );
}
/* Set the offset field for the fragment. */
PUT16(f_ip, IP_FRAGS_OFFSET,
(INT16)(((off - hlen) >> 3) + (GET16(ip, IP_FRAGS_OFFSET) & ~IP_MF)) );
/* If MF is set in the original packet then it should be set in all
fragments. */
if (GET16(ip, IP_FRAGS_OFFSET) & IP_MF)
PUT16(f_ip, IP_FRAGS_OFFSET, (INT16)(GET16(f_ip, IP_FRAGS_OFFSET) | IP_MF) );
/* Is this the last fragment. MF is set for every fragment except the
last one. Unless MF was set in the original packet. In that case MF
should have already been set above. */
if (off + len >= GET16(ip, IP_TLEN_OFFSET))
/* Shorten the length if this is the last fragment. */
len = GET16(ip, IP_TLEN_OFFSET) - off;
else
/* This is not the last fragment. Set MF. */
PUT16(f_ip, IP_FRAGS_OFFSET, (INT16)(GET16(f_ip,
IP_FRAGS_OFFSET) | IP_MF) );
/* Set the new length. */
PUT16(f_ip, IP_TLEN_OFFSET, (INT16)(len + f_hlen));
/* The IP header is the only data present. */
f_buf->data_len = f_hlen;
/* We will also add the device header length in here. This
is only done so that the Chain_Copy routine below will
compute the correct size for the buffer area available.
It will be removed after the copy. */
f_buf->data_len += int_face->dev_hdrlen;
/* Move the data point back to the start of the device header.
This is also being done for the Chain_Copy routine. It will
offset by the data_len and skip over these headers when
doing the copy. */
f_buf->data_ptr -= int_face->dev_hdrlen;
/* Copy data from the original packet into this fragment. */
MEM_Chain_Copy(f_buf, buf_ptr, off, len);
/* Now remove the device header length that was added
above. */
f_buf->data_len -= int_face->dev_hdrlen;
/* Put the data pointer back as well. */
f_buf->data_ptr += int_face->dev_hdrlen;
/* Set the length of all data in this buffer chain. */
f_buf->mem_total_data_len = len + f_hlen;
/* Clear the device pointer. */
f_buf->mem_buf_device = NU_NULL;
/* Compute the IP header checksum. */
PUT16(f_ip, IP_CHECK_OFFSET, 0);
PUT16(f_ip, IP_CHECK_OFFSET, TLS_IP_Check((UINT16 *)f_ip,
(UINT16)(f_hlen >> 1)) );
/* Link this fragment into the list of fragments. */
*next = f_buf;
next = &f_buf->next;
/* Increment the number of fragments that have been created. */
SNMP_ipFragCreates_Inc;
}
/* If the above loop was successful then the next step is to trim
all of the data in the original buffer chain that has been relocated
to the chain of fragments. */
if (err == NU_SUCCESS)
{
#if (INCLUDE_SNMP == NU_TRUE)
/* Increment the number of packets that have been fragmented. */
SNMP_ipFragOKs_Inc;
#endif
/* Convert the original packet into the first fragment */
f_buf = buf_ptr;
/* Update the first fragment by trimming what's been copied out. */
MEM_Trim(f_buf, hlen + first_len - tlen);
/* Determine the total data length of the first fragment */
total_data_len = f_buf->mem_total_data_len;
data_len = 0;
/* Terminate the first fragment */
for(work_buf = f_buf; data_len < total_data_len; work_buf = work_buf->next_buffer)
{
data_len = work_buf->data_len + data_len;
if(data_len == total_data_len)
{
/* Deallocate the buffers that the first fragment does not need */
MEM_One_Buffer_Chain_Free (work_buf->next_buffer, &MEM_Buffer_Freelist);
work_buf->next_buffer = NU_NULL;
}
}
/* Update the header in the first fragment (the original packet). */
PUT16(ip, IP_TLEN_OFFSET, (INT16)f_buf->mem_total_data_len);
PUT16(ip, IP_FRAGS_OFFSET, (INT16)(GET16(ip, IP_FRAGS_OFFSET) | IP_MF));
PUT16(ip, IP_CHECK_OFFSET, 0);
PUT16(ip, IP_CHECK_OFFSET, TLS_IP_Check((UINT16 *)ip, (UINT16)(f_hlen >> 1)) );
}
else
{
/* There were not enough buffers to break the original buffer chain up
into fragments. An error will be returned and the upper layer
software will free the original buffer chain. To keep the buffer chain
from being freed twice (once below and once in the upper layer
software) move buf_ptr forward, and separate it from the fragments
that were created. Doing this will cause the for loop below to only
free those buffers that were allocated within this function. The
upper layer software will free the original buffer chain. */
work_buf = buf_ptr;
buf_ptr = buf_ptr->next;
work_buf->next = NU_NULL;
}
/* Save a pointer to the first buffer in the chain. It might be needed below. */
work_buf = buf_ptr;
/* Send each fragment */
for (f_buf = buf_ptr; f_buf; f_buf = buf_ptr)
{
buf_ptr = f_buf->next;
f_buf->next = NU_NULL;
/* If the first packet can not be transmitted successfully, then abort
and free the rest. */
if(err == NU_SUCCESS)
{
/* Set the packet type that is in the buffer. */
f_buf->mem_flags |= NET_IP;
if ((err = (*(int_face->dev_output)) (f_buf, int_face, dest, ro))
!= NU_SUCCESS )
{
/* If the error occured on the first buffer don't free it. It will
be freed by the upper layer protocol. */
if (f_buf != work_buf)
{
MEM_One_Buffer_Chain_Free (f_buf, &MEM_Buffer_Freelist);
}
}
else
{
/* If at least one fragment was sent successfully we will want
to return success below. This is so the upper layer
protocols will not try to free the fragment that was sent
successfully. In reality this should never occur. It would
require a device going down or a route being timed out from
under us. Both of which should be impossibile as we have
the semaphore. */
at_least_one_succeeded = 1;
}
}
else
MEM_One_Buffer_Chain_Free (f_buf, &MEM_Buffer_Freelist);
}
if (at_least_one_succeeded)
return (NU_SUCCESS);
else
return (err);
} /* IP_Fragment */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -