📄 ip_read.c
字号:
/*
ip_read.c
*/
#include "inet.h"
#include "buf.h"
#include "clock.h"
#include "type.h"
#include "assert.h"
#include "icmp_lib.h"
#include "io.h"
#include "ip.h"
#include "ip_int.h"
INIT_PANIC();
FORWARD ip_ass_t *find_ass_ent ARGS(( ip_port_t *port, U16_t id,
int proto, ipaddr_t src, ipaddr_t dst ));
FORWARD acc_t *merge_frags ARGS(( acc_t *first, acc_t *second ));
FORWARD int net_broad ARGS(( ipaddr_t hoaddr, ipaddr_t netaddr,
ipaddr_t netmask ));
FORWARD int ip_frag_chk ARGS(( acc_t *pack ));
FORWARD acc_t *reassemble ARGS(( ip_port_t *port, acc_t *pack,
ip_hdr_t *ip_hdr ));
FORWARD int ok_for_port ARGS(( ip_port_t *port, ipaddr_t ipaddr,
int *ref_broad_all ));
PUBLIC int ip_read (fd, count)
int fd;
size_t count;
{
ip_fd_t *ip_fd;
ip_fd= &ip_fd_table[fd];
if (!(ip_fd->if_flags & IFF_OPTSET))
return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, EBADMODE,
(acc_t *)0, FALSE);
ip_fd->if_rd_count= count;
if (ip_fd->if_rd_buf)
{
if (get_time() <= ip_fd->if_exp_tim)
return ip_packet2user (ip_fd);
where();
bf_afree(ip_fd->if_rd_buf);
where();
ip_fd->if_rd_buf= 0;
}
ip_fd->if_flags |= IFF_READ_IP;
#if DEBUG & 256
{ where(); printf("ip_fd_table[%d].if_flags= 0x%x\n",
ip_fd-ip_fd_table, ip_fd->if_flags); }
#endif
return NW_SUSPEND;
}
PRIVATE acc_t *reassemble (port, pack, pack_hdr)
ip_port_t *port;
acc_t *pack;
ip_hdr_t *pack_hdr;
{
ip_ass_t *ass_ent;
size_t pack_hdr_len, pack_data_len, pack_offset, tmp_offset;
u16_t pack_flags_fragoff;
acc_t *prev_head, *new_head, *new_tail, *tmp_acc;
acc_t swap_acc;
ip_hdr_t *tmp_hdr;
time_t first_time;
#if DEBUG & 256
{ where(); printf("in reassemble()\n"); }
#endif
ass_ent= find_ass_ent (port, pack_hdr->ih_id,
pack_hdr->ih_proto, pack_hdr->ih_src, pack_hdr->ih_dst);
#if DEBUG & 256
{ where(); ip_print_frags(ass_ent->ia_frags); printf("\n"); }
#endif
pack_flags_fragoff= ntohs(pack_hdr->ih_flags_fragoff);
pack_hdr_len= (pack_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
pack_data_len= ntohs(pack_hdr->ih_length)-pack_hdr_len;
pack_offset= (pack_flags_fragoff & IH_FRAGOFF_MASK)*8;
pack->acc_ext_link= NULL;
#if DEBUG & 256
{ where(); ip_print_frags(pack); printf("\n"); }
#endif
new_head= 0;
for (prev_head= ass_ent->ia_frags, ass_ent->ia_frags= NULL; prev_head;
prev_head= prev_head->acc_ext_link)
{
tmp_hdr= (ip_hdr_t *)ptr2acc_data(prev_head);
tmp_offset= (ntohs(tmp_hdr->ih_flags_fragoff) &
IH_FRAGOFF_MASK)*8;
#if DEBUG & 256
{ where(); printf("tmp_offset= %d, pack_offset= %d\n", tmp_offset,
pack_offset); }
#endif
if (tmp_offset >= pack_offset)
break;
if (new_head)
new_tail->acc_ext_link= prev_head;
else
new_head= prev_head;
new_tail= prev_head;
}
if (prev_head)
{
where();
pack= merge_frags(pack, prev_head);
}
if (new_head)
{
pack= merge_frags(new_tail, pack);
if (pack != new_tail)
{
swap_acc= *pack;
*pack= *new_tail;
*new_tail= swap_acc;
}
}
else
{
new_head= pack;
new_tail= pack;
}
ass_ent->ia_frags= new_head;
#if DEBUG & 256
{ where(); ip_print_frags(ass_ent->ia_frags); printf("\n"); }
#endif
pack= ass_ent->ia_frags;
pack_hdr= (ip_hdr_t *)ptr2acc_data(pack);
pack_flags_fragoff= ntohs(pack_hdr->ih_flags_fragoff);
#if DEBUG & 256
{ where(); printf(
"merge_pack: flags_fragoff= %u, vers_ihl= 0x%x, length= %u\n",
pack_flags_fragoff, pack_hdr->ih_vers_ihl,
ntohs(pack_hdr->ih_length)); }
#endif
if (!(pack_flags_fragoff & (IH_FRAGOFF_MASK|IH_MORE_FRAGS)))
/* it's now a complete packet */
{
#if DEBUG & 256
{ where(); printf("got a complete packet now\n"); }
#endif
first_time= ass_ent->ia_first_time;
ass_ent->ia_frags= 0;
ass_ent->ia_first_time= 0;
while (pack->acc_ext_link)
{
{ where(); printf("strange\n"); }
tmp_acc= pack->acc_ext_link;
pack->acc_ext_link= tmp_acc->acc_ext_link;
bf_afree(tmp_acc);
}
if ((ass_ent->ia_min_ttl) * HZ + first_time <
get_time())
icmp_frag_ass_tim(pack);
else
return pack;
}
return NULL;
}
PRIVATE acc_t *merge_frags (first, second)
acc_t *first, *second;
{
ip_hdr_t *first_hdr, *second_hdr;
size_t first_hdr_size, second_hdr_size, first_datasize, second_datasize,
first_offset, second_offset;
acc_t *cut_second, *tmp_acc;
#if DEBUG & 256
{ where(); ip_print_frags(first); printf(" , "); ip_print_frags(second); }
#endif
if (!second)
{
first->acc_ext_link= NULL;
return first;
}
assert (first->acc_length >= IP_MIN_HDR_SIZE);
assert (second->acc_length >= IP_MIN_HDR_SIZE);
first_hdr= (ip_hdr_t *)ptr2acc_data(first);
first_offset= (ntohs(first_hdr->ih_flags_fragoff) &
IH_FRAGOFF_MASK) * 8;
first_hdr_size= (first_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
first_datasize= ntohs(first_hdr->ih_length) - first_hdr_size;
for (;;)
{
second_hdr= (ip_hdr_t *)ptr2acc_data(second);
second_offset= (ntohs(second_hdr->ih_flags_fragoff) &
IH_FRAGOFF_MASK) * 8;
second_hdr_size= (second_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
second_datasize= ntohs(second_hdr->ih_length) - second_hdr_size;
#if DEBUG
if (second_offset <= first_offset)
{ where(); printf ("first_offset= %u, second_offset= %u\n",
first_offset, second_offset);
printf ("first_hdr_size= %u, second_hdr_size= %u\n",
first_hdr_size, second_hdr_size);
printf ("first_datasize= %u, second_datasize= %u\n",
first_datasize, second_datasize); }
#endif
assert (first_hdr_size + first_datasize == bf_bufsize(first));
assert (second_hdr_size + second_datasize == bf_bufsize(second));
assert (second_offset > first_offset);
if (second_offset > first_offset+first_datasize)
{
first->acc_ext_link= second;
return first;
}
if (second_offset + second_datasize <= first_offset +
first_datasize)
{
first->acc_ext_link= second->acc_ext_link;
bf_afree(second);
break;
}
if (!(second_hdr->ih_flags_fragoff & HTONS(IH_MORE_FRAGS)))
first_hdr->ih_flags_fragoff &= ~HTONS(IH_MORE_FRAGS);
second_datasize= second_offset+second_datasize-(first_offset+
first_datasize);
cut_second= bf_cut(second, second_hdr_size + first_offset+
first_datasize-second_offset, second_datasize);
tmp_acc= second->acc_ext_link;
bf_afree(second);
second= tmp_acc;
first_datasize += second_datasize;
first_hdr->ih_length= htons(first_hdr_size + first_datasize);
first= bf_append (first, cut_second);
if (!second)
{
first->acc_ext_link= NULL;
break;
}
assert (first->acc_length >= IP_MIN_HDR_SIZE);
first_hdr= (ip_hdr_t *)ptr2acc_data(first);
}
assert (first_hdr_size + first_datasize == bf_bufsize(first));
return first;
}
PRIVATE ip_ass_t *find_ass_ent (port, id, proto, src, dst)
ip_port_t *port;
u16_t id;
ipproto_t proto;
ipaddr_t src;
ipaddr_t dst;
{
ip_ass_t *new_ass_ent, *tmp_ass_ent;
int i;
acc_t *tmp_acc, *curr_acc;
#if DEBUG & 256
{ where(); printf("find_ass_ent (.., id= %u, proto= %u, src= ",
id, ntohs(proto)); writeIpAddr(src); printf(" dst= ");
writeIpAddr(dst); printf(")\n"); }
#endif
new_ass_ent= 0;
for (i=0, tmp_ass_ent= ip_ass_table; i<IP_ASS_NR; i++,
tmp_ass_ent++)
{
if (!tmp_ass_ent->ia_frags && tmp_ass_ent->
ia_first_time)
{
#if DEBUG
{ where(); printf("ip.c: strange ip_ass entry (can be a race condition)\n"); }
#endif
continue;
}
if ((tmp_ass_ent->ia_srcaddr == src) &&
(tmp_ass_ent->ia_dstaddr == dst) &&
(tmp_ass_ent->ia_proto == proto) &&
(tmp_ass_ent->ia_id == id) &&
(tmp_ass_ent->ia_port == port))
{
#if DEBUG & 256
{ where(); printf("found an ass_ent\n"); }
#endif
return tmp_ass_ent;
}
if (!new_ass_ent || tmp_ass_ent->ia_first_time <
new_ass_ent->ia_first_time)
new_ass_ent= tmp_ass_ent;
}
#if DEBUG & 256
{ where(); printf("made an ass_ent\n"); }
#endif
new_ass_ent->ia_min_ttl= IP_MAX_TTL;
new_ass_ent->ia_port= port;
new_ass_ent->ia_first_time= get_time();
new_ass_ent->ia_srcaddr= src;
new_ass_ent->ia_dstaddr= dst;
new_ass_ent->ia_proto= proto;
new_ass_ent->ia_id= id;
if (new_ass_ent->ia_frags)
{
curr_acc= new_ass_ent->ia_frags->acc_ext_link;
while (curr_acc)
{
tmp_acc= curr_acc->acc_ext_link;
bf_afree(curr_acc);
curr_acc= tmp_acc;
}
curr_acc= new_ass_ent->ia_frags;
new_ass_ent->ia_frags= 0;
icmp_frag_ass_tim(curr_acc);
}
return new_ass_ent;
}
PUBLIC void ip_eth_arrived(ip_port, pack)
ip_port_t *ip_port;
acc_t *pack;
{
ip_hdr_t *ip_hdr;
int for_this_port, broadcast_allowed, broadcast_pack;
int ip_frag_len, ip_hdr_len;
acc_t *ip_acc, *eth_acc;
ether_addr_t eth_dst, eth_src;
eth_hdr_t *eth_hdr;
size_t pack_size;
#if DEBUG & 256
{ where(); printf("ip_eth_arrived(&ip_port_table[%d], packet_length= %d)\n",
ip_port-ip_port_table, bf_bufsize(pack)); }
#endif
pack= bf_packIffLess(pack, ETH_HDR_SIZE);
assert (pack->acc_length >= ETH_HDR_SIZE);
eth_hdr= (eth_hdr_t *)ptr2acc_data(pack);
eth_dst= eth_hdr->eh_dst;
eth_src= eth_hdr->eh_src;
if (eth_dst.ea_addr[0] & 0x01)
broadcast_pack= TRUE;
else
broadcast_pack= FALSE;
pack_size= bf_bufsize(pack);
eth_acc= bf_cut(pack, 0, ETH_HDR_SIZE);
ip_acc= bf_cut(pack, ETH_HDR_SIZE, pack_size-ETH_HDR_SIZE);
pack_size -= ETH_HDR_SIZE;
#if DEBUG & 256
{ where(); printf("packet_length= %d\n", bf_bufsize(ip_acc)); }
#endif
bf_afree(pack);
if (pack_size < IP_MIN_HDR_SIZE)
{
#if DEBUG
{ where(); printf("wrong acc_length\n"); }
#endif
bf_afree(ip_acc);
bf_afree(eth_acc);
return;
}
ip_acc= bf_packIffLess(ip_acc, IP_MIN_HDR_SIZE);
assert (ip_acc->acc_length >= IP_MIN_HDR_SIZE);
ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_acc);
ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
if (ip_hdr_len>IP_MIN_HDR_SIZE)
{
ip_acc= bf_packIffLess(ip_acc, ip_hdr_len);
ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_acc);
}
#if DEBUG & 256
{ where(); printf("ih_vers_ihl= 0x%x\n", ip_hdr->ih_vers_ihl); }
#endif
ip_frag_len= ntohs(ip_hdr->ih_length);
if (ip_frag_len<pack_size)
{
pack= ip_acc;
ip_acc= bf_cut(pack, 0, ip_frag_len);
bf_afree(pack);
}
#if DEBUG & 256
{ where(); printf("ip_frag_len= %d, packet length= %d\n", ip_frag_len, bf_bufsize(ip_acc)); }
#endif
if (!ip_frag_chk(ip_acc))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -