📄 arp.c
字号:
/*arp.c*/#include "inet.h"#include "arp.h"#include "assert.h"#include "buf.h"#include "clock.h"#include "eth.h"#include "io.h"#include "sr.h"#include "type.h"INIT_PANIC();#define ARP_PORT_NR 1#define ARP_CACHE1_NR 8#define ARP_CACHE2_NR 8#define ARP_CACHE3_NR 16#define ARP_CACHE_NR (ARP_CACHE1_NR+ARP_CACHE2_NR+ARP_CACHE3_NR)#define ARP_TYPE1 1#define ARP_TYPE2 2#define ARP_TYPE3 3#define MAX_RARP_RETRIES 5#define MAX_ARP_RETRIES 5#define RARP_TIMEOUT (1*HZ)#define ARP_TIMEOUT (HZ/2+1) /* .5 seconds */#define ARP_EXP_TIME (20L*60L*HZ) /* 20 minutes */#define ARP_NOTRCH_EXP_TIME (2L*60L*HZ) /* 2 minutes */#define ARP_INUSE_OFFSET (60*HZ) /* an entry in the cache can be deleted if its not used for 1 minute */typedef struct arp46{ ether_addr_t a46_dstaddr; ether_addr_t a46_srcaddr; ether_type_t a46_ethtype; union { struct { u16_t a_hdr, a_pro; u8_t a_hln, a_pln; u16_t a_op; ether_addr_t a_sha; u8_t a_spa[4]; ether_addr_t a_tha; u8_t a_tpa[4]; } a46_data; char a46_dummy[ETH_MIN_PACK_SIZE-ETH_HDR_SIZE]; } a46_data;} arp46_t, rarp46_t;#define a46_hdr a46_data.a46_data.a_hdr#define a46_pro a46_data.a46_data.a_pro#define a46_hln a46_data.a46_data.a_hln#define a46_pln a46_data.a46_data.a_pln#define a46_op a46_data.a46_data.a_op#define a46_sha a46_data.a46_data.a_sha#define a46_spa a46_data.a46_data.a_spa#define a46_tha a46_data.a46_data.a_tha#define a46_tpa a46_data.a46_data.a_tpatypedef struct arp_cache{ int ac_flags; int ac_type; ether_addr_t ac_ethaddr; ipaddr_t ac_ipaddr; int ac_eth_port; time_t ac_expire; time_t ac_lastuse;} arp_cache_t;#define ACF_EMPTY 0#define ACF_NETREQ 1#define ACF_NOTRCH 2typedef struct arp_port{ int ap_flags; int ap_state; int ap_eth_port; int ap_eth_fd; int ap_rarp_retries; ether_addr_t ap_ethaddr; ipaddr_t ap_ipaddr; timer_t ap_timer; ether_addr_t ap_write_ethaddr; ipaddr_t ap_write_ipaddr; int ap_write_code; ipaddr_t ap_req_ipaddr; arp_req_func_t ap_req_func; int ap_req_ref; int ap_req_count; rarp_func_t ap_rarp_func; int ap_rarp_ref;} arp_port_t;#define APF_EMPTY 0#define APF_RARP_RD_IP 0x1#define APF_RARP_RD_SP 0x2#define APF_ARP_RD_IP 0x4#define APF_ARP_RD_SP 0x8#define APF_ARP_WR_IP 0x10#define APF_ARP_WR_SP 0x20#define APF_INADDR_SET 0x100#define APF_MORE2WRITE 0x200#define APF_CLIENTREQ 0x400#define APF_RARPREQ 0x800#define APF_CLIENTWRITE 0x1000#define APS_EMPTY 0#define APS_STATMASK 0xff#define APS_GETADDR 0x1#define APS_RARPPROTO 0x2#define APS_RARPWRITE 0x4#define APS_RARPWAIT 0x8#define APS_ARPSTART 0x10#define APS_ARPPROTO 0x20#define APS_ARPMAIN 0x40#define APS_ERROR 0x80#define APS_SUSPEND 0x400FORWARD acc_t *arp_getdata ARGS(( int fd, size_t offset, size_t count, int for_ioctl ));FORWARD int arp_putdata ARGS(( int fd, size_t offset, acc_t *data, int for_ioctl ));FORWARD void arp_main ARGS(( arp_port_t *port ));FORWARD void arp_timeout ARGS(( int fd, timer_t *timer ));FORWARD void rarp_timeout ARGS(( int fd, timer_t *timer ));FORWARD void ipaddr_set ARGS(( arp_port_t *port ));FORWARD void setup_write ARGS(( arp_port_t *port ));FORWARD void setup_read ARGS(( arp_port_t *port ));FORWARD void process_arp_req ARGS(( arp_port_t *port, acc_t *data ));FORWARD void client_reply ARGS(( arp_port_t *port, ether_addr_t *ethaddr ));FORWARD arp_cache_t *find_cache_ent ARGS(( int eth_port, ipaddr_t ipaddr, int level, arp_cache_t **new_ent ));FORWARD void rarp_read_setup ARGS(( arp_port_t *port ));FORWARD void print_arp_cache ARGS(( void ));PRIVATE arp_port_t arp_port_table[ARP_PORT_NR];PRIVATE arp_port_t *arp_port;PRIVATE arp_cache_t arp_cache[ARP_CACHE_NR];PUBLIC void arp_init(){ int i; assert (BUF_S >= sizeof(struct nwio_ethstat)); assert (BUF_S >= sizeof(struct nwio_ethopt)); assert (BUF_S >= sizeof(rarp46_t)); assert (BUF_S >= sizeof(arp46_t)); arp_port_table[0].ap_eth_port= ETH0; for (i=0, arp_port= arp_port_table; i<ARP_PORT_NR; i++, arp_port++) { arp_port->ap_state= APS_EMPTY; arp_port->ap_flags= APF_EMPTY; arp_main(arp_port); }}PRIVATE void arp_main(port)arp_port_t *port;{ int result;#if DEBUG & 256 { where(); printf("in arp_main with status: %d\n", port->ap_state & APS_STATMASK); }#endif switch (port->ap_state & APS_STATMASK) { case APS_EMPTY: port->ap_rarp_retries= 0; port->ap_eth_fd= eth_open(port->ap_eth_port, port-arp_port_table, arp_getdata, arp_putdata); if (port->ap_eth_fd<0) { printf("arp.c: unable to open ethernet\n"); return; } port->ap_state= (port->ap_state & ~(APS_STATMASK|APS_SUSPEND)) | APS_GETADDR; result= eth_ioctl (port->ap_eth_fd, NWIOGETHSTAT); if (result==NW_SUSPEND) port->ap_state |= APS_SUSPEND; if (result<0) {#if DEBUG if (result != NW_SUSPEND) { where(); printf("arp.c: eth_ioctl(..,NWIOGETHSTAT)=%d\n", result); }#endif return; } if ((port->ap_state & APS_STATMASK) != APS_GETADDR) return; /* drop through */ case APS_GETADDR:#if DEBUG & 256 { where(); printf("in arp_main with status: %d\n", port->ap_state & APS_STATMASK); }#endif port->ap_state= (port->ap_state & ~(APS_STATMASK|APS_SUSPEND)) | APS_RARPPROTO; result= eth_ioctl (port->ap_eth_fd, NWIOSETHOPT); if (result==NW_SUSPEND) port->ap_state |= APS_SUSPEND; if (result<0) {#if DEBUG if (result != NW_SUSPEND) { printf("arp.c: eth_ioctl(..,NWIOSETHOPT)=%d\n", result); }#endif return; } if ((port->ap_state & APS_STATMASK) != APS_RARPPROTO) return; /* drop through */ case APS_RARPWAIT:#if DEBUG & 256 { where(); printf("in arp_main with status: %d\n", port->ap_state & APS_STATMASK); }#endif if (port->ap_flags & APF_INADDR_SET) { port->ap_state= (port->ap_state & ~(APS_STATMASK|APS_SUSPEND)) | APS_ARPSTART; arp_main(port); return; } /* drop through */ case APS_RARPPROTO:#if DEBUG & 256 { where(); printf("in arp_main with status: %d\n", port->ap_state & APS_STATMASK); }#endif rarp_read_setup(port); port->ap_state= (port->ap_state & ~(APS_STATMASK|APS_SUSPEND)) | APS_RARPWRITE;#if DEBUG & 256 { where(); printf("doing eth_write\n"); }#endif result= eth_write (port->ap_eth_fd, sizeof(rarp46_t)); if (result == NW_SUSPEND) port->ap_state |= APS_SUSPEND; if (result<0) {#if DEBUG & 256 if (result != NW_SUSPEND) { where(); printf("arp.c: eth_write(..,%d)=%d\n", sizeof(rarp46_t), result); }#endif return; } if ((port->ap_state & APS_STATMASK) != APS_RARPWRITE) return; /* drop through */ case APS_RARPWRITE:#if DEBUG & 256 { where(); printf("in arp_main with status: %d\n", port->ap_state & APS_STATMASK); }#endif port->ap_state= (port->ap_state & ~(APS_STATMASK|APS_SUSPEND)) | APS_RARPWAIT; if (port->ap_rarp_retries>=MAX_RARP_RETRIES) return;#if DEBUG & 256 { where(); printf("port->ap_rarp_retries= %d\n", port->ap_rarp_retries); }#endif port->ap_rarp_retries++; clck_timer(&port->ap_timer, get_time() + RARP_TIMEOUT, rarp_timeout, port-arp_port_table); return; case APS_ARPSTART:#if DEBUG & 256 { where(); printf("in arp_main with status: %d\n", port->ap_state & APS_STATMASK); }#endif if (port->ap_flags & APF_RARP_RD_IP) { eth_cancel(port->ap_eth_fd, SR_CANCEL_READ); port->ap_flags &= ~(APF_RARP_RD_IP|APF_RARP_RD_SP); } port->ap_state= (port->ap_state & ~(APS_STATMASK|APS_SUSPEND)) | APS_ARPPROTO; { arp_cache_t *cache; int i; cache= arp_cache; for (i=0; i<ARP_CACHE_NR; i++, cache++) { cache->ac_flags= ACF_EMPTY; cache->ac_expire= 0; cache->ac_lastuse= 0; } cache= arp_cache; for (i=0; i<ARP_CACHE1_NR; i++, cache++) cache->ac_type= 1; for (i=0; i<ARP_CACHE2_NR; i++, cache++) cache->ac_type= 2; for (i=0; i<ARP_CACHE3_NR; i++, cache++) cache->ac_type= 3; } result= eth_ioctl (port->ap_eth_fd, NWIOSETHOPT); if (result==NW_SUSPEND) port->ap_state |= APS_SUSPEND; if (result<0) {#if DEBUG { where(); printf("arp.c: /* arp */ eth_ioctl(..,NWIOSETHOPT)=%d\n", result); }#endif return; } if ((port->ap_state & APS_STATMASK) != APS_ARPPROTO) return; /* drop through */ case APS_ARPPROTO:#if DEBUG & 256 { where(); printf("in arp_main with status: %d\n", port->ap_state & APS_STATMASK); }#endif port->ap_state= (port->ap_state & ~(APS_STATMASK|APS_SUSPEND)) | APS_ARPMAIN; if (port->ap_flags & APF_MORE2WRITE) setup_write(port); setup_read(port); return; default: ip_panic(( "arp_main(&arp_port_table[%d]) called but ap_state=0x%x\n", port-arp_port_table, port->ap_state )); }}PRIVATE acc_t *arp_getdata (fd, offset, count, for_ioctl)int fd;size_t offset;size_t count;int for_ioctl;{ arp_port_t *port; rarp46_t *rarp; arp46_t *arp; acc_t *data; int result;#if DEBUG & 256 { where(); printf("arp_getdata (fd= %d, offset= %d, count= %d)\n", fd, offset, count); }#endif port= &arp_port_table[fd]; switch (port->ap_state & APS_STATMASK) { case APS_RARPPROTO: if (!count) { result= (int)offset; if (result<0) { port->ap_state= (port->ap_state & ~(APS_STATMASK|APS_SUSPEND))| APS_ERROR; break; } if (port->ap_state & APS_SUSPEND) arp_main(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_TYPESPEC; ethopt->nweo_type= htons(ETH_RARP_PROTO); return acc; } case APS_RARPWRITE: if (!count) { result= (int)offset; if (result<0) {#if DEBUG if (result != NW_SUSPEND) { where(); printf("arp.c: write error on port %d: error %d\n", fd, result); }#endif port->ap_state= (port->ap_state & ~(APS_STATMASK|APS_SUSPEND))| APS_ERROR; break; } if (port->ap_state & APS_SUSPEND) arp_main(port); return NW_OK; } assert (offset+count <= sizeof(rarp46_t)); data= bf_memreq(sizeof(rarp46_t)); rarp= (rarp46_t *)ptr2acc_data(data); data->acc_offset += offset; data->acc_length= count; rarp->a46_dstaddr.ea_addr[0]= 0xff; rarp->a46_dstaddr.ea_addr[1]= 0xff; rarp->a46_dstaddr.ea_addr[2]= 0xff; rarp->a46_dstaddr.ea_addr[3]= 0xff; rarp->a46_dstaddr.ea_addr[4]= 0xff; rarp->a46_dstaddr.ea_addr[5]= 0xff; rarp->a46_hdr= htons(ARP_ETHERNET); rarp->a46_pro= htons(ETH_IP_PROTO); rarp->a46_hln= 6; rarp->a46_pln= 4; rarp->a46_op= htons(RARP_REQUEST); rarp->a46_sha= port->ap_ethaddr; rarp->a46_tha= port->ap_ethaddr; return data; case APS_ARPPROTO: if (!count) { result= (int)offset; if (result<0) { port->ap_state= (port->ap_state & ~(APS_STATMASK|APS_SUSPEND))| APS_ERROR; break; } if (port->ap_state & APS_SUSPEND) arp_main(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_TYPESPEC; ethopt->nweo_type= htons(ETH_ARP_PROTO); return acc; } case APS_ARPMAIN: assert (port->ap_flags & APF_ARP_WR_IP); if (!count) { result= (int)offset; if (result<0) {#if DEBUG if (result != NW_SUSPEND) { where(); printf("arp.c: write error on port %d: error %d\n", fd, result); }#endif port->ap_state= (port->ap_state & ~(APS_STATMASK|APS_SUSPEND))| APS_ERROR; break; } port->ap_flags &= ~APF_ARP_WR_IP; if (port->ap_flags & APF_ARP_WR_SP) setup_write(port); return NW_OK; } assert (offset+count <= sizeof(arp46_t)); data= bf_memreq(sizeof(arp46_t)); arp= (arp46_t *)ptr2acc_data(data); data->acc_offset += offset; data->acc_length= count; if (port->ap_write_code == ARP_REPLY) arp->a46_dstaddr= port->ap_write_ethaddr; else { 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(port->ap_write_code); arp->a46_sha= port->ap_ethaddr; memcpy (arp->a46_spa, &port->ap_ipaddr, sizeof(ipaddr_t)); arp->a46_tha= port->ap_write_ethaddr; memcpy (arp->a46_tpa, &port->ap_write_ipaddr, sizeof(ipaddr_t)); return data; default: printf("arp_getdata(%d, 0x%d, 0x%d) called but ap_state=0x%x\n", fd, offset, count, port->ap_state); break; } return 0;}PRIVATE int arp_putdata (fd, offset, data, for_ioctl)int fd;size_t offset;acc_t *data;int for_ioctl;{ arp_port_t *port; int result; struct nwio_ethstat *ethstat; rarp46_t *rarp;#if DEBUG & 256 { where(); printf("arp_putdata (fd= %d, offset= %d, data= 0x%x)\n", fd, offset, data); }#endif port= &arp_port_table[fd]; if (port->ap_flags & APF_ARP_RD_IP) { if (!data) { result= (int)offset; if (result<0) {#if DEBUG if (result != NW_SUSPEND) { where(); printf("arp.c: read error on port %d: error %d\n", fd, result); }#endif return NW_OK; } if (port->ap_flags & APF_ARP_RD_SP) { port->ap_flags &= ~(APF_ARP_RD_IP| APF_ARP_RD_SP); setup_read(port); } else port->ap_flags &= ~(APF_ARP_RD_IP| APF_ARP_RD_SP); 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. */ data= bf_packIffLess(data, sizeof(arp46_t)); if (data->acc_length >= sizeof(arp46_t)) process_arp_req(port,data); bf_afree(data); return NW_OK; } if (port->ap_flags & APF_RARP_RD_IP) { if (!data) { result= (int)offset; if (result<0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -