📄 ip_eth.c
字号:
/*generic/ip_eth.cEthernet specific part of the IP implementationCreated: Apr 22, 1993 by Philip HomburgCopyright 1995 Philip Homburg*/#include "inet.h"#include "type.h"#include "arp.h"#include "assert.h"#include "buf.h"#include "clock.h"#include "eth.h"#include "event.h"#include "icmp_lib.h"#include "io.h"#include "ip.h"#include "ip_int.h"THIS_FILEtypedef struct xmit_hdr{ time_t xh_time; ipaddr_t xh_ipaddr;} xmit_hdr_t;PRIVATE ether_addr_t broadcast_ethaddr={ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }};PRIVATE ether_addr_t ipmulticast_ethaddr={ { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }};FORWARD void do_eth_read ARGS(( ip_port_t *port ));FORWARD acc_t *get_eth_data ARGS(( int fd, size_t offset, size_t count, int for_ioctl ));FORWARD int put_eth_data ARGS(( int fd, size_t offset, acc_t *data, int for_ioctl ));FORWARD void ipeth_main ARGS(( ip_port_t *port ));FORWARD void ipeth_set_ipaddr ARGS(( ip_port_t *port ));FORWARD void ipeth_restart_send ARGS(( ip_port_t *ip_port ));FORWARD int ipeth_send ARGS(( struct ip_port *ip_port, ipaddr_t dest, acc_t *pack, int type ));FORWARD void ipeth_arp_reply ARGS(( int ip_port_nr, ipaddr_t ipaddr, ether_addr_t *dst_ether_ptr ));FORWARD int ipeth_update_ttl ARGS(( time_t enq_time, time_t now, acc_t *eth_pack ));FORWARD void ip_eth_arrived ARGS(( int port, acc_t *pack, size_t pack_size ));PUBLIC int ipeth_init(ip_port)ip_port_t *ip_port;{ assert(BUF_S >= sizeof(xmit_hdr_t)); assert(BUF_S >= sizeof(eth_hdr_t)); ip_port->ip_dl.dl_eth.de_fd= eth_open(ip_port-> ip_dl.dl_eth.de_port, ip_port->ip_port, get_eth_data, put_eth_data, ip_eth_arrived, 0 /* no select_res */); if (ip_port->ip_dl.dl_eth.de_fd < 0) { DBLOCK(1, printf("ip.c: unable to open eth port\n")); return -1; } ip_port->ip_dl.dl_eth.de_state= IES_EMPTY; ip_port->ip_dl.dl_eth.de_flags= IEF_EMPTY; ip_port->ip_dl.dl_eth.de_q_head= NULL; ip_port->ip_dl.dl_eth.de_q_tail= NULL; ip_port->ip_dl.dl_eth.de_arp_head= NULL; ip_port->ip_dl.dl_eth.de_arp_tail= NULL; ip_port->ip_dev_main= ipeth_main; ip_port->ip_dev_set_ipaddr= ipeth_set_ipaddr; ip_port->ip_dev_send= ipeth_send; ip_port->ip_mtu= ETH_MAX_PACK_SIZE-ETH_HDR_SIZE; ip_port->ip_mtu_max= ip_port->ip_mtu; return 0;}PRIVATE void ipeth_main(ip_port)ip_port_t *ip_port;{ int result; switch (ip_port->ip_dl.dl_eth.de_state) { case IES_EMPTY: ip_port->ip_dl.dl_eth.de_state= IES_SETPROTO; result= eth_ioctl(ip_port->ip_dl.dl_eth.de_fd, NWIOSETHOPT); if (result == NW_SUSPEND) ip_port->ip_dl.dl_eth.de_flags |= IEF_SUSPEND; if (result<0) { DBLOCK(1, printf("eth_ioctl(..,0x%lx)=%d\n", (unsigned long)NWIOSETHOPT, result)); return; } if (ip_port->ip_dl.dl_eth.de_state != IES_SETPROTO) return; /* drops through */ case IES_SETPROTO: result= arp_set_cb(ip_port->ip_dl.dl_eth.de_port, ip_port->ip_port, ipeth_arp_reply); if (result != NW_OK) { printf("ipeth_main: arp_set_cb failed: %d\n", result); return; } /* Wait until the interface is configured up. */ ip_port->ip_dl.dl_eth.de_state= IES_GETIPADDR; if (!(ip_port->ip_flags & IPF_IPADDRSET)) { ip_port->ip_dl.dl_eth.de_flags |= IEF_SUSPEND; return; } /* fall through */ case IES_GETIPADDR: ip_port->ip_dl.dl_eth.de_state= IES_MAIN; do_eth_read(ip_port); return; default: ip_panic(( "unknown state: %d", ip_port->ip_dl.dl_eth.de_state)); }}PRIVATE acc_t *get_eth_data (fd, offset, count, for_ioctl)int fd;size_t offset;size_t count;int for_ioctl;{ ip_port_t *ip_port; acc_t *data; int result; ip_port= &ip_port_table[fd]; switch (ip_port->ip_dl.dl_eth.de_state) { case IES_SETPROTO: if (!count) { result= (int)offset; if (result<0) { ip_port->ip_dl.dl_eth.de_state= IES_ERROR; break; } if (ip_port->ip_dl.dl_eth.de_flags & IEF_SUSPEND) ipeth_main(ip_port); return NW_OK; } assert ((!offset) && (count == sizeof(struct nwio_ethopt))); { struct nwio_ethopt *ethopt; acc_t *acc; acc= bf_memreq(sizeof(*ethopt)); ethopt= (struct nwio_ethopt *)ptr2acc_data(acc); ethopt->nweo_flags= NWEO_COPY|NWEO_EN_BROAD| NWEO_EN_MULTI|NWEO_TYPESPEC; ethopt->nweo_type= HTONS(ETH_IP_PROTO); return acc; } case IES_MAIN: if (!count) { result= (int)offset; if (result<0) ip_warning(( "error on write: %d\n", result )); bf_afree (ip_port->ip_dl.dl_eth.de_frame); ip_port->ip_dl.dl_eth.de_frame= 0; if (ip_port->ip_dl.dl_eth.de_flags & IEF_WRITE_SP) { ip_port->ip_dl.dl_eth.de_flags &= ~IEF_WRITE_SP; ipeth_restart_send(ip_port); } return NW_OK; } data= bf_cut (ip_port->ip_dl.dl_eth.de_frame, offset, count); assert (data); return data; default: printf( "get_eth_data(%d, 0x%d, 0x%d) called but ip_state=0x%x\n", fd, offset, count, ip_port->ip_dl.dl_eth.de_state); break; } return 0;}PRIVATE int put_eth_data (port, offset, data, for_ioctl)int port;size_t offset;acc_t *data;int for_ioctl;{ ip_port_t *ip_port; int result; ip_port= &ip_port_table[port]; assert(0); if (ip_port->ip_dl.dl_eth.de_flags & IEF_READ_IP) { if (!data) { result= (int)offset; if (result<0) { DBLOCK(1, printf( "ip.c: put_eth_data(..,%d,..)\n", result)); return NW_OK; } if (ip_port->ip_dl.dl_eth.de_flags & IEF_READ_SP) { ip_port->ip_dl.dl_eth.de_flags &= ~(IEF_READ_IP|IEF_READ_SP); do_eth_read(ip_port); } else ip_port->ip_dl.dl_eth.de_flags &= ~IEF_READ_IP; return NW_OK; } assert (!offset); /* Warning: the above assertion is illegal; puts and gets of data can be brokenup in any piece the server likes. However we assume that the server is eth.c and it transfers only whole packets. */ ip_eth_arrived(port, data, bf_bufsize(data)); return NW_OK; } printf("ip_port->ip_dl.dl_eth.de_state= 0x%x", ip_port->ip_dl.dl_eth.de_state); ip_panic (( "strange status" ));}PRIVATE void ipeth_set_ipaddr(ip_port)ip_port_t *ip_port;{ arp_set_ipaddr (ip_port->ip_dl.dl_eth.de_port, ip_port->ip_ipaddr); if (ip_port->ip_dl.dl_eth.de_state == IES_GETIPADDR) ipeth_main(ip_port);}PRIVATE int ipeth_send(ip_port, dest, pack, type)struct ip_port *ip_port;ipaddr_t dest;acc_t *pack;int type;{ int i, r; acc_t *eth_pack, *tail; size_t pack_size; eth_hdr_t *eth_hdr; xmit_hdr_t *xmit_hdr; ipaddr_t hostpart, tmpaddr; time_t t; u32_t *p; /* Start optimistic: the arp will succeed without blocking and the * ethernet packet can be sent without blocking also. Start with * the allocation of the ethernet header. */ eth_pack= bf_memreq(sizeof(*eth_hdr)); assert(eth_pack->acc_next == NULL); eth_pack->acc_next= pack; pack_size= bf_bufsize(eth_pack); if (pack_size<ETH_MIN_PACK_SIZE) { tail= bf_memreq(ETH_MIN_PACK_SIZE-pack_size); /* Clear padding */ for (i= (ETH_MIN_PACK_SIZE-pack_size)/sizeof(*p), p= (u32_t *)ptr2acc_data(tail); i >= 0; i--, p++) { *p= 0xdeadbeef; } eth_pack= bf_append(eth_pack, tail); } eth_hdr= (eth_hdr_t *)ptr2acc_data(eth_pack); /* Lookup the ethernet address */ if (type != IP_LT_NORMAL) { if (type == IP_LT_BROADCAST) eth_hdr->eh_dst= broadcast_ethaddr; else { tmpaddr= ntohl(dest); eth_hdr->eh_dst= ipmulticast_ethaddr; eth_hdr->eh_dst.ea_addr[5]= tmpaddr & 0xff; eth_hdr->eh_dst.ea_addr[4]= (tmpaddr >> 8) & 0xff; eth_hdr->eh_dst.ea_addr[3]= (tmpaddr >> 16) & 0x7f; } } else { if ((dest ^ ip_port->ip_ipaddr) & ip_port->ip_subnetmask) { ip_panic(( "invalid destination" )); } hostpart= (dest & ~ip_port->ip_subnetmask); assert(dest != ip_port->ip_ipaddr); r= arp_ip_eth(ip_port->ip_dl.dl_eth.de_port, dest, ð_hdr->eh_dst); if (r == NW_SUSPEND) { /* Unfortunately, the arp takes some time, use * the ethernet header to store the next hop * ip address and the current time. */ xmit_hdr= (xmit_hdr_t *)eth_hdr; xmit_hdr->xh_time= get_time(); xmit_hdr->xh_ipaddr= dest; eth_pack->acc_ext_link= NULL; if (ip_port->ip_dl.dl_eth.de_arp_head == NULL) ip_port->ip_dl.dl_eth.de_arp_head= eth_pack; else { ip_port->ip_dl.dl_eth.de_arp_tail-> acc_ext_link= eth_pack; } ip_port->ip_dl.dl_eth.de_arp_tail= eth_pack; return NW_OK; } if (r == EDSTNOTRCH) { bf_afree(eth_pack); return EDSTNOTRCH; } assert(r == NW_OK); } /* If we have no write in progress, we can try to send the ethernet * packet using eth_send. If the IP packet is larger than mtu, * enqueue the packet and let ipeth_restart_send deal with it. */ pack_size= bf_bufsize(eth_pack); if (ip_port->ip_dl.dl_eth.de_frame == NULL && pack_size <=
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -