📄 arp.c
字号:
memcpy (arp->a46_spa, &tpa, sizeof(ipaddr_t)); arp->a46_tha= ce->ac_ethaddr; memcpy (arp->a46_tpa, &ce->ac_ipaddr, sizeof(ipaddr_t)); assert(data->acc_linkC == 1); data->acc_ext_link= arp_port->ap_sendlist; arp_port->ap_sendlist= data; data= NULL; if (!(arp_port->ap_flags & APF_ARP_WR_IP)) setup_write(arp_port); }}PRIVATE void client_reply (arp_port, ipaddr, ethaddr)arp_port_t *arp_port;ipaddr_t ipaddr;ether_addr_t *ethaddr;{ (*arp_port->ap_arp_func)(arp_port->ap_ip_port, ipaddr, ethaddr);}PRIVATE arp_cache_t *find_cache_ent (arp_port, ipaddr)arp_port_t *arp_port;ipaddr_t ipaddr;{ arp_cache_t *ce; int i; unsigned hash; hash= (ipaddr >> 24) ^ (ipaddr >> 16) ^ (ipaddr >> 8) ^ ipaddr; hash &= ARP_HASH_MASK; ce= arp_hash[hash].ahe_row[0]; if (ce && ce->ac_ipaddr == ipaddr && ce->ac_port == arp_port && ce->ac_state != ACS_UNUSED) { return ce; } for (i= 1; i<ARP_HASH_WIDTH; i++) { ce= arp_hash[hash].ahe_row[i]; if (!ce || ce->ac_ipaddr != ipaddr || ce->ac_port != arp_port || ce->ac_state == ACS_UNUSED) { continue; } arp_hash[hash].ahe_row[i]= arp_hash[hash].ahe_row[0]; arp_hash[hash].ahe_row[0]= ce; return ce; } for (i=0, ce= arp_cache; i<arp_cache_nr; i++, ce++) { if (ce->ac_state != ACS_UNUSED && ce->ac_port == arp_port && ce->ac_ipaddr == ipaddr) { for (i= ARP_HASH_WIDTH-1; i>0; i--) { arp_hash[hash].ahe_row[i]= arp_hash[hash].ahe_row[i-1]; } assert(i == 0); arp_hash[hash].ahe_row[0]= ce; return ce; } } return NULL;}PRIVATE arp_cache_t *alloc_cache_ent(flags)int flags;{ arp_cache_t *cache, *old; int i; old= NULL; for (i=0, cache= arp_cache; i<arp_cache_nr; i++, cache++) { if (cache->ac_state == ACS_UNUSED) { old= cache; break; } if (cache->ac_state == ACS_INCOMPLETE) continue; if (cache->ac_flags & ACF_PERM) continue; if (!old || cache->ac_lastuse < old->ac_lastuse) old= cache; } assert(old); if (!flags) return old; /* Get next permanent entry */ for (i=0, cache= arp_cache; i<arp_cache_nr; i++, cache++) { if (cache->ac_state == ACS_UNUSED) break; if (cache->ac_flags & ACF_PERM) continue; break; } if (i >= arp_cache_nr/2) return NULL; /* Too many entries */ if (cache != old) { assert(old > cache); *old= *cache; old= cache; } if (!(flags & ACF_PUB)) return old; /* Get first nonpublished entry */ for (i=0, cache= arp_cache; i<arp_cache_nr; i++, cache++) { if (cache->ac_state == ACS_UNUSED) break; if (cache->ac_flags & ACF_PUB) continue; break; } if (cache != old) { assert(old > cache); *old= *cache; old= cache; } return old;}PUBLIC void arp_set_ipaddr (eth_port, ipaddr)int eth_port;ipaddr_t ipaddr;{ arp_port_t *arp_port; if (eth_port < 0 || eth_port >= eth_conf_nr) return; arp_port= &arp_port_table[eth_port]; arp_port->ap_ipaddr= ipaddr; arp_port->ap_flags |= APF_INADDR_SET; arp_port->ap_flags &= ~APF_SUSPEND; if (arp_port->ap_state == APS_GETADDR) arp_main(arp_port);}PUBLIC int arp_set_cb(eth_port, ip_port, arp_func)int eth_port;int ip_port;arp_func_t arp_func;{ int i; arp_port_t *arp_port; assert(eth_port >= 0); if (eth_port >= eth_conf_nr) return ENXIO; arp_port= &arp_port_table[eth_port]; arp_port->ap_eth_port= eth_port; arp_port->ap_ip_port= ip_port; arp_port->ap_state= APS_INITIAL; arp_port->ap_flags= APF_EMPTY; arp_port->ap_arp_func= arp_func; arp_port->ap_sendpkt= NULL; arp_port->ap_sendlist= NULL; arp_port->ap_reclist= NULL; for (i= 0; i<AP_REQ_NR; i++) arp_port->ap_req[i].ar_entry= -1; ev_init(&arp_port->ap_event); arp_main(arp_port); return NW_OK;}PUBLIC int arp_ip_eth (eth_port, ipaddr, ethaddr)int eth_port;ipaddr_t ipaddr;ether_addr_t *ethaddr;{ int i, ref; arp_port_t *arp_port; struct arp_req *reqp; arp_cache_t *ce; time_t curr_time; assert(eth_port >= 0 && eth_port < eth_conf_nr); arp_port= &arp_port_table[eth_port]; assert(arp_port->ap_state == APS_ARPMAIN || (printf("arp[%d]: ap_state= %d\n", arp_port-arp_port_table, arp_port->ap_state), 0)); curr_time= get_time(); ce= find_cache_ent (arp_port, ipaddr); if (ce && ce->ac_expire < curr_time) { assert(ce->ac_state != ACS_INCOMPLETE); /* Check whether there is enough space for an ARP * request or not. */ for (i= 0, reqp= arp_port->ap_req; i<AP_REQ_NR; i++, reqp++) { if (reqp->ar_entry < 0) break; } if (i < AP_REQ_NR) { /* Okay, expire this entry. */ ce->ac_state= ACS_UNUSED; ce= NULL; } else { /* Continue using this entry for a while */ printf("arp[%d]: Overloaded! Keeping entry for ", arp_port-arp_port_table); writeIpAddr(ipaddr); printf("\n"); ce->ac_expire= curr_time+ARP_NOTRCH_EXP_TIME; } } if (ce) { /* Found an entry. This entry should be valid, unreachable * or incomplete. */ ce->ac_lastuse= curr_time; if (ce->ac_state == ACS_VALID) { *ethaddr= ce->ac_ethaddr; return NW_OK; } if (ce->ac_state == ACS_UNREACHABLE) return EDSTNOTRCH; assert(ce->ac_state == ACS_INCOMPLETE); return NW_SUSPEND; } /* Find an empty slot for an ARP request */ for (i= 0, reqp= arp_port->ap_req; i<AP_REQ_NR; i++, reqp++) { if (reqp->ar_entry < 0) break; } if (i >= AP_REQ_NR) { /* We should be able to report that this ARP request * cannot be accepted. At the moment we just return SUSPEND. */ return NW_SUSPEND; } ref= (eth_port*AP_REQ_NR + i); ce= alloc_cache_ent(ACF_EMPTY); ce->ac_flags= 0; ce->ac_state= ACS_INCOMPLETE; ce->ac_ipaddr= ipaddr; ce->ac_port= arp_port; ce->ac_expire= curr_time+ARP_EXP_TIME; ce->ac_lastuse= curr_time; reqp->ar_entry= ce-arp_cache; reqp->ar_req_count= -1; /* Send the first packet by expiring the timer */ clck_timer(&reqp->ar_timer, 1, arp_timeout, ref); return NW_SUSPEND;}PUBLIC int arp_ioctl (eth_port, fd, req, get_userdata, put_userdata)int eth_port;int fd;ioreq_t req;get_userdata_t get_userdata;put_userdata_t put_userdata;{ arp_port_t *arp_port; arp_cache_t *ce, *cache; acc_t *data; nwio_arp_t *arp_iop; int entno, result, ac_flags; u32_t flags; ipaddr_t ipaddr; time_t curr_time; assert(eth_port >= 0 && eth_port < eth_conf_nr); arp_port= &arp_port_table[eth_port]; assert(arp_port->ap_state == APS_ARPMAIN || (printf("arp[%d]: ap_state= %d\n", arp_port-arp_port_table, arp_port->ap_state), 0)); switch(req) { case NWIOARPGIP: data= (*get_userdata)(fd, 0, sizeof(*arp_iop), TRUE); if (data == NULL) return EFAULT; data= bf_packIffLess(data, sizeof(*arp_iop)); arp_iop= (nwio_arp_t *)ptr2acc_data(data); ipaddr= arp_iop->nwa_ipaddr; ce= NULL; /* lint */ for (entno= 0; entno < arp_cache_nr; entno++) { ce= &arp_cache[entno]; if (ce->ac_state == ACS_UNUSED || ce->ac_port != arp_port) { continue; } if (ce->ac_ipaddr == ipaddr) break; } if (entno == arp_cache_nr) { /* Also report the address of this interface */ if (ipaddr != arp_port->ap_ipaddr) { bf_afree(data); return ENOENT; } arp_iop->nwa_entno= arp_cache_nr; arp_iop->nwa_ipaddr= ipaddr; arp_iop->nwa_ethaddr= arp_port->ap_ethaddr; arp_iop->nwa_flags= NWAF_PERM | NWAF_PUB; } else { arp_iop->nwa_entno= entno+1; arp_iop->nwa_ipaddr= ce->ac_ipaddr; arp_iop->nwa_ethaddr= ce->ac_ethaddr; arp_iop->nwa_flags= 0; if (ce->ac_state == ACS_INCOMPLETE) arp_iop->nwa_flags |= NWAF_INCOMPLETE; if (ce->ac_state == ACS_UNREACHABLE) arp_iop->nwa_flags |= NWAF_DEAD; if (ce->ac_flags & ACF_PERM) arp_iop->nwa_flags |= NWAF_PERM; if (ce->ac_flags & ACF_PUB) arp_iop->nwa_flags |= NWAF_PUB; } result= (*put_userdata)(fd, 0, data, TRUE); return result; case NWIOARPGNEXT: data= (*get_userdata)(fd, 0, sizeof(*arp_iop), TRUE); if (data == NULL) return EFAULT; data= bf_packIffLess(data, sizeof(*arp_iop)); arp_iop= (nwio_arp_t *)ptr2acc_data(data); entno= arp_iop->nwa_entno; if (entno < 0) entno= 0; ce= NULL; /* lint */ for (; entno < arp_cache_nr; entno++) { ce= &arp_cache[entno]; if (ce->ac_state == ACS_UNUSED || ce->ac_port != arp_port) { continue; } break; } if (entno == arp_cache_nr) { bf_afree(data); return ENOENT; } arp_iop->nwa_entno= entno+1; arp_iop->nwa_ipaddr= ce->ac_ipaddr; arp_iop->nwa_ethaddr= ce->ac_ethaddr; arp_iop->nwa_flags= 0; if (ce->ac_state == ACS_INCOMPLETE) arp_iop->nwa_flags |= NWAF_INCOMPLETE; if (ce->ac_state == ACS_UNREACHABLE) arp_iop->nwa_flags |= NWAF_DEAD; if (ce->ac_flags & ACF_PERM) arp_iop->nwa_flags |= NWAF_PERM; if (ce->ac_flags & ACF_PUB) arp_iop->nwa_flags |= NWAF_PUB; result= (*put_userdata)(fd, 0, data, TRUE); return result; case NWIOARPSIP: data= (*get_userdata)(fd, 0, sizeof(*arp_iop), TRUE); if (data == NULL) return EFAULT; data= bf_packIffLess(data, sizeof(*arp_iop)); arp_iop= (nwio_arp_t *)ptr2acc_data(data); ipaddr= arp_iop->nwa_ipaddr; if (find_cache_ent(arp_port, ipaddr)) { bf_afree(data); return EEXIST; } flags= arp_iop->nwa_flags; ac_flags= ACF_EMPTY; if (flags & NWAF_PERM) ac_flags |= ACF_PERM; if (flags & NWAF_PUB) ac_flags |= ACF_PUB|ACF_PERM; /* Allocate a cache entry */ ce= alloc_cache_ent(ac_flags); if (ce == NULL) { bf_afree(data); return ENOMEM; } ce->ac_flags= ac_flags; ce->ac_state= ACS_VALID; ce->ac_ethaddr= arp_iop->nwa_ethaddr; ce->ac_ipaddr= arp_iop->nwa_ipaddr; ce->ac_port= arp_port; curr_time= get_time(); ce->ac_expire= curr_time+ARP_EXP_TIME; ce->ac_lastuse= curr_time; bf_afree(data); return 0; case NWIOARPDIP: data= (*get_userdata)(fd, 0, sizeof(*arp_iop), TRUE); if (data == NULL) return EFAULT; data= bf_packIffLess(data, sizeof(*arp_iop)); arp_iop= (nwio_arp_t *)ptr2acc_data(data); ipaddr= arp_iop->nwa_ipaddr; bf_afree(data); data= NULL; ce= find_cache_ent(arp_port, ipaddr); if (!ce) return ENOENT; if (ce->ac_state == ACS_INCOMPLETE) return EINVAL; ac_flags= ce->ac_flags; if (ac_flags & ACF_PUB) { /* Make sure entry is at the end of published * entries. */ for (entno= 0, cache= arp_cache; entno<arp_cache_nr; entno++, cache++) { if (cache->ac_state == ACS_UNUSED) break; if (cache->ac_flags & ACF_PUB) continue; break; } assert(cache > arp_cache); cache--; if (cache != ce) { assert(cache > ce); *ce= *cache; ce= cache; } } if (ac_flags & ACF_PERM) { /* Make sure entry is at the end of permanent * entries. */ for (entno= 0, cache= arp_cache; entno<arp_cache_nr; entno++, cache++) { if (cache->ac_state == ACS_UNUSED) break; if (cache->ac_flags & ACF_PERM) continue; break; } assert(cache > arp_cache); cache--; if (cache != ce) { assert(cache > ce); *ce= *cache; ce= cache; } } /* Clear entry */ ce->ac_state= ACS_UNUSED; return 0; default: ip_panic(("arp_ioctl: unknown request 0x%lx", (unsigned long)req)); } return 0;}PRIVATE void arp_timeout (ref, timer)int ref;timer_t *timer;{ int i, port, reqind, acind; arp_port_t *arp_port; arp_cache_t *ce; struct arp_req *reqp; time_t curr_time; acc_t *data; arp46_t *arp; u16_t *p; port= ref / AP_REQ_NR; reqind= ref % AP_REQ_NR; assert(port >= 0 && port <eth_conf_nr); arp_port= &arp_port_table[port]; reqp= &arp_port->ap_req[reqind]; assert (timer == &reqp->ar_timer); acind= reqp->ar_entry; assert(acind >= 0 && acind < arp_cache_nr); ce= &arp_cache[acind]; assert(ce->ac_port == arp_port); assert(ce->ac_state == ACS_INCOMPLETE); if (++reqp->ar_req_count >= MAX_ARP_RETRIES) { curr_time= get_time(); ce->ac_state= ACS_UNREACHABLE; ce->ac_expire= curr_time+ ARP_NOTRCH_EXP_TIME; ce->ac_lastuse= curr_time; clck_untimer(&reqp->ar_timer); reqp->ar_entry= -1; client_reply(arp_port, ce->ac_ipaddr, NULL); return; } data= bf_memreq(sizeof(arp46_t)); arp= (arp46_t *)ptr2acc_data(data); /* Clear padding */ assert(sizeof(arp->a46_data.a46_dummy) % sizeof(*p) == 0); for (i= 0, p= (u16_t *)arp->a46_data.a46_dummy; i < sizeof(arp->a46_data.a46_dummy)/sizeof(*p); i++, p++) { *p= 0xdead; } arp->a46_dstaddr.ea_addr[0]= 0xff; arp->a46_dstaddr.ea_addr[1]= 0xff; arp->a46_dstaddr.ea_addr[2]= 0xff; arp->a46_dstaddr.ea_addr[3]= 0xff; arp->a46_dstaddr.ea_addr[4]= 0xff; arp->a46_dstaddr.ea_addr[5]= 0xff; arp->a46_hdr= HTONS(ARP_ETHERNET); arp->a46_pro= HTONS(ETH_IP_PROTO); arp->a46_hln= 6; arp->a46_pln= 4; arp->a46_op= HTONS(ARP_REQUEST); arp->a46_sha= arp_port->ap_ethaddr; memcpy (arp->a46_spa, &arp_port->ap_ipaddr, sizeof(ipaddr_t)); memset(&arp->a46_tha, '\0', sizeof(ether_addr_t)); memcpy (arp->a46_tpa, &ce->ac_ipaddr, sizeof(ipaddr_t)); assert(data->acc_linkC == 1); data->acc_ext_link= arp_port->ap_sendlist; arp_port->ap_sendlist= data; data= NULL; if (!(arp_port->ap_flags & APF_ARP_WR_IP)) setup_write(arp_port); clck_timer(&reqp->ar_timer, get_time() + ARP_TIMEOUT, arp_timeout, ref);}PRIVATE void arp_buffree(priority)int priority;{ int i; acc_t *pack, *next_pack; arp_port_t *arp_port; for (i= 0, arp_port= arp_port_table; i<eth_conf_nr; i++, arp_port++) { if (priority == ARP_PRI_REC) { next_pack= arp_port->ap_reclist; while(next_pack && next_pack->acc_ext_link) { pack= next_pack; next_pack= pack->acc_ext_link; bf_afree(pack); } if (next_pack) { if (ev_in_queue(&arp_port->ap_event)) { DBLOCK(1, printf( "not freeing ap_reclist, ap_event enqueued\n")); } else { bf_afree(next_pack); next_pack= NULL; } } arp_port->ap_reclist= next_pack; } if (priority == ARP_PRI_SEND) { next_pack= arp_port->ap_sendlist; while(next_pack && next_pack->acc_ext_link) { pack= next_pack; next_pack= pack->acc_ext_link; bf_afree(pack); } if (next_pack) { if (ev_in_queue(&arp_port->ap_event)) { DBLOCK(1, printf( "not freeing ap_sendlist, ap_event enqueued\n")); } else { bf_afree(next_pack); next_pack= NULL; } } arp_port->ap_sendlist= next_pack; } }}#ifdef BUF_CONSISTENCY_CHECKPRIVATE void arp_bufcheck(){ int i; arp_port_t *arp_port; acc_t *pack; for (i= 0, arp_port= arp_port_table; i<eth_conf_nr; i++, arp_port++) { for (pack= arp_port->ap_reclist; pack; pack= pack->acc_ext_link) { bf_check_acc(pack); } for (pack= arp_port->ap_sendlist; pack; pack= pack->acc_ext_link) { bf_check_acc(pack); } }}#endif /* BUF_CONSISTENCY_CHECK *//* * $PchId: arp.c,v 1.22 2005/06/28 14:15:06 philip Exp $ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -