📄 ip_eth.c
字号:
ip_port->ip_mtu + sizeof(*eth_hdr)) { r= eth_send(ip_port->ip_dl.dl_eth.de_fd, eth_pack, pack_size); if (r == NW_OK) return NW_OK; /* A non-blocking send is not possible, start a regular * send. */ assert(r == NW_WOULDBLOCK); ip_port->ip_dl.dl_eth.de_frame= eth_pack; r= eth_write(ip_port->ip_dl.dl_eth.de_fd, pack_size); if (r == NW_SUSPEND) { assert(!(ip_port->ip_dl.dl_eth.de_flags & IEF_WRITE_SP)); ip_port->ip_dl.dl_eth.de_flags |= IEF_WRITE_SP; } assert(r == NW_OK || r == NW_SUSPEND); return NW_OK; } /* Enqueue the packet, and store the current time, in the * space for the ethernet source address. */ t= get_time(); assert(sizeof(t) <= sizeof(eth_hdr->eh_src)); memcpy(ð_hdr->eh_src, &t, sizeof(t)); eth_pack->acc_ext_link= NULL; if (ip_port->ip_dl.dl_eth.de_q_head == NULL) ip_port->ip_dl.dl_eth.de_q_head= eth_pack; else { ip_port->ip_dl.dl_eth.de_q_tail->acc_ext_link= eth_pack; } ip_port->ip_dl.dl_eth.de_q_tail= eth_pack; if (ip_port->ip_dl.dl_eth.de_frame == NULL) ipeth_restart_send(ip_port); return NW_OK;}PRIVATE void ipeth_restart_send(ip_port)ip_port_t *ip_port;{ time_t now, enq_time; int i, r; acc_t *eth_pack, *ip_pack, *next_eth_pack, *next_part, *tail; size_t pack_size; eth_hdr_t *eth_hdr, *next_eth_hdr; u32_t *p; now= get_time(); while (ip_port->ip_dl.dl_eth.de_q_head != NULL) { eth_pack= ip_port->ip_dl.dl_eth.de_q_head; ip_port->ip_dl.dl_eth.de_q_head= eth_pack->acc_ext_link; eth_hdr= (eth_hdr_t *)ptr2acc_data(eth_pack); pack_size= bf_bufsize(eth_pack); if (pack_size > ip_port->ip_mtu+sizeof(*eth_hdr)) { /* Split the IP packet */ assert(eth_pack->acc_linkC == 1); ip_pack= eth_pack->acc_next; eth_pack->acc_next= NULL; next_part= ip_pack; ip_pack= NULL; ip_pack= ip_split_pack(ip_port, &next_part, ip_port->ip_mtu); if (ip_pack == NULL) { bf_afree(eth_pack); continue; } eth_pack->acc_next= ip_pack; ip_pack= NULL; /* Allocate new ethernet header */ next_eth_pack= bf_memreq(sizeof(*next_eth_hdr)); next_eth_hdr= (eth_hdr_t *)ptr2acc_data(next_eth_pack); *next_eth_hdr= *eth_hdr; next_eth_pack->acc_next= next_part; next_eth_pack->acc_ext_link= NULL; if (ip_port->ip_dl.dl_eth.de_q_head == NULL) ip_port->ip_dl.dl_eth.de_q_head= next_eth_pack; else { ip_port->ip_dl.dl_eth.de_q_tail->acc_ext_link= next_eth_pack; } ip_port->ip_dl.dl_eth.de_q_tail= next_eth_pack; pack_size= bf_bufsize(eth_pack); } memcpy(&enq_time, ð_hdr->eh_src, sizeof(enq_time)); if (enq_time + HZ < now) { r= ipeth_update_ttl(enq_time, now, eth_pack); if (r == ETIMEDOUT) { ip_pack= bf_delhead(eth_pack, sizeof(*eth_hdr)); eth_pack= NULL; icmp_snd_time_exceeded(ip_port->ip_port, ip_pack, ICMP_TTL_EXC); continue; } assert(r == NW_OK); } 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); pack_size= ETH_MIN_PACK_SIZE; } assert(ip_port->ip_dl.dl_eth.de_frame == NULL); r= eth_send(ip_port->ip_dl.dl_eth.de_fd, eth_pack, pack_size); if (r == NW_OK) continue; /* A non-blocking send is not possible, start a regular * send. */ assert(r == NW_WOULDBLOCK); ip_port->ip_dl.dl_eth.de_frame= eth_pack; r= eth_write(ip_port->ip_dl.dl_eth.de_fd, pack_size); if (r == NW_SUSPEND) { assert(!(ip_port->ip_dl.dl_eth.de_flags & IEF_WRITE_SP)); ip_port->ip_dl.dl_eth.de_flags |= IEF_WRITE_SP; return; } assert(r == NW_OK); }}PRIVATE void ipeth_arp_reply(ip_port_nr, ipaddr, eth_addr)int ip_port_nr;ipaddr_t ipaddr;ether_addr_t *eth_addr;{ acc_t *prev, *eth_pack; int r; xmit_hdr_t *xmit_hdr; ip_port_t *ip_port; time_t t; eth_hdr_t *eth_hdr; ether_addr_t tmp_eth_addr; assert (ip_port_nr >= 0 && ip_port_nr < ip_conf_nr); ip_port= &ip_port_table[ip_port_nr]; for (;;) { for (prev= 0, eth_pack= ip_port->ip_dl.dl_eth.de_arp_head; eth_pack; prev= eth_pack, eth_pack= eth_pack->acc_ext_link) { xmit_hdr= (xmit_hdr_t *)ptr2acc_data(eth_pack); if (xmit_hdr->xh_ipaddr == ipaddr) break; } if (eth_pack == NULL) { /* No packet found. */ break; } /* Delete packet from the queue. */ if (prev == NULL) { ip_port->ip_dl.dl_eth.de_arp_head= eth_pack->acc_ext_link; } else { prev->acc_ext_link= eth_pack->acc_ext_link; if (prev->acc_ext_link == NULL) ip_port->ip_dl.dl_eth.de_arp_tail= prev; } if (eth_addr == NULL) { /* Destination is unreachable, delete packet. */ bf_afree(eth_pack); continue; } /* Fill in the ethernet address and put the packet on the * transmit queue. */ t= xmit_hdr->xh_time; eth_hdr= (eth_hdr_t *)ptr2acc_data(eth_pack); eth_hdr->eh_dst= *eth_addr; memcpy(ð_hdr->eh_src, &t, sizeof(t)); eth_pack->acc_ext_link= NULL; if (ip_port->ip_dl.dl_eth.de_q_head == NULL) ip_port->ip_dl.dl_eth.de_q_head= eth_pack; else { ip_port->ip_dl.dl_eth.de_q_tail->acc_ext_link= eth_pack; } ip_port->ip_dl.dl_eth.de_q_tail= eth_pack; } /* Try to get some more ARPs in progress. */ while (ip_port->ip_dl.dl_eth.de_arp_head) { eth_pack= ip_port->ip_dl.dl_eth.de_arp_head; xmit_hdr= (xmit_hdr_t *)ptr2acc_data(eth_pack); r= arp_ip_eth(ip_port->ip_dl.dl_eth.de_port, xmit_hdr->xh_ipaddr, &tmp_eth_addr); if (r == NW_SUSPEND) break; /* Normal case */ /* Dequeue the packet */ ip_port->ip_dl.dl_eth.de_arp_head= eth_pack->acc_ext_link; if (r == EDSTNOTRCH) { bf_afree(eth_pack); continue; } assert(r == NW_OK); /* Fill in the ethernet address and put the packet on the * transmit queue. */ t= xmit_hdr->xh_time; eth_hdr= (eth_hdr_t *)ptr2acc_data(eth_pack); eth_hdr->eh_dst= tmp_eth_addr; memcpy(ð_hdr->eh_src, &t, sizeof(t)); eth_pack->acc_ext_link= NULL; if (ip_port->ip_dl.dl_eth.de_q_head == NULL) ip_port->ip_dl.dl_eth.de_q_head= eth_pack; else { ip_port->ip_dl.dl_eth.de_q_tail->acc_ext_link= eth_pack; } ip_port->ip_dl.dl_eth.de_q_tail= eth_pack; } /* Restart sending ethernet packets. */ if (ip_port->ip_dl.dl_eth.de_frame == NULL) ipeth_restart_send(ip_port);}PRIVATE int ipeth_update_ttl(enq_time, now, eth_pack)time_t enq_time;time_t now;acc_t *eth_pack;{ int ttl_diff; ip_hdr_t *ip_hdr; u32_t sum; u16_t word; acc_t *ip_pack; ttl_diff= (now-enq_time)/HZ; enq_time += ttl_diff*HZ; assert(enq_time <= now && enq_time + HZ > now); ip_pack= eth_pack->acc_next; assert(ip_pack->acc_length >= sizeof(*ip_hdr)); assert(ip_pack->acc_linkC == 1 && ip_pack->acc_buffer->buf_linkC == 1); ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_pack); if (ip_hdr->ih_ttl <= ttl_diff) return ETIMEDOUT; sum= (u16_t)~ip_hdr->ih_hdr_chk; word= *(u16_t *)&ip_hdr->ih_ttl; if (word > sum) sum += 0xffff - word; else sum -= word; ip_hdr->ih_ttl -= ttl_diff; word= *(u16_t *)&ip_hdr->ih_ttl; sum += word; if (sum > 0xffff) sum -= 0xffff; assert(!(sum & 0xffff0000)); ip_hdr->ih_hdr_chk= ~sum; assert(ip_hdr->ih_ttl > 0); return NW_OK;}PRIVATE void do_eth_read(ip_port)ip_port_t *ip_port;{ int result; assert(!(ip_port->ip_dl.dl_eth.de_flags & IEF_READ_IP)); for (;;) { ip_port->ip_dl.dl_eth.de_flags |= IEF_READ_IP; result= eth_read (ip_port->ip_dl.dl_eth.de_fd, ETH_MAX_PACK_SIZE); if (result == NW_SUSPEND) { assert(!(ip_port->ip_dl.dl_eth.de_flags & IEF_READ_SP)); ip_port->ip_dl.dl_eth.de_flags |= IEF_READ_SP; return; } ip_port->ip_dl.dl_eth.de_flags &= ~IEF_READ_IP; if (result<0) { return; } }}PRIVATE void ip_eth_arrived(port, pack, pack_size)int port;acc_t *pack;size_t pack_size;{ int broadcast; ip_port_t *ip_port; ip_port= &ip_port_table[port]; broadcast= (*(u8_t *)ptr2acc_data(pack) & 1); pack= bf_delhead(pack, ETH_HDR_SIZE); if (broadcast) ip_arrived_broadcast(ip_port, pack); else ip_arrived(ip_port, pack);}/* * $PchId: ip_eth.c,v 1.25 2005/06/28 14:18:10 philip Exp $ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -