📄 ip_write.c
字号:
#if DEBUG & 256
{ where(); printf("processing arp_pack\n"); }
#endif
assert (ip_port->ip_dl.dl_eth.de_arp_pack);
ip_port->ip_dl.dl_eth.de_wr_ipaddr= (ipaddr_t)0;
ip_port->ip_dl.dl_eth.de_wr_ethaddr= ip_port->ip_dl.
dl_eth.de_arp_ethaddr;
ip_port->ip_dl.dl_eth.de_wr_frag= ip_port->ip_dl.dl_eth.
de_arp_pack;
ip_port->ip_dl.dl_eth.de_flags &= ~IEF_ARP_MASK;
return;
}
for (i=0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
{
if (!(ip_fd->if_flags & IFF_INUSE))
continue;
if (!(ip_fd->if_flags & IFF_DLL_WR_IP))
continue;
if (ip_fd->if_wr_port != ip_port)
continue;
#if DEBUG & 256
{ where(); printf("calling restart_fd_write\n"); }
#endif
restart_fd_write(ip_fd);
if (ip_port->ip_dl.dl_eth.de_wr_frag)
return;
}
}
PRIVATE void restart_netbroad_fd(ip_fd)
ip_fd_t *ip_fd;
{
assert (!(netbroad_flags & NF_INUSE));
assert (ip_fd->if_flags & IFF_NETBROAD_IP);
ip_fd->if_flags &= ~IFF_NETBROAD_IP;
netbroad_flags |= NF_INUSE;
netbroad_dst= ip_fd->if_wr_dstaddr;
netbroad_netmask= ip_get_netmask(netbroad_dst);
netbroad_pack= get_packet(ip_fd, (int)get_time());
if (!netbroad_pack)
{
netbroad_flags &= ~NF_INUSE;
return;
}
netbroad_port= ip_port_table;
restart_netbroadcast();
error_reply(ip_fd, ip_fd->if_wr_count);
}
PRIVATE void restart_fd_write(ip_fd)
ip_fd_t *ip_fd;
{
ip_port_t *ip_port;
ipaddr_t dstaddr;
acc_t *pack;
int result;
assert (ip_fd->if_flags & IFF_DLL_WR_IP);
ip_port= ip_fd->if_wr_port;
dstaddr= ip_fd->if_wr_dstaddr;
result= dll_ready(ip_port, dstaddr);
if (result == NW_SUSPEND)
{
return;
}
if (result == EDSTNOTRCH)
{
#if DEBUG
{ where(); printf("dll_ready returned EDSTNOTRCH, gateway= ");
writeIpAddr(ip_fd->if_wr_dstaddr); printf(", the packet was %s\n",
(ip_fd->if_flags & IFF_ROUTED) ? "routed" : "not routed"); }
#endif
if (!(ip_fd->if_flags & IFF_ROUTED))
{
error_reply (ip_fd, result);
return;
}
else
{
ipr_gateway_down (ip_fd->if_wr_dstaddr,
IPR_GW_DOWN_TIMEOUT);
error_reply(ip_fd, NW_OK);
return;
}
}
assert (result == NW_OK);
ip_fd->if_flags &= ~IFF_DLL_WR_IP;
ip_port->ip_frame_id++;
pack= get_packet(ip_fd, ip_port->ip_frame_id);
if (!pack)
{
return;
}
dll_write(ip_port, dstaddr, pack);
error_reply(ip_fd, ip_fd->if_wr_count);
}
PRIVATE void ip_remroute_addr(ip_fd, ttl)
ip_fd_t *ip_fd;
u8_t ttl;
{
ipaddr_t dstaddr, nexthop;
ip_port_t *ip_port;
int result, port;
dstaddr= ip_fd->if_wr_dstaddr;
result= iproute_frag (dstaddr, ttl, &nexthop, &port);
#if DEBUG & 256
{ where(); printf("ip_remroute_addr("); writeIpAddr(dstaddr);
printf(", %d)= %d\n", ttl, result); }
#endif
if (result>0)
{
ip_port= &ip_port_table[port];
ip_fd->if_flags |= IFF_DLL_WR_IP|IFF_ROUTED;
ip_fd->if_wr_dstaddr= nexthop;
ip_fd->if_wr_port= ip_port;
#if DEBUG & 256
{ where(); printf("calling restart_fd_write\n"); }
#endif
restart_fd_write(ip_fd);
return;
}
if (result<0)
{
error_reply (ip_fd, result);
return;
}
#if IP_ROUTER
ip_panic(( "not implemented" ));
#else
ip_panic(( "shouldn't be here" ));
#endif
}
PRIVATE acc_t *ip_split_pack (ref_last, first_size)
acc_t **ref_last;
int first_size;
{
int pack_siz;
ip_hdr_t *first_hdr, *second_hdr;
int first_hdr_len, second_hdr_len;
int first_data_len, second_data_len;
int new_first_data_len;
int first_opt_size, second_opt_size;
acc_t *first_pack, *second_pack, *tmp_pack, *tmp_pack1;
u8_t *first_optptr, *second_optptr;
int i, optlen;
first_pack= *ref_last;
*ref_last= 0;
second_pack= 0;
first_pack= bf_packIffLess(first_pack, IP_MIN_HDR_SIZE);
assert (first_pack->acc_length >= IP_MIN_HDR_SIZE);
first_hdr= (ip_hdr_t *)ptr2acc_data(first_pack);
#if DEBUG & 256
{ where(); writeIpAddr(first_hdr->ih_dst); printf("\n"); }
#endif
first_hdr_len= (first_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
#if DEBUG & 256
{ where(); printf("fist_hdr_len= %d\n", first_hdr_len); }
#endif
pack_siz= bf_bufsize(first_pack);
if (pack_siz > first_size)
{
#if DEBUG & 256
{ where(); printf("splitting pack\n"); }
#endif
if (first_hdr->ih_flags_fragoff & HTONS(IH_DONT_FRAG))
{
assert (!(first_hdr->ih_flags_fragoff) & HTONS(IH_FRAGOFF_MASK));
icmp_dont_frag(first_pack);
return 0;
}
first_data_len= ntohs(first_hdr->ih_length) - first_hdr_len;
new_first_data_len= (first_size- first_hdr_len) & ~7;
/* data goes in 8 byte chuncks */
second_data_len= first_data_len-new_first_data_len;
second_pack= bf_cut(first_pack, first_hdr_len+
new_first_data_len, second_data_len);
tmp_pack= first_pack;
first_data_len= new_first_data_len;
first_pack= bf_cut (tmp_pack, 0, first_hdr_len+first_data_len);
bf_afree(tmp_pack);
tmp_pack= bf_memreq(first_hdr_len);
tmp_pack->acc_next= second_pack;
second_pack= tmp_pack;
second_hdr= (ip_hdr_t *)ptr2acc_data(second_pack);
*second_hdr= *first_hdr;
second_hdr->ih_flags_fragoff= htons(
ntohs(first_hdr->ih_flags_fragoff)+(first_data_len/8));
first_opt_size= first_hdr_len-IP_MIN_HDR_SIZE;
second_opt_size= 0;
if (first_opt_size)
{
first_pack= bf_packIffLess (first_pack,
first_hdr_len);
first_hdr= (ip_hdr_t *)ptr2acc_data(first_pack);
assert (first_pack->acc_length>=first_hdr_len);
first_optptr= (u8_t *)ptr2acc_data(first_pack)+
IP_MIN_HDR_SIZE;
second_optptr= (u8_t *)ptr2acc_data(
second_pack)+IP_MIN_HDR_SIZE;
i= 0;
while (i<first_opt_size)
{
switch (*first_optptr & IP_OPT_NUMBER)
{
case 0:
case 1:
optlen= 1;
break;
default:
optlen= first_optptr[1];
break;
}
assert (i + optlen <= first_opt_size);
i += optlen;
if (*first_optptr & IP_OPT_COPIED)
{
second_opt_size += optlen;
while (optlen--)
*second_optptr++=
*first_optptr++;
}
else
first_optptr += optlen;
}
while (second_opt_size & 3)
{
*second_optptr++= 0;
second_opt_size++;
}
}
second_hdr_len= IP_MIN_HDR_SIZE + second_opt_size;
#if DEBUG & 256
{ where(); printf("second_opt_size= %d, second_hdr_len= %d\n",
second_opt_size, second_hdr_len); }
#endif
second_hdr->ih_vers_ihl= second_hdr->ih_vers_ihl & 0xf0
+ (second_hdr_len/4);
second_hdr->ih_length= htons(second_data_len+
second_hdr_len);
second_pack->acc_length= second_hdr_len;
if (first_pack->acc_buffer->buf_linkC>1)
{
tmp_pack= bf_cut(first_pack, 0,
IP_MIN_HDR_SIZE);
tmp_pack1= bf_cut(first_pack, IP_MIN_HDR_SIZE,
bf_bufsize(first_pack)-
IP_MIN_HDR_SIZE);
bf_afree(first_pack);
#if DEBUG
{ where(); printf("calling bf_pack\n"); }
#endif
first_pack= bf_pack(tmp_pack);
first_pack->acc_next= tmp_pack1;
first_hdr= (ip_hdr_t *)ptr2acc_data(
first_pack);
}
assert (first_pack->acc_buffer->buf_linkC == 1);
first_hdr->ih_flags_fragoff |= HTONS(IH_MORE_FRAGS);
first_hdr->ih_length= htons(first_data_len+
first_hdr_len);
assert (!(second_hdr->ih_flags_fragoff & HTONS(IH_DONT_FRAG)));
}
if (first_pack->acc_buffer->buf_linkC>1)
{
tmp_pack= bf_cut(first_pack, 0, IP_MIN_HDR_SIZE);
tmp_pack1= bf_cut(first_pack, IP_MIN_HDR_SIZE,
bf_bufsize(first_pack)-IP_MIN_HDR_SIZE);
bf_afree(first_pack);
#if DEBUG
{ where(); printf("calling bf_pack\n"); }
#endif
first_pack= bf_pack(tmp_pack);
first_pack->acc_next= tmp_pack1;
first_hdr= (ip_hdr_t *)ptr2acc_data(first_pack);
}
assert (first_hdr->ih_ttl);
#if DEBUG & 256
{ where(); printf("ip_write.c: ip_split_pack: first_hdr_len= %d\n",
first_hdr_len); }
#endif
first_hdr->ih_hdr_chk= 0;
first_hdr->ih_hdr_chk= ~oneC_sum (0, (u16_t *)first_hdr,
first_hdr_len);
*ref_last= second_pack;
return first_pack;
}
PRIVATE void restart_netbroadcast()
{
int was_suspended, result, i;
ip_port_t *ip_port, *hi_port;
ip_fd_t *ip_fd;
assert (netbroad_flags & NF_INUSE);
was_suspended= !!(netbroad_flags & NF_SUSPENDED);
hi_port= &ip_port_table[IP_PORT_NR];
for (; netbroad_port < hi_port; netbroad_port++)
{
if (!(netbroad_port->ip_flags & IPF_IPADDRSET))
continue;
if (!((netbroad_dst ^ netbroad_port->ip_ipaddr) &
netbroad_netmask))
continue;
result= dll_ready (netbroad_port, (ipaddr_t)-1);
if (result == NW_SUSPEND)
{
netbroad_flags |= NF_SUSPENDED;
return;
}
assert (result >= 0);
netbroad_pack->acc_linkC++;
#if DEBUG
{ where(); printf("calling dll_write\n"); }
#endif
dll_write (netbroad_port, (ipaddr_t)(-1),
netbroad_pack);
}
netbroad_flags &= ~NF_INUSE;
bf_afree(netbroad_pack);
netbroad_pack= 0;
if (!was_suspended)
return;
for (i=0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
{
if (!(ip_fd->if_flags & IFF_INUSE) ||
!(ip_fd->if_flags & IFF_NETBROAD_IP))
continue;
restart_netbroad_fd(ip_fd);
if (netbroad_flags & NF_INUSE)
return;
}
}
PRIVATE void error_reply (ip_fd, error)
ip_fd_t *ip_fd;
int error;
{
ip_fd->if_flags &= ~IFF_WRITE_MASK;
if ((*ip_fd->if_get_userdata)(ip_fd->if_srfd, (size_t)error,
(size_t)0, FALSE))
ip_panic(( "can't error_reply" ));
}
PRIVATE acc_t *get_packet (ip_fd, id)
ip_fd_t *ip_fd;
u16_t id;
{
acc_t *pack, *tmp_pack, *tmp_pack1;
ip_hdr_t *hdr, *tmp_hdr;
int pack_len, hdr_len, hdr_opt_len, error;
pack_len= ip_fd->if_wr_count;
pack= (*ip_fd->if_get_userdata)(ip_fd->if_srfd, (size_t)0,
pack_len, FALSE);
if (!pack)
return pack;
assert(pack_len == bf_bufsize(pack));
if (ip_fd->if_ipopt.nwio_flags & NWIO_RWDATONLY)
{
tmp_pack= bf_memreq (IP_MIN_HDR_SIZE);
tmp_pack->acc_next= pack;
pack= tmp_pack;
pack_len += IP_MIN_HDR_SIZE;
}
if (pack_len<IP_MIN_HDR_SIZE)
{
bf_afree(pack);
error_reply(ip_fd, EPACKSIZE);
return 0;
}
pack= bf_packIffLess(pack, IP_MIN_HDR_SIZE);
assert (pack->acc_length >= IP_MIN_HDR_SIZE);
hdr= (ip_hdr_t *)ptr2acc_data(pack);
if (pack->acc_linkC != 1 || pack->acc_buffer->buf_linkC != 1)
{
tmp_pack= bf_memreq(IP_MIN_HDR_SIZE);
tmp_hdr= (ip_hdr_t *)ptr2acc_data(tmp_pack);
*tmp_hdr= *hdr;
tmp_pack->acc_next= bf_cut(pack, IP_MIN_HDR_SIZE,
pack_len-IP_MIN_HDR_SIZE);
bf_afree(pack);
hdr= tmp_hdr;
#if DEBUG & 256
{ where(); printf("ih_vers_ihl= 0x%x\n", hdr->ih_vers_ihl); }
#endif
pack= tmp_pack;
assert (pack->acc_length >= IP_MIN_HDR_SIZE);
}
assert (pack->acc_linkC == 1 && pack->acc_buffer->buf_linkC == 1);
if (ip_fd->if_ipopt.nwio_flags & NWIO_HDR_O_SPEC)
{
#if DEBUG & 256
{ where(); printf("ih_vers_ihl= 0x%x\n", hdr->ih_vers_ihl); }
#endif
hdr_opt_len= ip_fd->if_ipopt.nwio_hdropt.iho_opt_siz;
if (hdr_opt_len)
{
tmp_pack= bf_cut(pack, 0, IP_MIN_HDR_SIZE);
tmp_pack1= bf_cut (pack, IP_MIN_HDR_SIZE,
pack_len-IP_MIN_HDR_SIZE);
bf_afree(pack);
pack= bf_packIffLess(tmp_pack, IP_MIN_HDR_SIZE);
hdr= (ip_hdr_t *)ptr2acc_data(pack);
{ where(); printf("ih_vers_ihl= 0x%x\n", hdr->ih_vers_ihl); }
tmp_pack= bf_memreq (hdr_opt_len);
memcpy (ptr2acc_data(tmp_pack), ip_fd->if_ipopt.
nwio_hdropt.iho_data, hdr_opt_len);
{ where(); printf("ih_vers_ihl= 0x%x\n", hdr->ih_vers_ihl); }
pack->acc_next= tmp_pack;
tmp_pack->acc_next= tmp_pack1;
hdr_len= IP_MIN_HDR_SIZE+hdr_opt_len;
}
else
hdr_len= IP_MIN_HDR_SIZE;
hdr->ih_vers_ihl= hdr_len/4;
#if DEBUG & 256
{ where(); printf("ih_vers_ihl= 0x%x\n", hdr->ih_vers_ihl); }
#endif
hdr->ih_tos= ip_fd->if_ipopt.nwio_tos;
hdr->ih_flags_fragoff= 0;
if (ip_fd->if_ipopt.nwio_df)
hdr->ih_flags_fragoff |= HTONS(IH_DONT_FRAG);
hdr->ih_ttl= ip_fd->if_ipopt.nwio_ttl;
#if DEBUG & 256
{ where(); printf("ih_vers_ihl= 0x%x\n", hdr->ih_vers_ihl); }
#endif
}
else
{
assert (ip_fd->if_ipopt.nwio_flags & NWIO_HDR_O_ANY);
hdr_len= (hdr->ih_vers_ihl & IH_IHL_MASK)*4;
#if DEBUG & 256
{ where(); printf("ih_vers_ihl= 0x%x\n", hdr->ih_vers_ihl); }
#endif
error= NW_OK;
if (hdr_len<IP_MIN_HDR_SIZE)
error= EINVAL;
else if (hdr_len>pack_len)
error= EPACKSIZE;
else if (!hdr->ih_ttl)
error= EINVAL;
if (error<0)
{
bf_afree(pack);
error_reply (ip_fd, error);
return 0;
}
pack= bf_packIffLess(pack, hdr_len);
hdr= (ip_hdr_t *)ptr2acc_data(pack);
#if DEBUG & 256
{ where(); printf("ih_vers_ihl= 0x%x\n", hdr->ih_vers_ihl); }
#endif
if (hdr_len != IP_MIN_HDR_SIZE)
{
error= ip_chk_hdropt((u8_t *)(ptr2acc_data(pack) +
IP_MIN_HDR_SIZE),
hdr_len-IP_MIN_HDR_SIZE);
if (error<0)
{
bf_afree(pack);
error_reply (ip_fd, error);
return 0;
}
}
#if DEBUG & 256
{ where(); printf("ih_vers_ihl= 0x%x\n", hdr->ih_vers_ihl); }
#endif
}
#if DEBUG & 256
if (hdr->ih_flags_fragoff & HTONS(IH_DONT_FRAG))
{ where(); printf("proto= %d\n", hdr->ih_proto); }
#endif
assert (!(hdr->ih_flags_fragoff & HTONS(IH_DONT_FRAG)));
#if DEBUG & 256
{ where(); printf("ih_vers_ihl= 0x%x\n", hdr->ih_vers_ihl); }
#endif
hdr->ih_vers_ihl= (hdr->ih_vers_ihl & IH_IHL_MASK) |
(IP_VERSION << 4);
#if DEBUG & 256
{ where(); printf("ih_vers_ihl= 0x%x\n", hdr->ih_vers_ihl); }
#endif
hdr->ih_length= htons(pack_len);
hdr->ih_flags_fragoff &= ~HTONS(IH_FRAGOFF_MASK |
IH_FLAGS_UNUSED | IH_MORE_FRAGS);
if (ip_fd->if_ipopt.nwio_flags & NWIO_PROTOSPEC)
hdr->ih_proto= ip_fd->if_ipopt.nwio_proto;
hdr->ih_id= htons(id);
hdr->ih_src= ip_fd->if_port->ip_ipaddr;
if (ip_fd->if_ipopt.nwio_flags & NWIO_REMSPEC)
hdr->ih_dst= ip_fd->if_ipopt.nwio_rem;
else
{
assert (ip_fd->if_ipopt.nwio_flags & NWIO_REMANY);
error= chk_dstaddr(hdr->ih_dst);
if (error<0)
{
bf_afree(pack);
error_reply(ip_fd, error);
return 0;
}
}
return pack;
}
PRIVATE chk_dstaddr (dst)
ipaddr_t dst;
{
ipaddr_t hostrep_dst, netmask;
hostrep_dst= ntohl(dst);
if (hostrep_dst == (ipaddr_t)-1)
return NW_OK;
if ((hostrep_dst & 0xe0000000l) == 0xe0000000l)
return EBADDEST;
netmask= ip_get_netmask(dst);
if (!(dst & ~netmask))
return EBADDEST;
return NW_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -