📄 ip_write.c
字号:
/*
ip_write.c
*/
#include "inet.h"
#include "buf.h"
#include "type.h"
#include "arp.h"
#include "assert.h"
#include "clock.h"
#include "eth.h"
#include "icmp_lib.h"
#include "io.h"
#include "ip.h"
#include "ip_int.h"
#include "ipr.h"
INIT_PANIC();
FORWARD acc_t *get_packet ARGS(( ip_fd_t *ip_fd,
U16_t id /* should be: u16_t id */ ));
FORWARD int dll_ready ARGS(( ip_port_t *port, ipaddr_t dst ));
FORWARD void dll_write ARGS(( ip_port_t *port, ipaddr_t dst,
acc_t *pack ));
FORWARD int dll_eth_ready ARGS(( ip_port_t *port, ipaddr_t dst ));
FORWARD void dll_eth_write ARGS(( ip_port_t *port, ipaddr_t dst,
acc_t *pack ));
FORWARD void dll_eth_arp_func ARGS(( int fd,
ether_addr_t *ethaddr ));
FORWARD acc_t *ip_split_pack ARGS(( acc_t **ref_last,
int first_size ));
FORWARD void error_reply ARGS(( ip_fd_t *fd, int error ));
FORWARD int chk_dstaddr ARGS(( ipaddr_t dst ));
FORWARD void restart_netbroadcast ARGS(( void ));
FORWARD int ip_localroute_addr ARGS(( ip_fd_t *ip_fd ));
FORWARD void ip_remroute_addr ARGS(( ip_fd_t *ip_fd, U8_t ttl ));
FORWARD void restart_fd_write ARGS(( ip_fd_t *ip_fd ));
FORWARD void restart_netbroad_fd ARGS(( ip_fd_t *tcp_fd ));
FORWARD void dll_eth_get_work ARGS(( ip_port_t *ip_port ));
#define NF_EMPTY 0
#define NF_INUSE 1
#define NF_SUSPENDED 2
PRIVATE unsigned int netbroad_flags= NF_EMPTY;
PRIVATE acc_t *netbroad_pack;
PRIVATE ipaddr_t netbroad_dst;
PRIVATE ipaddr_t netbroad_netmask;
PRIVATE ip_port_t *netbroad_port;
PUBLIC int ip_write (fd, count)
int fd;
size_t count;
{
ip_fd_t *ip_fd;
acc_t *data;
int result;
int ttl;
#if DEBUG & 256
{ where(); printf("ip_write.c: ip_write(fd= %d, count= %d\n", fd,
count); }
#endif
ip_fd= &ip_fd_table[fd];
if (!(ip_fd->if_flags & IFF_OPTSET))
{
error_reply (ip_fd, EBADMODE);
return NW_OK;
}
if (ip_fd->if_ipopt.nwio_flags & NWIO_RWDATALL)
{
if (count < IP_MIN_HDR_SIZE || count > IP_MAX_PACKSIZE)
{
error_reply (ip_fd, EPACKSIZE);
return NW_OK;
}
}
else
{
assert (ip_fd->if_ipopt.nwio_flags & NWIO_RWDATONLY);
if (count < 0 || count > IP_MAX_PACKSIZE-IP_MIN_HDR_SIZE)
{
error_reply (ip_fd, EPACKSIZE);
return NW_OK;
}
}
ip_fd->if_wr_count= count;
assert (!(ip_fd->if_flags & IFF_WRITE_IP));
ip_fd->if_flags &= ~IFF_WRITE_MASK;
ip_fd->if_flags |= IFF_WRITE_IP;
if (!(ip_fd->if_port->ip_flags & IPF_IPADDRSET))
return NW_SUSPEND;
if (ip_fd->if_ipopt.nwio_flags & NWIO_REMSPEC)
ip_fd->if_wr_dstaddr= ip_fd->if_ipopt.nwio_rem;
else
{
data= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
(size_t)(offsetof (struct ip_hdr, ih_dst)),
sizeof(ipaddr_t), FALSE);
if (!data)
{
ip_fd->if_flags &= ~IFF_WRITE_IP;
return NW_OK;
}
data= bf_packIffLess (data, sizeof(ipaddr_t));
ip_fd->if_wr_dstaddr= *(ipaddr_t *)ptr2acc_data(data);
bf_afree(data);
data= 0;
}
if (ip_fd->if_ipopt.nwio_flags & NWIO_HDR_O_SPEC)
ttl= 255; /* For traceroute */
else
{
data= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
(size_t)(offsetof (struct ip_hdr, ih_ttl)),
sizeof(u8_t), FALSE);
if (!data)
{
ip_fd->if_flags &= ~IFF_WRITE_IP;
return NW_OK;
}
data= bf_packIffLess (data, sizeof(u8_t));
ttl= *(u8_t *)ptr2acc_data(data);
bf_afree(data);
data= 0;
}
result= ip_localroute_addr(ip_fd);
if (!result)
ip_remroute_addr(ip_fd, ttl);
if (ip_fd->if_flags & IFF_WRITE_IP)
return NW_SUSPEND;
else
return NW_OK;
}
PRIVATE int ip_localroute_addr (ip_fd)
ip_fd_t *ip_fd;
{
ipaddr_t dstaddr, netmask;
u8_t *addrInBytes;
acc_t *pack;
ip_hdr_t *hdr_ptr;
ip_port_t *ip_port;
int result, i;
#if DEBUG & 256
{ where(); printf("ip_write.c: ip_route_addr(...) to ");
writeIpAddr(ip_fd->if_wr_dstaddr); printf("\n"); }
#endif
dstaddr= ip_fd->if_wr_dstaddr;
addrInBytes= (u8_t *)&dstaddr;
ip_port= ip_fd->if_port;
if ((addrInBytes[0] & 0xff) == 0x7f) /* local loopback */
{
pack= get_packet(ip_fd, (u16_t)0);
if (!pack)
{
ip_fd->if_flags &= ~IFF_WRITE_IP;
return TRUE;
}
assert (pack->acc_length >= IP_MIN_HDR_SIZE);
assert (pack->acc_linkC == 1);
hdr_ptr= (ip_hdr_t *)ptr2acc_data(pack);
dstaddr= hdr_ptr->ih_dst; /* src and dst
addresses */
hdr_ptr->ih_dst= hdr_ptr->ih_src;
hdr_ptr->ih_src= dstaddr;
ip_port_arrive (ip_port, pack, hdr_ptr);
ip_fd->if_flags &= ~IFF_WRITE_IP;
error_reply (ip_fd, ip_fd->if_wr_count);
return TRUE;
}
if (dstaddr == (ipaddr_t)-1)
{
ip_fd->if_flags |= IFF_DLL_WR_IP;
ip_fd->if_wr_port= ip_port;
#if DEBUG
{ where(); printf("calling restart_fd_write\n"); }
#endif
restart_fd_write(ip_fd);
return TRUE;
}
netmask= ip_get_netmask(dstaddr);
for (i=0, ip_port= ip_port_table; i<IP_PORT_NR; i++, ip_port++)
{
if (!(ip_port->ip_flags & IPF_IPADDRSET))
{
#if DEBUG
{ where(); printf("!(ip_port_table[%d].ip_flags & IPF_IPADDRSET)\n",
ip_port-ip_port_table); }
#endif
continue;
}
#if DEBUG & 256
{ where(); printf("ip_port_table[%d].ip_ipaddr= ", ip_port-ip_port_table);
writeIpAddr(ip_port->ip_ipaddr); printf("\n"); }
#endif
if (ip_port->ip_ipaddr == dstaddr)
{
pack= get_packet(ip_fd, (u16_t)0);
if (!pack)
{
ip_fd->if_flags &= ~IFF_WRITE_IP;
return TRUE;
}
assert (pack->acc_length >= IP_MIN_HDR_SIZE);
assert (pack->acc_linkC == 1);
ip_port_arrive (ip_port, pack,
(ip_hdr_t *)ptr2acc_data(pack));
ip_fd->if_flags &= ~IFF_WRITE_IP;
error_reply (ip_fd, ip_fd->if_wr_count);
return TRUE;
}
if ((dstaddr & ip_port->ip_netmask) ==
(ip_port->ip_ipaddr & ip_port->ip_netmask))
{
ip_fd->if_wr_port= ip_port;
if ((dstaddr & ~ip_port->ip_netmask) ==
~ip_port->ip_netmask)
ip_fd->if_wr_dstaddr= (ipaddr_t)-1;
ip_fd->if_flags |= IFF_DLL_WR_IP;
#if DEBUG & 256
{ where(); printf("calling restart_fd_write\n"); }
#endif
restart_fd_write(ip_fd);
return TRUE;
}
if (((dstaddr & netmask) == (ip_port->ip_ipaddr &
netmask)) && ((dstaddr & ~netmask) == ~netmask))
{
if (!(netbroad_flags & NF_INUSE))
restart_netbroad_fd(ip_fd);
else
ip_fd->if_flags |= IFF_NETBROAD_IP;
return TRUE;
}
}
return FALSE;
}
PRIVATE int dll_ready(port, dst)
ip_port_t *port;
ipaddr_t dst;
{
switch (port->ip_dl_type)
{
case IPDL_ETH:
return dll_eth_ready (port, dst);
default:
ip_panic(( "strange dll_type" ));
}
return NW_OK;
}
PRIVATE int dll_eth_ready (port, dst)
ip_port_t *port;
ipaddr_t dst;
{
int result;
if (port->ip_dl.dl_eth.de_wr_frame || port->ip_dl.dl_eth.
de_wr_frag)
{
#if DEBUG & 256
{ where(); printf("dll_eth_ready: frame or frag present\n"); }
#endif
return NW_SUSPEND;
}
if (dst == (ipaddr_t)-1)
{
#if DEBUG & 256
{ where(); printf("dll_eth_ready: broadcast\n"); }
#endif
port->ip_dl.dl_eth.de_wr_ipaddr= dst;
port->ip_dl.dl_eth.de_wr_ethaddr.ea_addr[0]= 0xff;
port->ip_dl.dl_eth.de_wr_ethaddr.ea_addr[1]= 0xff;
port->ip_dl.dl_eth.de_wr_ethaddr.ea_addr[2]= 0xff;
port->ip_dl.dl_eth.de_wr_ethaddr.ea_addr[3]= 0xff;
port->ip_dl.dl_eth.de_wr_ethaddr.ea_addr[4]= 0xff;
port->ip_dl.dl_eth.de_wr_ethaddr.ea_addr[5]= 0xff;
return NW_OK;
}
#if DEBUG & 256
{ where(); printf("ip_write.c: calling arp_ip_eth_nonbl(...)\n"); }
#endif
result= arp_ip_eth_nonbl (port->ip_dl.dl_eth.de_port,
dst, &port->ip_dl.dl_eth.de_wr_ethaddr);
#if DEBUG & 256
{ where(); printf("ip_write.c: arp_ip_eth_nonbl(...)= %d\n", result); }
#endif
if (result<0)
port->ip_dl.dl_eth.de_wr_ipaddr= (ipaddr_t)0;
if (result == EDSTNOTRCH)
return EDSTNOTRCH;
if (result >= 0)
{
port->ip_dl.dl_eth.de_wr_ipaddr= dst;
return NW_OK;
}
assert (result == NW_SUSPEND);
if (!(port->ip_dl.dl_eth.de_flags & IEF_ARP_IP))
{
#if DEBUG & 256
{ where(); printf("dll_eth_ready: no ARP_IP\n"); }
#endif
return NW_OK;
}
#if DEBUG
{ where(); printf("dll_eth_ready: ARP_IP\n"); }
#endif
return NW_SUSPEND;
}
PRIVATE void dll_write (port, dst, pack)
ip_port_t *port;
ipaddr_t dst;
acc_t *pack;
{
switch (port->ip_dl_type)
{
case IPDL_ETH:
dll_eth_write (port, dst, pack);
break;
default:
ip_panic(( "wrong dl_type" ));
break;
}
}
PRIVATE void dll_eth_write (ip_port, dst, pack)
ip_port_t *ip_port;
ipaddr_t dst;
acc_t *pack;
{
int result;
if (!ip_port->ip_dl.dl_eth.de_wr_frag)
{
if (ip_port->ip_dl.dl_eth.de_wr_ipaddr == dst)
{
ip_port->ip_dl.dl_eth.de_wr_frag= pack;
if (!(ip_port->ip_dl.dl_eth.de_flags &
IEF_WRITE_IP))
{
dll_eth_write_frame(ip_port);
}
return;
}
ip_port->ip_dl.dl_eth.de_wr_ipaddr= (ipaddr_t)0;
#if DEBUG & 256
{ where(); printf("ip_write.c: calling arp_ip_eth_nonbl(...)\n"); }
#endif
result= arp_ip_eth_nonbl (ip_port->ip_dl.dl_eth.de_port,
dst, &ip_port->ip_dl.dl_eth.de_wr_ethaddr);
#if DEBUG & 256
{ where(); printf("ip_write.c: arp_ip_eth_nonbl(...)= %d\n", result); }
#endif
if (result == NW_OK)
{
ip_port->ip_dl.dl_eth.de_wr_frag= pack;
if (!(ip_port->ip_dl.dl_eth.de_flags &
IEF_WRITE_IP))
dll_eth_write_frame(ip_port);
return;
}
}
assert (!(ip_port->ip_dl.dl_eth.de_flags & IEF_ARP_MASK));
ip_port->ip_dl.dl_eth.de_arp_pack= pack;
ip_port->ip_dl.dl_eth.de_flags |= IEF_ARP_IP;
#if DEBUG & 256
{ where(); printf("ip_write.c: calling arp_ip_eth(...)\n"); }
#endif
result= arp_ip_eth (ip_port->ip_dl.dl_eth.de_port,
ip_port-ip_port_table, dst, dll_eth_arp_func);
#if DEBUG & 256
{ where(); printf("ip_write.c: arp_ip_eth(...)= %d\n", result); }
#endif
if (result == NW_SUSPEND)
ip_port->ip_dl.dl_eth.de_flags |= IEF_ARP_SP;
else if (result == EDSTNOTRCH)
{
if (ip_port->ip_dl.dl_eth.de_arp_pack)
{
bf_afree(ip_port->ip_dl.dl_eth.de_arp_pack);
ip_port->ip_dl.dl_eth.de_arp_pack= 0;
}
ip_port->ip_dl.dl_eth.de_flags &= ~IEF_ARP_MASK;
}
else
{
assert (result == NW_OK);
assert (ip_port->ip_dl.dl_eth.de_flags & IEF_WRITE_IP);
}
}
PUBLIC void dll_eth_write_frame (ip_port)
ip_port_t *ip_port;
{
acc_t *frag, *frame, *hdr, *tail;
eth_hdr_t *eth_hdr;
size_t pack_size;
int result;
#if DEBUG & 256
{ where(); printf("ip_write.c: dll_eth_write_frame(...)\n"); }
#endif
assert (!(ip_port->ip_dl.dl_eth.de_flags & IEF_WRITE_IP));
ip_port->ip_dl.dl_eth.de_flags |= IEF_WRITE_IP;
do
{
if (!ip_port->ip_dl.dl_eth.de_wr_frag)
{
dll_eth_get_work (ip_port);
if (!ip_port->ip_dl.dl_eth.de_wr_frag)
{
ip_port->ip_dl.dl_eth.de_flags &=
~IEF_WRITE_IP;
return;
}
}
assert (!ip_port->ip_dl.dl_eth.de_wr_frame);
assert (ip_port->ip_dl.dl_eth.de_wr_frag);
frag= ip_port->ip_dl.dl_eth.de_wr_frag;
ip_port->ip_dl.dl_eth.de_wr_frag= 0;
frame= ip_split_pack(&frag, ETH_MAX_PACK_SIZE-
ETH_HDR_SIZE);
if (!frame)
{
assert (!frag);
continue;
}
ip_port->ip_dl.dl_eth.de_wr_frag= frag;
hdr= bf_memreq(ETH_HDR_SIZE);
eth_hdr= (eth_hdr_t *)ptr2acc_data(hdr);
eth_hdr->eh_dst= ip_port->ip_dl.dl_eth.de_wr_ethaddr;
hdr->acc_next= frame;
frame= hdr;
hdr= 0;
pack_size= bf_bufsize(frame);
if (pack_size<ETH_MIN_PACK_SIZE)
{
#if DEBUG & 256
{ where(); printf("pack_size= %d\n", pack_size); }
#endif
tail= bf_memreq(ETH_MIN_PACK_SIZE-pack_size);
frame= bf_append(frame, tail);
}
#if DEBUG & 256
{ where(); printf("packet size= %d\n", bf_bufsize(ip_port->ip_dl.
dl_eth.de_wr_frame)); }
#endif
ip_port->ip_dl.dl_eth.de_wr_frame= frame;
ip_port->ip_dl.dl_eth.de_flags &= ~IEF_WRITE_SP;
#if DEBUG & 256
{ where(); printf("ip_write.c: calling eth_write(...)\n"); }
#endif
result= eth_write (ip_port->ip_dl.dl_eth.de_fd,
bf_bufsize(ip_port->ip_dl.dl_eth.de_wr_frame));
#if DEBUG & 256
{ where(); printf("ip_write.c: eth_write(...)= %d\n", result); }
#endif
if (result == NW_SUSPEND)
{
ip_port->ip_dl.dl_eth.de_flags |= IEF_WRITE_SP;
return;
}
} while (!ip_port->ip_dl.dl_eth.de_wr_frame);
ip_port->ip_dl.dl_eth.de_flags &= ~IEF_WRITE_IP;
}
PRIVATE void dll_eth_arp_func (port, ethaddr)
int port;
ether_addr_t *ethaddr;
{
ip_port_t *ip_port;
#if DEBUG & 256
{ where(); printf("ip_write.c: dll_eth_arp_func(port= %d, ...)\n",
port); }
#endif
ip_port= &ip_port_table[port];
if (ethaddr && ip_port->ip_dl.dl_eth.de_arp_pack)
{
ip_port->ip_dl.dl_eth.de_arp_ethaddr= *ethaddr;
ip_port->ip_dl.dl_eth.de_flags |= IEF_ARP_COMPL;
}
else
{
if (ip_port->ip_dl.dl_eth.de_arp_pack)
{
bf_afree(ip_port->ip_dl.dl_eth.de_arp_pack);
ip_port->ip_dl.dl_eth.de_arp_pack= 0;
}
ip_port->ip_dl.dl_eth.de_flags &= ~IEF_ARP_MASK;
}
if (!(ip_port->ip_dl.dl_eth.de_flags & IEF_WRITE_IP))
dll_eth_write_frame(ip_port);
}
PRIVATE void dll_eth_get_work(ip_port)
ip_port_t *ip_port;
{
int i;
ip_fd_t *ip_fd;
if (ip_port->ip_dl.dl_eth.de_wr_frag)
return;
if ((netbroad_flags & NF_INUSE) && netbroad_port == ip_port)
{
restart_netbroadcast();
if (ip_port->ip_dl.dl_eth.de_wr_frag)
return;
}
if (ip_port->ip_dl.dl_eth.de_flags & IEF_ARP_COMPL)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -