diff --git a/PDP10/kx10_cpu.c b/PDP10/kx10_cpu.c index c687abf..f0caa59 100644 --- a/PDP10/kx10_cpu.c +++ b/PDP10/kx10_cpu.c @@ -6010,6 +6010,19 @@ qua_srv(UNIT * uptr) #endif +/* + * This sequence of instructions is a mix that hopefully + * represents a resonable instruction set that is a close + * estimate to the normal calibrated result. + */ + +static const char *pdp10_clock_precalibrate_commands[] = { + "-m 100 ADDM 0,110", + "-m 101 ADDI 0,1", + "-m 102 JRST 100", + "PC 100", + NULL}; + /* Reset routine */ t_stat cpu_reset (DEVICE *dptr) @@ -6044,6 +6057,7 @@ exec_map = 0; for(i=0; i < 128; dev_irq[i++] = 0); sim_brk_types = SWMASK('E') | SWMASK('W') | SWMASK('R'); sim_brk_dflt = SWMASK ('E'); +sim_clock_precalibrate_commands = pdp10_clock_precalibrate_commands; sim_rtcn_init_unit (&cpu_unit[0], cpu_unit[0].wait, TMR_RTC); sim_activate(&cpu_unit[0], 10000); #if MPX_DEV diff --git a/PDP10/kx10_imp.c b/PDP10/kx10_imp.c index e458223..9494775 100644 --- a/PDP10/kx10_imp.c +++ b/PDP10/kx10_imp.c @@ -146,6 +146,7 @@ #endif #define IMP_ARPTAB_SIZE 8 +#define IMP_ARP_MAX_AGE 100 uint32 mask[] = { 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8, @@ -257,7 +258,8 @@ struct arp_hdr { struct arp_entry { in_addr_T ipaddr; ETH_MAC ethaddr; - uint16 time; + int16 age; +#define ARP_DONT_AGE -1 }; /* DHCP client states */ @@ -294,6 +296,11 @@ struct arp_entry { #define DHCP_MAGIC_COOKIE 0x63825363UL +#define DHCP_INFINITE_LEASE 0xFFFFFFFF + +#define DHCP_UDP_PORT_CLIENT 68 +#define DHCP_UDP_PORT_SERVER 67 + /* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */ /* BootP options */ @@ -312,7 +319,7 @@ struct arp_entry { /* DHCP options */ #define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */ #define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */ -#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */ +#define DHCP_OPTION_OVERLOAD 52 /* RFC 2132 9.3, use file and/or sname field for options */ #define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ #define DHCP_OPTION_MESSAGE_TYPE_LEN 1 @@ -340,8 +347,6 @@ struct arp_entry { #define DHCP_SNAME_LEN 64 #define DHCP_FILE_LEN 128 -#define XID 0x3903F326 - PACKED_BEGIN struct dhcp { uint8 op; /* Operation */ @@ -396,7 +401,9 @@ struct imp_stats { struct imp_device { ETH_PCALLBACK rcallback; /* read callback routine */ ETH_PCALLBACK wcallback; /* write callback routine */ - ETH_MAC mac; /* Hardware MAC address */ + ETH_MAC macs[2]; /* Hardware MAC addresses */ +#define mac macs[0] +#define bcast macs[1] struct imp_packet *sendq; /* Send queue */ struct imp_packet *freeq; /* Free queue */ in_addr_T ip; /* Local IP address */ @@ -406,12 +413,12 @@ struct imp_device { int maskbits; /* Mask length */ struct imp_map port_map[64]; /* Ports to adjust */ in_addr_T dhcpip; /* DHCP server address */ - int dhcp; /* Use dhcp */ uint8 dhcp_state; /* State of DHCP */ int dhcp_lease; /* DHCP lease time */ int dhcp_renew; /* DHCP renew time */ int dhcp_rebind; /* DHCP rebind time */ - int sec_tim; /* 1 second timer */ + int dhcp_wait_time; /* seconds waiting for response */ + int dhcp_retry_after; /* timeout time */ int init_state; /* Initialization state */ uint32 dhcp_xid; /* Transaction ID */ int padding; /* Type zero padding */ @@ -428,6 +435,7 @@ struct imp_device { int host_error; int rfnm_count; /* Number of pending RFNM packets */ int pia; /* PIA channels */ + struct arp_entry arp_table[IMP_ARPTAB_SIZE]; } imp_data; extern int32 tmxr_poll; @@ -436,11 +444,10 @@ static CONST ETH_MAC broadcast_ethaddr = {0xff,0xff,0xff,0xff,0xff,0xff}; static CONST in_addr_T broadcast_ipaddr = {0xffffffff}; -static struct arp_entry arp_table[IMP_ARPTAB_SIZE]; - t_stat imp_devio(uint32 dev, uint64 *data); t_stat imp_srv(UNIT *); t_stat imp_eth_srv(UNIT *); +t_stat imp_tim_srv(UNIT *); t_stat imp_reset (DEVICE *dptr); t_stat imp_set_mpx (UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat imp_show_mpx (FILE *st, UNIT *uptr, int32 val, CONST void *desc); @@ -453,31 +460,40 @@ t_stat imp_set_gwip (UNIT* uptr, int32 val, CONST char* cptr, void* desc t_stat imp_show_hostip (FILE *st, UNIT *uptr, int32 val, CONST void *desc); t_stat imp_set_hostip (UNIT* uptr, int32 val, CONST char* cptr, void* desc); t_stat imp_show_dhcpip (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +t_stat imp_show_arp (FILE *st, UNIT *uptr, int32 val, CONST void *desc); +t_stat imp_set_arp (UNIT *uptr, int32 val, CONST char *cptr, void *desc); void imp_timer_task(struct imp_device *imp); void imp_send_rfmn(struct imp_device *imp); void imp_packet_in(struct imp_device *imp); void imp_send_packet (struct imp_device *imp_data, int len); void imp_free_packet(struct imp_device *imp, struct imp_packet *p); struct imp_packet * imp_get_packet(struct imp_device *imp); -void imp_arp_update(in_addr_T ipaddr, ETH_MAC *ethaddr); +void imp_arp_update(struct imp_device *imp, in_addr_T ipaddr, ETH_MAC *ethaddr, int age); void imp_arp_arpin(struct imp_device *imp, ETH_PACK *packet); +void imp_arp_arpout(struct imp_device *imp, in_addr_T ipaddr); +struct arp_entry * imp_arp_lookup(struct imp_device *imp, in_addr_T ipaddr); void imp_packet_out(struct imp_device *imp, ETH_PACK *packet); void imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *packet); void imp_dhcp_timer(struct imp_device *imp); void imp_dhcp_discover(struct imp_device *imp); +void imp_dhcp_request(struct imp_device *imp, in_addr_T dhcpip); void imp_dhcp_release(struct imp_device *imp); +void imp_arp_age(struct imp_device *imp); t_stat imp_attach (UNIT * uptr, CONST char * cptr); t_stat imp_detach (UNIT * uptr); t_stat imp_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr); const char *imp_description (DEVICE *dptr); +static char *ipv4_inet_ntoa(struct in_addr ip); +static int ipv4_inet_aton(const char *str, struct in_addr *inp); int imp_mpx_lvl = 0; -int last_coni; +double last_coni; UNIT imp_unit[] = { - {UDATA(imp_srv, UNIT_IDLE+UNIT_ATTABLE+UNIT_DISABLE, 0)}, /* 0 */ - {UDATA(imp_eth_srv, UNIT_IDLE+UNIT_DISABLE, 0)}, /* 0 */ + {UDATA(imp_srv, UNIT_IDLE+UNIT_ATTABLE+UNIT_DHCP, 0)}, /* 0 */ + {UDATA(imp_eth_srv, UNIT_IDLE+UNIT_DIS, 0)}, /* 0 */ + {UDATA(imp_tim_srv, UNIT_IDLE+UNIT_DIS, 0)}, /* 0 */ }; DIB imp_dib = {IMP_DEVNUM, 1, &imp_devio, NULL}; @@ -485,33 +501,37 @@ MTAB imp_mod[] = { { MTAB_XTD|MTAB_VDV|MTAB_VALR|MTAB_NC, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx", &imp_set_mac, &imp_show_mac, NULL, "MAC address" }, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "MPX", "MPX", - &imp_set_mpx, &imp_show_mpx, NULL}, + &imp_set_mpx, &imp_show_mpx, NULL, "ITS Interrupt Channel #"}, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "IP", "IP=ddd.ddd.ddd.ddd/dd", &imp_set_ip, &imp_show_ip, NULL, "IP address" }, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "GW", "GW=ddd.ddd.ddd.ddd", - &imp_set_gwip, &imp_show_gwip, NULL, "GW address" }, + &imp_set_gwip, &imp_show_gwip, NULL, "Gateway address" }, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "HOST", "HOST=ddd.ddd.ddd.ddd", &imp_set_hostip, &imp_show_hostip, NULL, "HOST IP address" }, { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "ETH", NULL, NULL, ð_show, NULL, "Display attachedable devices" }, - { UNIT_DHCP, 0, "DHCP disabled", "NODHCP", NULL, NULL, NULL, + { UNIT_DHCP, 0, NULL, "NODHCP", NULL, NULL, NULL, "Don't aquire address from DHCP"}, { UNIT_DHCP, UNIT_DHCP, "DHCP", "DHCP", NULL, NULL, NULL, "Use DHCP to set IP address"}, - { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "DHCPIP", "DHCPIP=ddd.ddd.ddd.ddd", - NULL, &imp_show_dhcpip, NULL, "DHCP server address" }, + { MTAB_XTD|MTAB_VDV, 0, "DHCPIP", NULL, + NULL, &imp_show_dhcpip, NULL, "DHCP info" }, { UNIT_DTYPE, (TYPE_MIT << UNIT_V_DTYPE), "MIT", "MIT", NULL, NULL, NULL, "ITS/MIT style interface"}, { UNIT_DTYPE, (TYPE_BBN << UNIT_V_DTYPE), "BBN", "BBN", NULL, NULL, NULL, "Tenex/BBN style interface"}, { UNIT_DTYPE, (TYPE_WAITS << UNIT_V_DTYPE), "WAITS", "WAITS", NULL, NULL, NULL, "WAITS style interface"}, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "ARP", NULL, + NULL, &imp_show_arp, NULL, "ARP IP address->MAC address table" }, + { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, NULL, "ARP=ddd.ddd.ddd.ddd=XX:XX:XX:XX:XX:XX", + &imp_set_arp, NULL, NULL, "Create a static ARP Entry" }, { 0 } }; DEVICE imp_dev = { "IMP", imp_unit, NULL, imp_mod, - 1, 8, 0, 1, 8, 36, + 3, 8, 0, 1, 8, 36, NULL, NULL, &imp_reset, NULL, &imp_attach, &imp_detach, &imp_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, dev_debug, NULL, NULL, &imp_help, NULL, NULL, &imp_description @@ -573,7 +593,7 @@ t_stat imp_devio(uint32 dev, uint64 *data) } if (*data & IMPHEC) { /* Clear host error. */ /* Only if there has been a CONI lately. */ - if (last_coni - sim_interval < CONI_TIMEOUT) + if (last_coni - sim_gtime() < CONI_TIMEOUT) uptr->STATUS &= ~IMPHER; } if (*data & IMIIHE) /* Inhibit interrupt on host error. */ @@ -630,7 +650,7 @@ t_stat imp_devio(uint32 dev, uint64 *data) case CONI: switch (GET_DTYPE(uptr->flags)) { case TYPE_MIT: - last_coni = sim_interval; + last_coni = sim_gtime(); *data = (uint64)(uptr->STATUS | (imp_data.pia & 07)); break; case TYPE_BBN: @@ -806,10 +826,13 @@ t_stat imp_eth_srv(UNIT * uptr) imp_packet_in(&imp_data); if (imp_data.init_state >= 3 && imp_data.init_state < 6) { - if (imp_unit[0].flags & UNIT_DHCP && imp_data.dhcp_state != DHCP_STATE_BOUND) + if (imp_unit[0].flags & UNIT_DHCP && + imp_data.dhcp_state != DHCP_STATE_BOUND && + imp_data.dhcp_state != DHCP_STATE_REBINDING && + imp_data.dhcp_state != DHCP_STATE_RENEWING) return SCPE_OK; - sim_debug(DEBUG_DETAIL, &imp_dev, "IMP init Nop %d\n", - imp_data.init_state); + sim_debug(DEBUG_DETAIL, &imp_dev, "IMP init Nop %d\n", + imp_data.init_state); if (imp_unit[0].ILEN == 0) { /* Queue up a nop packet */ imp_data.rbuffer[0] = 0x4; @@ -836,12 +859,6 @@ imp_timer_task(struct imp_device *imp) struct imp_packet *nq = NULL; /* New send queue */ int n; - /* If DHCP enabled, send a discover packet */ - if (imp_data.init_state >= 1 && - imp_unit[0].flags & UNIT_DHCP && imp->dhcp_state == DHCP_STATE_OFF) { - imp_dhcp_discover(&imp_data); - } - /* Scan through adjusted ports and remove old ones */ for (n = 0; n < 64; n++) { if (imp->port_map[n].cls_tim > 0) { @@ -869,13 +886,17 @@ imp_timer_task(struct imp_device *imp) } } imp->sendq = nq; - - if (imp->sec_tim-- == 0) { - imp_dhcp_timer(&imp_data); - imp->sec_tim = 1000; - } } +t_stat imp_tim_srv(UNIT * uptr) +{ + sim_activate_after(uptr, 1000000); /* come back once per second */ + + imp_dhcp_timer(&imp_data); + imp_arp_age(&imp_data); + return SCPE_OK; +} + void imp_packet_in(struct imp_device *imp) { @@ -915,8 +936,9 @@ imp_packet_in(struct imp_device *imp) (ip_hdr->ip_v_hl & 0xf) * 4]); struct udp *udp_hdr = (struct udp *)payload; /* Check for DHCP traffic */ - if (ip_hdr->ip_p == UDP_PROTO && ntohs(udp_hdr->udp_dport) == 68 && - ntohs(udp_hdr->udp_sport) == 67) { + if (ip_hdr->ip_p == UDP_PROTO && + ntohs(udp_hdr->udp_dport) == DHCP_UDP_PORT_CLIENT && + ntohs(udp_hdr->udp_sport) == DHCP_UDP_PORT_SERVER) { imp_do_dhcp_client(imp, &read_buffer); return; } @@ -924,7 +946,7 @@ imp_packet_in(struct imp_device *imp) /* Process as IP if it is for us */ if (ip_hdr->ip_dst == imp_data.ip || ip_hdr->ip_dst == 0) { /* Add mac address since we will probably need it later */ - imp_arp_update(ip_hdr->ip_src, &hdr->src); + imp_arp_update(imp, ip_hdr->ip_src, &hdr->src, 0); /* Clear beginning of message */ memset(&imp->rbuffer[0], 0, 256); imp->rbuffer[0] = 0xf; @@ -1050,8 +1072,8 @@ imp_packet_in(struct imp_device *imp) } else if (ip_hdr->ip_p == UDP_PROTO) { struct udp *udp_hdr = (struct udp *)payload; if (ip_hdr->ip_p == UDP_PROTO && - htons(udp_hdr->udp_dport) == 68 && - htons(udp_hdr->udp_sport) == 67) { + htons(udp_hdr->udp_dport) == DHCP_UDP_PORT_CLIENT && + htons(udp_hdr->udp_sport) == DHCP_UDP_PORT_SERVER) { imp_do_dhcp_client(imp, &read_buffer); return; } @@ -1175,8 +1197,6 @@ imp_packet_out(struct imp_device *imp, ETH_PACK *packet) { struct ip_hdr *pkt = (struct ip_hdr *)(&packet->msg[0]); struct imp_packet *send; struct arp_entry *tabptr; - struct arp_hdr *arp; - ETH_PACK arp_pkt; in_addr_T ipaddr; int i; @@ -1312,7 +1332,7 @@ imp_packet_out(struct imp_device *imp, ETH_PACK *packet) { ipaddr = imp->gwip; for (i = 0; i < IMP_ARPTAB_SIZE; i++) { - tabptr = &arp_table[i]; + tabptr = &imp->arp_table[i]; if (ipaddr == tabptr->ipaddr) { memcpy(&pkt->ethhdr.dest, &tabptr->ethaddr, 6); memcpy(&pkt->ethhdr.src, &imp->mac, 6); @@ -1332,24 +1352,8 @@ imp_packet_out(struct imp_device *imp, ETH_PACK *packet) { send->dest = pkt->iphdr.ip_dst; memcpy(&send->packet.msg[0], pkt, send->packet.len); - /* We did not find it, so construct and send a ARP packet */ - memset(&arp_pkt, 0, sizeof(ETH_PACK)); - arp = (struct arp_hdr *)(&arp_pkt.msg[0]); - memcpy(&arp->ethhdr.dest, &broadcast_ethaddr, 6); - memcpy(&arp->ethhdr.src, &imp->mac, 6); - arp->ethhdr.type = htons(ETHTYPE_ARP); - memset(&arp->dhwaddr, 0x00, 6); - memcpy(&arp->shwaddr, &imp->mac, 6); - arp->dipaddr = ipaddr; - arp->sipaddr = imp->ip; - arp->opcode = htons(ARP_REQUEST); - arp->hwtype = htons(ARP_HWTYPE_ETH); - arp->protocol = htons(ETHTYPE_IP); - arp->hwlen = 6; - arp->protolen = 4; - - arp_pkt.len = sizeof(struct arp_hdr); - eth_write(&imp->etherface, &arp_pkt, NULL); + /* We did not find it, so construct and send an ARP packet */ + imp_arp_arpout(imp, ipaddr); } @@ -1357,20 +1361,20 @@ imp_packet_out(struct imp_device *imp, ETH_PACK *packet) { * Update the ARP table, first use free entry, else use oldest. */ void -imp_arp_update(in_addr_T ipaddr, ETH_MAC *ethaddr) +imp_arp_update(struct imp_device *imp, in_addr_T ipaddr, ETH_MAC *ethaddr, int age) { struct arp_entry *tabptr; int i; - static int arptime = 0; /* Check if entry already in the table. */ for (i = 0; i < IMP_ARPTAB_SIZE; i++) { - tabptr = &arp_table[i]; + tabptr = &imp->arp_table[i]; if (tabptr->ipaddr != 0) { if (tabptr->ipaddr == ipaddr) { memcpy(&tabptr->ethaddr, ethaddr, sizeof(ETH_MAC)); - tabptr->time = ++arptime; + if (tabptr->age != ARP_DONT_AGE) + tabptr->age = age; return; } } @@ -1378,7 +1382,7 @@ imp_arp_update(in_addr_T ipaddr, ETH_MAC *ethaddr) /* See if we can find an unused entry. */ for (i = 0; i < IMP_ARPTAB_SIZE; i++) { - tabptr = &arp_table[i]; + tabptr = &imp->arp_table[i]; if (tabptr->ipaddr == 0) break; @@ -1387,21 +1391,42 @@ imp_arp_update(in_addr_T ipaddr, ETH_MAC *ethaddr) /* If no empty entry search for oldest one. */ if (tabptr->ipaddr != 0) { int fnd = 0; - uint16 tmpage = 0; + int16 tmpage = 0; for (i = 0; i < IMP_ARPTAB_SIZE; i++) { - tabptr = &arp_table[i]; - if (arptime - tabptr->time > tmpage) { - tmpage = arptime - tabptr->time; + tabptr = &imp->arp_table[i]; + if (tabptr->age > tmpage) { + tmpage = tabptr->age; fnd = i; } } - tabptr = &arp_table[fnd]; + tabptr = &imp->arp_table[fnd]; } /* Now update the entry */ memcpy(&tabptr->ethaddr, ethaddr, sizeof(ETH_MAC)); tabptr->ipaddr = ipaddr; - tabptr->time = ++arptime; + tabptr->age = age; +} + +/* + * Age arp entries and free up old ones. + */ +void imp_arp_age(struct imp_device *imp) +{ + struct arp_entry *tabptr; + int i; + + for (i = 0; i < IMP_ARPTAB_SIZE; i++) { + tabptr = &imp->arp_table[i]; + if (tabptr->ipaddr != 0) { /* active entry? */ + if (tabptr->age != ARP_DONT_AGE) + tabptr->age++; /* Age it */ + /* expire too old entries */ + if (tabptr->age > IMP_ARP_MAX_AGE) { + memset(tabptr, 0, sizeof(*tabptr)); + } + } + } } @@ -1424,7 +1449,7 @@ imp_arp_arpin(struct imp_device *imp, ETH_PACK *packet) switch (op) { case ARP_REQUEST: if (arp->dipaddr == imp->ip) { - imp_arp_update(arp->sipaddr, &arp->shwaddr); + imp_arp_update(imp, arp->sipaddr, &arp->shwaddr, 0); arp->opcode = htons(ARP_REPLY); memcpy(&arp->dhwaddr, &arp->shwaddr, 6); @@ -1444,7 +1469,7 @@ imp_arp_arpin(struct imp_device *imp, ETH_PACK *packet) /* Check if this is our address */ if (arp->dipaddr == imp->ip) { struct imp_packet *nq = NULL; /* New send queue */ - imp_arp_update(arp->sipaddr, &arp->shwaddr); + imp_arp_update(imp, arp->sipaddr, &arp->shwaddr, 0); /* Scan send queue, and send all packets for this host */ while (imp->sendq != NULL) { struct imp_packet *temp = imp->sendq; @@ -1470,6 +1495,101 @@ imp_arp_arpin(struct imp_device *imp, ETH_PACK *packet) } return; } + +/* + * Send a ARP_REQUEST packet. + */ + +void +imp_arp_arpout(struct imp_device *imp, in_addr_T ipaddr) +{ + struct arp_hdr *arp; + ETH_PACK arp_pkt; + + memset(&arp_pkt, 0, sizeof(ETH_PACK)); + arp = (struct arp_hdr *)(&arp_pkt.msg[0]); + memcpy(&arp->ethhdr.dest, &broadcast_ethaddr, 6); + memcpy(&arp->ethhdr.src, &imp->mac, 6); + arp->ethhdr.type = htons(ETHTYPE_ARP); + memset(&arp->dhwaddr, 0x00, 6); + memcpy(&arp->shwaddr, &imp->mac, 6); + arp->dipaddr = ipaddr; + arp->sipaddr = imp->ip; + arp->opcode = htons(ARP_REQUEST); + arp->hwtype = htons(ARP_HWTYPE_ETH); + arp->protocol = htons(ETHTYPE_IP); + arp->hwlen = 6; + arp->protolen = 4; + + arp_pkt.len = sizeof(struct arp_hdr); + eth_write(&imp->etherface, &arp_pkt, NULL); +} + +/* + * Lookup an IP's ARP entry. + */ + +struct arp_entry *imp_arp_lookup(struct imp_device *imp, in_addr_T ipaddr) +{ + struct arp_entry *tabptr; + int i; + + /* Check if entry already in the table. */ + for (i = 0; i < IMP_ARPTAB_SIZE; i++) { + tabptr = &imp->arp_table[i]; + + if (tabptr->ipaddr != 0) { + if (tabptr->ipaddr == ipaddr) + return tabptr; + } + } + return NULL; +} + +t_stat imp_set_arp (UNIT* uptr, int32 val, CONST char* cptr, void* desc) +{ + char abuf[CBUFSIZE]; + in_addr_T ip; + ETH_MAC mac_addr; + + if (!cptr) return SCPE_IERR; + + cptr = get_glyph (cptr, abuf, '='); + if (cptr && *cptr) { + if (SCPE_OK != eth_mac_scan (&mac_addr, cptr)) /* scan string for mac, put in mac */ + return sim_messagef(SCPE_ARG, "Invalid MAC address: %s", cptr); + } else + return sim_messagef(SCPE_ARG, "Invalid MAC address: %s", cptr); + if (ipv4_inet_aton (abuf, (struct in_addr *)&ip)) { + imp_arp_update(&imp_data, ip, &mac_addr, ARP_DONT_AGE); + return SCPE_OK; + } + return sim_messagef(SCPE_ARG, "Invalid IP Address: %s", abuf); +} + +t_stat imp_show_arp (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + struct arp_entry *tabptr; + int i; + + fprintf (st, "%-17s%-19s%s\n", "IP Address:", "MAC:", "Age:"); + + for (i = 0; i < IMP_ARPTAB_SIZE; i++) { + char buf[32]; + + tabptr = &imp_data.arp_table[i]; + + if (tabptr->ipaddr == 0) + continue; + + eth_mac_fmt(&tabptr->ethaddr, buf); /* format ethernet mac address */ + if (tabptr->age == ARP_DONT_AGE) + fprintf (st, "%-17s%-19s%s\n", ipv4_inet_ntoa(*((struct in_addr *)&tabptr->ipaddr)), buf, "static"); + else + fprintf (st, "%-17s%-19s%d\n", ipv4_inet_ntoa(*((struct in_addr *)&tabptr->ipaddr)), buf, tabptr->age); + } + return SCPE_OK; +} static int sent_flag = 0; @@ -1477,9 +1597,22 @@ void sent(int status) { sent_flag = 1; } +static const char *dhcp_state_names[] = { + "OFF", "REQUESTING", "INIT", "REBOOTING", + "REBINDING", "RENEWING", "SELECTING", "INFORMING", + "CHECKING", "PERMANENT", "BOUND", "RELEASING", + "BACKING_OFF" + }; + +static const char *dhcp_opr_names[16] = { + "", "DISCOVER", "OFFER", "REQUEST", + "DECLINE", "ACK", "NAK", "RELEASE", + "INFORM" + }; + /* Send out a DHCP packet, fill in IP and Ethernet data. */ void -imp_do_send_dhcp(struct imp_device *imp, ETH_PACK *packet, uint8 *last) +imp_do_send_dhcp(struct imp_device *imp, const char *op, ETH_PACK *packet, uint8 *last, const struct arp_entry *destarp) { struct ip_hdr *pkt; struct udp *udp; @@ -1491,7 +1624,10 @@ imp_do_send_dhcp(struct imp_device *imp, ETH_PACK *packet, uint8 *last) sizeof(struct ip)]); len = last - (uint8 *)udp; /* Fill in ethernet and IP packet */ - memcpy(&pkt->ethhdr.dest, &broadcast_ethaddr, 6); + if (destarp) + memcpy(&pkt->ethhdr.dest, &destarp->ethaddr, 6); + else + memcpy(&pkt->ethhdr.dest, &broadcast_ethaddr, 6); memcpy(&pkt->ethhdr.src, &imp->mac, 6); pkt->ethhdr.type = htons(ETHTYPE_IP); pkt->iphdr.ip_v_hl = 0x45; @@ -1499,8 +1635,8 @@ imp_do_send_dhcp(struct imp_device *imp, ETH_PACK *packet, uint8 *last) pkt->iphdr.ip_ttl = 128; pkt->iphdr.ip_p = UDP_PROTO; pkt->iphdr.ip_dst = broadcast_ipaddr; - udp->udp_sport = htons(68); - udp->udp_dport = htons(67); + udp->udp_sport = htons(DHCP_UDP_PORT_CLIENT); + udp->udp_dport = htons(DHCP_UDP_PORT_SERVER); udp->len = htons(len); pkt->iphdr.ip_len = htons(len + sizeof(struct ip)); ip_checksum((uint8 *)(&pkt->iphdr.ip_sum), (uint8 *)&pkt->iphdr, 20); @@ -1514,8 +1650,9 @@ imp_do_send_dhcp(struct imp_device *imp, ETH_PACK *packet, uint8 *last) checksumadjust((uint8 *)&udp->chksum, (uint8 *)(&udp_hdr), 0, (uint8 *)(&udp_hdr), sizeof(udp_hdr)); packet->len = len + sizeof(struct ip_hdr); - sent_flag = 0; - eth_write(&imp->etherface, packet, &sent); + eth_write(&imp->etherface, packet, NULL); + sim_debug(DEBUG_DETAIL, &imp_dev, + "DHCP client sent %s packet\n", op); } /* Handle incoming DCHP offer and other requests */ @@ -1524,7 +1661,7 @@ imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *read_buffer) { struct ip *ip_hdr = (struct ip *) (&read_buffer->msg[sizeof(struct imp_eth_hdr)]); - ETH_PACK dhcp_pkt; + struct imp_eth_hdr *eth = (struct imp_eth_hdr *)read_buffer->msg; int hl = (ip_hdr->ip_v_hl & 0xf) * 4; struct dhcp *dhcp; struct udp *upkt; @@ -1536,9 +1673,10 @@ imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *read_buffer) in_addr_T my_mask = 0; /* Local IP mask */ in_addr_T my_gw = 0; /* Gateway IP address */ int lease_time = 0; /* Lease time */ + int renew_time = 0; /* Renewal time */ + int rebind_time = 0; /* Rebind time */ in_addr_T dhcpip = 0; /* DHCP server address */ - int opr = -1; /* Dhcp operation */ - + int opr = -1; /* DHCP operation */ upkt = (struct udp *)(&((uint8 *)(ip_hdr))[hl]); dhcp = (struct dhcp *)(&((uint8 *)(upkt))[sizeof(struct udp)]); @@ -1568,6 +1706,8 @@ imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *read_buffer) opt = &dhcp->options[0]; + my_ip = dhcp->yiaddr; + /* Scan and collect the options we care about */ while (*opt != DHCP_OPTION_END) { switch(*opt++) { @@ -1595,6 +1735,19 @@ imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *read_buffer) case DHCP_OPTION_LEASE_TIME: len = *opt++; memcpy(&lease_time, opt, 4); + lease_time = ntohl(lease_time); + opt += len; + break; + case DHCP_OPTION_T1: + len = *opt++; + memcpy(&renew_time, opt, 4); + renew_time = ntohl(renew_time); + opt += len; + break; + case DHCP_OPTION_T2: + len = *opt++; + memcpy(&rebind_time, opt, 4); + rebind_time = ntohl(rebind_time); opt += len; break; case DHCP_OPTION_SERVER_ID: @@ -1610,144 +1763,137 @@ imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *read_buffer) } } + sim_debug(DEBUG_DETAIL, &imp_dev, + "DHCP client incoming %s packet: dhcp_state=%s - wait_time=%d\n", (opr == -1) ? "" : dhcp_opr_names[opr], dhcp_state_names[imp->dhcp_state], imp->dhcp_wait_time); + /* Process an offer message */ if (opr == DHCP_OFFER && imp->dhcp_state == DHCP_STATE_SELECTING) { /* Create a REQUEST Packet with IP address given */ - struct dhcp *dhcp_rply; - in_addr_T ip_t; - - memset(&dhcp_pkt.msg[0], 0, ETH_FRAME_SIZE); - dhcp_rply = (struct dhcp *)(&dhcp_pkt.msg[sizeof(struct imp_eth_hdr) + - sizeof(struct ip) + sizeof(struct udp)]); - - dhcp_rply->op = DHCP_BOOTREQUEST; - dhcp_rply->htype = DHCP_HTYPE_ETH; - dhcp_rply->hlen = 6; - dhcp_rply->xid = ++imp->dhcp_xid; - dhcp_rply->cookie = htonl(DHCP_MAGIC_COOKIE); - memcpy(&dhcp_rply->chaddr, &imp->mac, 6); - opt = &dhcp_rply->options[0]; - *opt++ = DHCP_OPTION_MESSAGE_TYPE; - *opt++ = 1; - *opt++ = DHCP_REQUEST; - *opt++ = DHCP_OPTION_REQUESTED_IP; - *opt++ = 4; - ip_t = htonl(dhcp->yiaddr); - *opt++ = (ip_t >> 24) & 0xff; - *opt++ = (ip_t >> 16) & 0xff; - *opt++ = (ip_t >> 8) & 0xff; - *opt++ = ip_t & 0xff; - *opt++ = DHCP_OPTION_SERVER_ID; - *opt++ = 4; - ip_t = imp->dhcpip; - *opt++ = (ip_t >> 24) & 0xff; - *opt++ = (ip_t >> 16) & 0xff; - *opt++ = (ip_t >> 8) & 0xff; - *opt++ = ip_t & 0xff; - *opt++ = DHCP_OPTION_CLIENT_ID; - *opt++ = 6; - for (len = 0; len < 6; len++) - *opt++ = imp->mac[len]; - *opt++ = DHCP_OPTION_PARAMETER_REQUEST_LIST; - *opt++ = 2; /* Number */ - *opt++ = DHCP_OPTION_SUBNET_MASK; /* Subnet mask */ - *opt++ = DHCP_OPTION_ROUTER; /* Routers */ - *opt++ = DHCP_OPTION_END; /* Last option */ - imp_do_send_dhcp(imp, &dhcp_pkt, opt); imp->dhcp_state = DHCP_STATE_REQUESTING; + imp->ip = my_ip; + imp->dhcp_wait_time = 0; + imp->dhcp_retry_after = 4; + imp_dhcp_request(imp, dhcpip); } - if (opr == DHCP_ACK && (imp->dhcp_state == DHCP_STATE_REQUESTING || + if (opr == DHCP_ACK && imp->dhcp_xid == dhcp->xid && + (imp->dhcp_state == DHCP_STATE_REQUESTING || imp->dhcp_state == DHCP_STATE_REBINDING || imp->dhcp_state == DHCP_STATE_RENEWING)) { + ETH_PACK arp_pkt; + struct arp_hdr *arp; + /* Set my IP address to one offered */ imp->ip = dhcp->yiaddr; imp->ip_mask = my_mask; imp->gwip = my_gw; imp->dhcpip = dhcpip; imp->dhcp_state = DHCP_STATE_BOUND; - imp->dhcp_lease = ntohl(lease_time); + imp->dhcp_lease = lease_time; imp->dhcp_renew = imp->dhcp_lease / 2; + if (renew_time) + imp->dhcp_renew = renew_time; imp->dhcp_rebind = (7 * imp->dhcp_lease) / 8; + if (rebind_time) + imp->dhcp_rebind = rebind_time; for (len = 0; len < 33; len++) { - if (mask[len] == my_mask) { + if (htonl(mask[len]) == my_mask) { imp->maskbits = 32 - len; break; } + /* Record a static ARP for the DHCP server */ + imp_arp_update(imp, dhcpip, ð->src, ARP_DONT_AGE); + + /* Broadcast an ARP Reply with the assigned IP Address */ + memset(&arp_pkt, 0, sizeof(ETH_PACK)); + arp = (struct arp_hdr *)(&arp_pkt.msg[0]); + memcpy(&arp->ethhdr.dest, &broadcast_ethaddr, 6); + memcpy(&arp->ethhdr.src, &imp->mac, 6); + arp->ethhdr.type = htons(ETHTYPE_ARP); + memcpy(&arp->dhwaddr, &imp->mac, 6); + memcpy(&arp->shwaddr, &imp->mac, 6); + arp->dipaddr = imp->ip; + arp->sipaddr = imp->ip; + arp->opcode = htons(ARP_REPLY); + arp->hwtype = htons(ARP_HWTYPE_ETH); + arp->protocol = htons(ETHTYPE_IP); + arp->hwlen = 6; + arp->protolen = 4; + arp_pkt.len = sizeof(struct arp_hdr); + eth_write(&imp->etherface, &arp_pkt, NULL); } } if (opr == DHCP_NAK && (imp->dhcp_state == DHCP_STATE_REQUESTING || imp->dhcp_state == DHCP_STATE_REBINDING || - imp->dhcp_state == DHCP_STATE_RENEWING)) + imp->dhcp_state == DHCP_STATE_RENEWING)) { + imp->ip = imp->gwip = imp->dhcpip = imp->maskbits = 0; imp->dhcp_state = DHCP_STATE_OFF; + + } } void imp_dhcp_timer(struct imp_device *imp) { - ETH_PACK dhcp_pkt; - uint8 *opt; - int len; - in_addr_T ip_t; - struct dhcp *dhcp_rply; + if (!(imp_unit[0].flags & UNIT_DHCP)) + return; - if (imp->dhcp_lease-- == 0) - imp->dhcp_state = DHCP_STATE_OFF; - else if (imp->dhcp_rebind-- == 0) { - imp->dhcp_state = DHCP_STATE_REBINDING; - imp->dhcpip = 0; - } else if (imp->dhcp_renew-- == 0) { - imp->dhcp_state = DHCP_STATE_RENEWING; + if (imp->dhcp_state == DHCP_STATE_BOUND) + sim_debug(DEBUG_DETAIL, &imp_dev, + "DHCP timer: dhcp_state=BOUND, Lease remaining time=%d\n", imp->dhcp_lease); + else + sim_debug(DEBUG_DETAIL, &imp_dev, + "DHCP timer: dhcp_state=%s, wait_time=%d\n", dhcp_state_names[imp->dhcp_state], imp->dhcp_wait_time); + + if ((imp->dhcp_state == DHCP_STATE_BOUND) || + (imp->dhcp_state == DHCP_STATE_REBINDING) || + (imp->dhcp_state == DHCP_STATE_RENEWING)) { + if (imp->dhcp_lease != DHCP_INFINITE_LEASE) { + if (imp->dhcp_lease-- == 0) { + imp->dhcp_state = DHCP_STATE_OFF; + } else { + if (imp->dhcp_rebind-- == 0) { + imp->dhcp_state = DHCP_STATE_REBINDING; + imp->dhcpip = 0; + imp->dhcp_wait_time = 0; + imp->dhcp_retry_after = 4; + } else { + if (imp->dhcp_renew-- == 0) { + imp->dhcp_state = DHCP_STATE_RENEWING; + imp->dhcp_wait_time = 0; + imp->dhcp_retry_after = 4; + } + } + } + } } switch (imp->dhcp_state) { case DHCP_STATE_REBINDING: case DHCP_STATE_RENEWING: - /* Create a REQUEST Packet with IP address given */ - - memset(&dhcp_pkt.msg[0], 0, ETH_FRAME_SIZE); - dhcp_rply = (struct dhcp *)(&dhcp_pkt.msg[sizeof(struct imp_eth_hdr) + - sizeof(struct ip) + sizeof(struct udp)]); - - dhcp_rply->op = DHCP_BOOTREQUEST; - dhcp_rply->htype = DHCP_HTYPE_ETH; - dhcp_rply->hlen = 6; - dhcp_rply->xid = ++imp->dhcp_xid; - dhcp_rply->cookie = htonl(DHCP_MAGIC_COOKIE); - memcpy(&dhcp_rply->chaddr, &imp->mac, 6); - opt = &dhcp_rply->options[0]; - *opt++ = DHCP_OPTION_MESSAGE_TYPE; - *opt++ = 1; - *opt++ = DHCP_REQUEST; - *opt++ = DHCP_OPTION_REQUESTED_IP; - *opt++ = 4; - ip_t = htonl(imp->ip); - *opt++ = (ip_t >> 24) & 0xff; - *opt++ = (ip_t >> 16) & 0xff; - *opt++ = (ip_t >> 8) & 0xff; - *opt++ = ip_t & 0xff; - *opt++ = DHCP_OPTION_SERVER_ID; - *opt++ = 4; - ip_t = imp->dhcpip; - *opt++ = (ip_t >> 24) & 0xff; - *opt++ = (ip_t >> 16) & 0xff; - *opt++ = (ip_t >> 8) & 0xff; - *opt++ = ip_t & 0xff; - *opt++ = DHCP_OPTION_CLIENT_ID; - *opt++ = 6; - for (len = 0; len < 6; len++) - *opt++ = imp->mac[len]; - *opt++ = DHCP_OPTION_PARAMETER_REQUEST_LIST; - *opt++ = 2; /* Number */ - *opt++ = DHCP_OPTION_SUBNET_MASK; /* Subnet mask */ - *opt++ = DHCP_OPTION_ROUTER; /* Routers */ - *opt++ = DHCP_OPTION_END; /* Last option */ - imp_do_send_dhcp(imp, &dhcp_pkt, opt); + /* Create a REQUEST Packet with IP address previously given */ + imp_dhcp_request(imp, (imp->dhcp_state == DHCP_STATE_RENEWING) ? imp->dhcpip : 0); break; case DHCP_STATE_OFF: + imp->dhcp_wait_time = 0; + imp->dhcp_retry_after = 4; imp_dhcp_discover(imp); break; + case DHCP_STATE_SELECTING: + case DHCP_STATE_REQUESTING: + imp->dhcp_wait_time++; + if (imp->dhcp_wait_time % imp->dhcp_retry_after == 0) { + if (imp->dhcp_retry_after < 64) + imp->dhcp_retry_after *= 2; + imp->dhcp_wait_time = 0; + if (imp->dhcp_state == DHCP_STATE_SELECTING) + imp_dhcp_discover(imp); + else + imp_dhcp_request(imp, imp->dhcpip); + } + break; + default: break; } @@ -1759,6 +1905,7 @@ imp_dhcp_discover(struct imp_device *imp) ETH_PACK dhcp_pkt; struct dhcp *dhcp; uint8 *opt; + int len; /* Fill in Discover packet */ memset(&dhcp_pkt.msg[0], 0, ETH_FRAME_SIZE); @@ -1769,20 +1916,23 @@ imp_dhcp_discover(struct imp_device *imp) dhcp->htype = DHCP_HTYPE_ETH; dhcp->hlen = 6; dhcp->xid = ++imp->dhcp_xid; + dhcp->secs = imp->dhcp_wait_time; dhcp->cookie = htonl(DHCP_MAGIC_COOKIE); memcpy(&dhcp->chaddr, &imp->mac, 6); opt = &dhcp->options[0]; *opt++ = DHCP_OPTION_MESSAGE_TYPE; *opt++ = 1; *opt++ = DHCP_DISCOVER; + *opt++ = DHCP_OPTION_CLIENT_ID; + *opt++ = 7; + *opt++ = DHCP_HTYPE_ETH; + for (len = 0; len < 6; len++) + *opt++ = imp->mac[len]; if (imp->ip != 0) { - in_addr_T ip_t = htonl(imp->ip); *opt++ = DHCP_OPTION_REQUESTED_IP; *opt++ = 0x04; - *opt++ = (ip_t >> 24) & 0xff; - *opt++ = (ip_t >> 16) & 0xff; - *opt++ = (ip_t >> 8) & 0xff; - *opt++ = ip_t & 0xff; + memcpy(opt, &imp->ip, 4); + opt += 4; } *opt++= DHCP_OPTION_PARAMETER_REQUEST_LIST; *opt++= 2; /* Number */ @@ -1790,10 +1940,58 @@ imp_dhcp_discover(struct imp_device *imp) *opt++= DHCP_OPTION_ROUTER; /* Routers */ *opt++= DHCP_OPTION_END; /* Last option */ /* Fill in ethernet and IP packet */ - imp_do_send_dhcp(imp, &dhcp_pkt, opt); + imp_do_send_dhcp(imp, "DISCOVER", &dhcp_pkt, opt, NULL); imp->dhcp_state = DHCP_STATE_SELECTING; } +void +imp_dhcp_request(struct imp_device *imp, in_addr_T dhcpip) +{ + ETH_PACK dhcp_pkt; + struct dhcp *dhcp; + uint8 *opt; + int len; + + /* Fill in Request packet */ + memset(&dhcp_pkt.msg[0], 0, ETH_FRAME_SIZE); + dhcp = (struct dhcp *)(&dhcp_pkt.msg[sizeof(struct imp_eth_hdr) + + sizeof(struct ip) + sizeof(struct udp)]); + + dhcp->op = DHCP_BOOTREQUEST; + dhcp->htype = DHCP_HTYPE_ETH; + dhcp->hlen = 6; + dhcp->xid = imp->dhcp_xid; + dhcp->cookie = htonl(DHCP_MAGIC_COOKIE); + memcpy(&dhcp->chaddr, &imp->mac, 6); + opt = &dhcp->options[0]; + *opt++ = DHCP_OPTION_MESSAGE_TYPE; + *opt++ = 1; + *opt++ = DHCP_REQUEST; + *opt++ = DHCP_OPTION_REQUESTED_IP; + *opt++ = 4; + memcpy(opt, &imp->ip, 4); + opt += 4; + if (dhcpip) { + *opt++ = DHCP_OPTION_SERVER_ID; + *opt++ = 4; + memcpy(opt, &dhcpip, 4); + opt += 4; + } + *opt++ = DHCP_OPTION_CLIENT_ID; + *opt++ = 7; + *opt++ = DHCP_HTYPE_ETH; + for (len = 0; len < 6; len++) + *opt++ = imp->mac[len]; + *opt++ = DHCP_OPTION_PARAMETER_REQUEST_LIST; + *opt++ = 4; /* Number */ + *opt++ = DHCP_OPTION_SUBNET_MASK; /* Subnet mask */ + *opt++ = DHCP_OPTION_ROUTER; /* Routers */ + *opt++ = DHCP_OPTION_T1; /* Renewal time */ + *opt++ = DHCP_OPTION_T2; /* Rebinding time */ + *opt++ = DHCP_OPTION_END; /* Last option */ + imp_do_send_dhcp(imp, "REQUEST", &dhcp_pkt, opt, imp_arp_lookup(imp, dhcpip)); +} + void imp_dhcp_release(struct imp_device *imp) { @@ -1804,7 +2002,7 @@ imp_dhcp_release(struct imp_device *imp) /* Nothing to send if we are not bound */ - if (imp_data.dhcp_state != DHCP_STATE_OFF) + if (imp->dhcp_state == DHCP_STATE_OFF) return; /* Fill in DHCP RELEASE PACKET */ memset(&dhcp_pkt.msg[0], 0, ETH_FRAME_SIZE); @@ -1815,36 +2013,32 @@ imp_dhcp_release(struct imp_device *imp) dhcp->htype = DHCP_HTYPE_ETH; dhcp->hlen = 6; dhcp->xid = ++imp->dhcp_xid; - dhcp->ciaddr = htonl(imp->ip); + dhcp->ciaddr = imp->ip; dhcp->cookie = htonl(DHCP_MAGIC_COOKIE); memcpy(&dhcp->chaddr, &imp->mac, 6); opt = &dhcp->options[0]; *opt++ = DHCP_OPTION_SERVER_ID; *opt++ = 4; - *opt++ = (imp->dhcpip >> 24) & 0xff; - *opt++ = (imp->dhcpip >> 16) & 0xff; - *opt++ = (imp->dhcpip >> 8) & 0xff; - *opt++ = imp->dhcpip & 0xff; + memcpy(opt, &imp->dhcpip, 4); + opt += 4; *opt++ = DHCP_OPTION_MESSAGE_TYPE; *opt++ = 1; *opt++ = DHCP_RELEASE; if (imp->ip != 0) { - in_addr_T ip_t = htonl(imp->ip); *opt++ = DHCP_OPTION_REQUESTED_IP; *opt++ = 0x04; - *opt++ = (ip_t >> 24) & 0xff; - *opt++ = (ip_t >> 16) & 0xff; - *opt++ = (ip_t >> 8) & 0xff; - *opt++ = ip_t & 0xff; + memcpy(opt, &imp->ip, 4); + opt += 4; } *opt++ = DHCP_OPTION_CLIENT_ID; - *opt++ = 6; + *opt++ = 7; + *opt++ = DHCP_HTYPE_ETH; for (len = 0; len < 6; len++) *opt++ = imp->mac[len]; *opt++= DHCP_OPTION_END; /* Last option */ - imp_do_send_dhcp(imp, &dhcp_pkt, opt); - while(sent_flag == 0); + imp_do_send_dhcp(imp, "RELEASE", &dhcp_pkt, opt, imp_arp_lookup(imp, imp->dhcpip)); imp->dhcp_state = DHCP_STATE_OFF; + imp->ip = imp->gwip = imp->dhcpip = imp->maskbits = 0; } @@ -1854,8 +2048,12 @@ ipv4_inet_ntoa(struct in_addr ip) { static char str[20]; - sprintf (str, "%d.%d.%d.%d", ip.s_addr & 0xFF, (ip.s_addr >> 8) & 0xFF, - (ip.s_addr >> 16) & 0xFF, (ip.s_addr >> 24) & 0xFF); + if (sim_end) + sprintf (str, "%d.%d.%d.%d", ip.s_addr & 0xFF, (ip.s_addr >> 8) & 0xFF, + (ip.s_addr >> 16) & 0xFF, (ip.s_addr >> 24) & 0xFF); + else + sprintf (str, "%d.%d.%d.%d", (ip.s_addr >> 24) & 0xFF, (ip.s_addr >> 16) & 0xFF, + (ip.s_addr >> 8) & 0xFF, ip.s_addr & 0xFF); return str; } @@ -1947,6 +2145,7 @@ t_stat imp_set_mac (UNIT* uptr, int32 val, CONST char* cptr, void* desc) if (status != SCPE_OK) return status; + memcpy(&imp_data.bcast, &broadcast_ethaddr, 6); return SCPE_OK; } @@ -1978,6 +2177,10 @@ t_stat imp_set_ip (UNIT* uptr, int32 val, CONST char* cptr, void* desc) if (ipv4_inet_aton (abuf, &ip)) { imp_data.ip = ip.s_addr; imp_data.ip_mask = htonl(mask[imp_data.maskbits]); + if (uptr->flags & UNIT_DHCP) { + uptr->flags &= ~UNIT_DHCP; + return sim_messagef (SCPE_OK, "IMP DHCP disabled\n"); + } return SCPE_OK; } return SCPE_ARG; @@ -1999,7 +2202,11 @@ t_stat imp_set_gwip (UNIT* uptr, int32 val, CONST char* cptr, void* desc) if (uptr->flags & UNIT_ATT) return SCPE_ALATT; if (ipv4_inet_aton (cptr, &ip)) { - imp_data.gwip = ip.s_addr; + imp_data.gwip = ip.s_addr; + if (uptr->flags & UNIT_DHCP) { + uptr->flags &= ~UNIT_DHCP; + return sim_messagef (SCPE_OK, "IMP DHCP disabled\n"); + } return SCPE_OK; } return SCPE_ARG; @@ -2007,9 +2214,18 @@ t_stat imp_set_gwip (UNIT* uptr, int32 val, CONST char* cptr, void* desc) t_stat imp_show_dhcpip (FILE *st, UNIT *uptr, int32 val, CONST void *desc) { - struct in_addr ip; - ip.s_addr = imp_data.dhcpip; - fprintf (st, "DHCPIP=%s", ipv4_inet_ntoa(ip)); + if (!(uptr->flags & UNIT_DHCP)) { + fprintf (st, "DHCP disabled"); + } else { + struct in_addr ip; + ip.s_addr = imp_data.dhcpip; + fprintf (st, "DHCP Server IP=%s", ipv4_inet_ntoa(ip)); + if (imp_data.dhcp_state == DHCP_STATE_BOUND) { + fprintf (st, ", Lease Expires in %d seconds", imp_data.dhcp_lease); + } else { + fprintf (st, ", State:%s, Waited %d seconds", dhcp_state_names[imp_data.dhcp_state], imp_data.dhcp_wait_time); + } + } return SCPE_OK; } @@ -2057,9 +2273,16 @@ t_stat imp_reset (DEVICE *dptr) int i; struct imp_packet *p; - /* Clear ARP table. */ - for (i = 0; i < IMP_ARPTAB_SIZE; i++) { - arp_table[i].ipaddr = 0; + for (i = 0; i < 6; i++) { + if (imp_data.mac[i] != 0) + break; + } + if (i == 6) { /* First call to reset? */ + /* Set a default MAC address in a BBN assigned OID range no longer in use */ + imp_set_mac (dptr->units, 0, "00:00:02:00:00:00/24", NULL); + /* Clear ARP table. */ + memset(imp_data.arp_table, 0, sizeof(imp_data.arp_table)); + imp_data.dhcp_state = DHCP_STATE_OFF; } /* Clear queues. */ imp_data.sendq = NULL; @@ -2072,8 +2295,7 @@ t_stat imp_reset (DEVICE *dptr) /* Fix last entry */ imp_data.freeq = p; imp_data.init_state = 0; - last_coni = sim_interval; - imp_data.dhcp_state = DHCP_STATE_OFF; + last_coni = sim_gtime(); return SCPE_OK; } @@ -2082,6 +2304,7 @@ t_stat imp_attach(UNIT* uptr, CONST char* cptr) { t_stat status; char* tptr; + char buf[32]; /* Set to correct device number */ switch(GET_DTYPE(imp_unit[0].flags)) { @@ -2093,6 +2316,9 @@ t_stat imp_attach(UNIT* uptr, CONST char* cptr) imp_dib.dev_num = WA_IMP_DEVNUM; break; } + if (!(uptr->flags & UNIT_DHCP) && imp_data.ip == 0) + return sim_messagef (SCPE_NOATT, "%s: An IP Address must be specified when DHCP is disabled\n", imp_dev.name); + tptr = (char *) malloc(strlen(cptr) + 1); if (tptr == NULL) return SCPE_MEM; strcpy(tptr, cptr); @@ -2102,36 +2328,63 @@ t_stat imp_attach(UNIT* uptr, CONST char* cptr) free(tptr); return status; } + eth_mac_fmt(&imp_data.mac, buf); /* format ethernet mac address */ if (SCPE_OK != eth_check_address_conflict (&imp_data.etherface, &imp_data.mac)) { - char buf[32]; - - eth_mac_fmt(&imp_data.mac, buf); /* format ethernet mac address */ - sim_printf("%s: MAC Address Conflict on LAN for address %s\n", imp_dev.name, buf); eth_close(&imp_data.etherface); free(tptr); - return SCPE_NOATT; + return sim_messagef (SCPE_NOATT, "%s: MAC Address Conflict on LAN for address %s\n", imp_dev.name, buf); } - if (SCPE_OK != eth_filter(&imp_data.etherface, 1, &imp_data.mac, 1, 0)) { + if (SCPE_OK != eth_filter(&imp_data.etherface, 2, &imp_data.mac, 0, 0)) { eth_close(&imp_data.etherface); free(tptr); - return SCPE_NOATT; + return sim_messagef (SCPE_NOATT, "%s: Can't set packet filter for MAC Address %s\n", imp_dev.name, buf); } uptr->filename = tptr; uptr->flags |= UNIT_ATT; - eth_setcrc(&imp_data.etherface, 0); /* Don't need CRC */ + eth_setcrc(&imp_data.etherface, 0); /* Don't need CRC */ /* init read queue (first time only) */ status = ethq_init(&imp_data.ReadQ, 8); if (status != SCPE_OK) { eth_close(&imp_data.etherface); + uptr->filename = NULL; free(tptr); - return status; + return sim_messagef (status, "%s: Can't initialize receive queue\n", imp_dev.name); } - imp_data.sec_tim = 1000; - imp_data.dhcp_xid = XID; + /* Pick a relatively unique starting xid, presuming that the + MAC address has been verified unique on the LAN by eth_open */ + imp_data.dhcp_xid = (imp_data.mac[0] | (imp_data.mac[1] << 8) | (imp_data.mac[2] << 16) | (imp_data.mac[3] << 24)) + (uint32)time(NULL); imp_data.dhcp_state = DHCP_STATE_OFF; + memset(imp_data.arp_table, 0, sizeof(imp_data.arp_table)); + + /* If we're not doing DHCP and a gateway is defined on the network + then define a static APR entry for the gateway to facilitate + outbound routing */ + if (!(uptr->flags & UNIT_DHCP) && imp_data.gwip) { + ETH_PACK read_buffer; + struct imp_eth_hdr *hdr = (struct imp_eth_hdr *)(&read_buffer.msg[0]); + int type; + struct arp_entry *arp; + + imp_arp_arpout(&imp_data, imp_data.gwip); + sim_os_ms_sleep (300); /* wait for an ARP response to arrive */ + + /* empty the read queue and find ARP_REPLYs */ + do { + memset (&read_buffer, 0, sizeof(read_buffer)); + status = eth_read (&imp_data.etherface, &read_buffer, NULL); + type = ntohs(hdr->type); + if (type == ETHTYPE_ARP) + imp_arp_arpin(&imp_data, &read_buffer); + } while (read_buffer.len > 0); + if ((arp = imp_arp_lookup(&imp_data, imp_data.gwip))) + imp_arp_update(&imp_data, imp_data.gwip, &arp->ethaddr, ARP_DONT_AGE); + } + + eth_set_async (&imp_data.etherface, 0); /* Allow Asynchronous inbound packets */ + sim_activate_after(uptr+2, 1000000); /* Start Timer service */ return SCPE_OK; } @@ -2150,7 +2403,8 @@ t_stat imp_detach(UNIT* uptr) free(uptr->filename); uptr->filename = NULL; uptr->flags &= ~UNIT_ATT; - sim_cancel (uptr+1); /* stop the timer services */ + sim_cancel (uptr+1); /* stop the packet timing services */ + sim_cancel (uptr+2); /* stop the clock timer services */ } return SCPE_OK; } diff --git a/doc/ka10_doc.doc b/doc/ka10_doc.doc index 9bdca48..58e8d19 100644 Binary files a/doc/ka10_doc.doc and b/doc/ka10_doc.doc differ diff --git a/sim_ether.c b/sim_ether.c index cf5cf43..6754827 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -2118,9 +2118,7 @@ else { /* !tap: */ while (isspace(*devname)) ++devname; - if (!(*handle = (void*) sim_slirp_open(devname, opaque, &_slirp_callback, dptr, dbit))) - strlcpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE); - else { + if ((*handle = (void*) sim_slirp_open(devname, opaque, &_slirp_callback, dptr, dbit, errbuf, PCAP_ERRBUF_SIZE))) { *eth_api = ETH_API_NAT; *fd_handle = 0; } diff --git a/slirp_glue/sim_slirp.c b/slirp_glue/sim_slirp.c index b63af46..fe83f70 100644 --- a/slirp_glue/sim_slirp.c +++ b/slirp_glue/sim_slirp.c @@ -172,7 +172,7 @@ uint32 slirp_dbit; } #endif -SLIRP *sim_slirp_open (const char *args, void *opaque, packet_callback callback, DEVICE *dptr, uint32 dbit) +SLIRP *sim_slirp_open (const char *args, void *opaque, packet_callback callback, DEVICE *dptr, uint32 dbit, char *errbuf, size_t errbuf_size) { SLIRP *slirp = (SLIRP *)g_malloc0(sizeof(*slirp)); char *targs = g_strdup (args); @@ -191,6 +191,7 @@ slirp->maskbits = 24; slirp->dhcpmgmt = 1; slirp->db_chime = INVALID_SOCKET; inet_aton(DEFAULT_IP_ADDR,&slirp->vgateway); +pthread_mutex_init (&slirp->write_buffer_lock, NULL); err = 0; while (*tptr && !err) { @@ -209,7 +210,7 @@ while (*tptr && !err) { if (cptr && *cptr) slirp->tftp_path = g_strdup (cptr); else { - sim_printf ("Missing TFTP Path\n"); + strlcpy (errbuf, "Missing TFTP Path", errbuf_size); err = 1; } continue; @@ -218,7 +219,7 @@ while (*tptr && !err) { if (cptr && *cptr) slirp->boot_file = g_strdup (cptr); else { - sim_printf ("Missing DHCP Boot file name\n"); + strlcpy (errbuf, "Missing DHCP Boot file name", errbuf_size); err = 1; } continue; @@ -228,7 +229,7 @@ while (*tptr && !err) { if (cptr && *cptr) inet_aton (cptr, &slirp->vnameserver); else { - sim_printf ("Missing nameserver\n"); + strlcpy (errbuf, "Missing nameserver", errbuf_size); err = 1; } continue; @@ -253,7 +254,7 @@ while (*tptr && !err) { } while (name && *name); } else { - sim_printf ("Missing DNS search list\n"); + strlcpy (errbuf, "Missing DNS search list", errbuf_size); err = 1; } continue; @@ -266,7 +267,7 @@ while (*tptr && !err) { inet_aton (abuf, &slirp->vgateway); } else { - sim_printf ("Missing host\n"); + strlcpy (errbuf, "Missing host", errbuf_size); err = 1; } continue; @@ -279,7 +280,7 @@ while (*tptr && !err) { inet_aton (abuf, &slirp->vnetwork); } else { - sim_printf ("Missing network\n"); + strlcpy (errbuf, "Missing network", errbuf_size); err = 1; } continue; @@ -292,7 +293,7 @@ while (*tptr && !err) { if (cptr && *cptr) err = _parse_redirect_port (&slirp->rtcp, cptr, IS_UDP); else { - sim_printf ("Missing UDP port mapping\n"); + strlcpy (errbuf, "Missing UDP port mapping", errbuf_size); err = 1; } continue; @@ -301,12 +302,12 @@ while (*tptr && !err) { if (cptr && *cptr) err = _parse_redirect_port (&slirp->rtcp, cptr, IS_TCP); else { - sim_printf ("Missing TCP port mapping\n"); + strlcpy (errbuf, "Missing TCP port mapping", errbuf_size); err = 1; } continue; } - sim_printf ("Unexpected NAT argument: %s\n", gbuf); + snprintf (errbuf, errbuf_size - 1, "Unexpected NAT argument: %s", gbuf); err = 1; } if (err) { @@ -337,7 +338,6 @@ else { GPollFD pfd; int64_t rnd_val = qemu_clock_get_ns ((QEMUClockType)0) / 1000000; - pthread_mutex_init (&slirp->write_buffer_lock, NULL); slirp->gpollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD)); /* setup transmit packet wakeup doorbell */ do { diff --git a/slirp_glue/sim_slirp.h b/slirp_glue/sim_slirp.h index 00493ff..0411e3f 100644 --- a/slirp_glue/sim_slirp.h +++ b/slirp_glue/sim_slirp.h @@ -8,7 +8,7 @@ typedef struct sim_slirp SLIRP; typedef void (*packet_callback)(void *opaque, const unsigned char *buf, int len); -SLIRP *sim_slirp_open (const char *args, void *opaque, packet_callback callback, DEVICE *dptr, uint32 dbit); +SLIRP *sim_slirp_open (const char *args, void *opaque, packet_callback callback, DEVICE *dptr, uint32 dbit, char *errbuf, size_t errbuf_size); void sim_slirp_close (SLIRP *slirp); int sim_slirp_send (SLIRP *slirp, const char *msg, size_t len, int flags); int sim_slirp_select (SLIRP *slirp, int ms_timeout);