📄 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 2PRIVATE 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"); }#endifassert (!(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 + -