static void process_timeout_event(struct state *s, time_t now) { int ret = 0; /* * Is the link up? If not, try again in 1 second. */ if (!netdev_running(s->dev)) { s->expire = now + 1; s->state = s->restart_state; return; } /* * If we had an error, restore a sane state to * restart from. */ if (s->state == DEVST_ERROR) s->state = s->restart_state; /* * Now send a packet depending on our state. */ switch (s->state) { case DEVST_BOOTP: ret = bootp_send_request(s->dev); s->restart_state = DEVST_BOOTP; break; case DEVST_DHCPDISC: ret = dhcp_send_discover(s->dev); s->restart_state = DEVST_DHCPDISC; break; case DEVST_DHCPREQ: ret = dhcp_send_request(s->dev); s->restart_state = DEVST_DHCPDISC; break; } if (ret == -1) { s->state = DEVST_ERROR; s->expire = now + 10; } else { s->expire = now + s->retry_period; s->retry_period *= 2; if (s->retry_period > 60) s->retry_period = 60; } }
void dhcp_check_timeout(void) { if(retry_count < DHCP_MAX_RETRY) { if(next_dhcp_time < dhcp_time) { dhcp_time = 0; next_dhcp_time = dhcp_time + DHCP_WAIT_TIME; retry_count++; switch(dhcp_state) { case STATE_DHCP_DISCOVER: { dhcp_send_discover(dhcp_socket); break; } case STATE_DHCP_REQUEST: { dhcp_send_request(dhcp_socket); break; } case STATE_DHCP_REREQUEST: { dhcp_send_request(dhcp_socket); break; } default : { break; } } } } else { dhcp_reset_time(); DHCP_timeout = 1; dhcp_send_discover(dhcp_socket); dhcp_state = STATE_DHCP_DISCOVER; } }
void dhcp_app_call(void) { if(uip_newdata()) { switch(dhcp_s.state) { case DHCP_STATE_OFFER: dhcp_parse_offer(); break; case DHCP_STATE_ACK: dhcp_parse_ack(); break; } } if(uip_poll()) { switch(dhcp_s.state) { case DHCP_STATE_BOOT_WAIT: if(get_clock() > dhcp_s.dhcp_renew_time) dhcp_s.state = DHCP_STATE_DISCOVER; break; case DHCP_STATE_DISCOVER: dhcp_send_discover(); break; case DHCP_STATE_REQUEST: dhcp_send_request(); break; case DHCP_STATE_WAIT_RENEW: if(get_clock() > dhcp_s.dhcp_renew_time) dhcp_s.state = DHCP_STATE_REQUEST; break; } } }
/* * Returns: * 0 = Not handled, try again later * 1 = Handled */ static int process_receive_event(struct state *s, time_t now) { int handled = 1; switch (s->state) { case DEVST_ERROR: return 0; /* Not handled */ case DEVST_COMPLETE: return 0; /* Not handled as already configured */ case DEVST_BOOTP: s->restart_state = DEVST_BOOTP; switch (bootp_recv_reply(s->dev)) { case -1: s->state = DEVST_ERROR; break; case 0: handled = 0; break; case 1: s->state = DEVST_COMPLETE; dprintf("\n bootp reply\n"); break; } break; case DEVST_DHCPDISC: s->restart_state = DEVST_DHCPDISC; switch (dhcp_recv_offer(s->dev)) { case -1: s->state = DEVST_ERROR; break; case 0: handled = 0; break; case DHCPOFFER: /* Offer received */ s->state = DEVST_DHCPREQ; dhcp_send_request(s->dev); break; } break; case DEVST_DHCPREQ: s->restart_state = DEVST_DHCPDISC; switch (dhcp_recv_ack(s->dev)) { case -1: /* error */ s->state = DEVST_ERROR; break; case 0: handled = 0; break; case DHCPACK: /* ACK received */ s->state = DEVST_COMPLETE; break; case DHCPNAK: /* NAK received */ s->state = DEVST_DHCPDISC; break; } break; default: dprintf("\n"); handled = 0; break; } switch (s->state) { case DEVST_COMPLETE: complete_device(s->dev); break; case DEVST_ERROR: /* error occurred, try again in 10 seconds */ s->expire = now + 10; break; } return handled; }
/* Called at the reception of a DHCP Offer packet. p points to the DHCP Offer */ void dhcp_request(FullPacket *p) { dhcp_send_request(p->dhcp.xid, p->dhcp.yiaddr, ntohl(dhcp_get_option_simple(p->dhcp.options+4, OPTION_DHCP_SERVER_IDENTIFIER)), 1); }
int8_t handle_dhcp(uint8_t * packet, int32_t packetsize) { struct btphdr * btph; struct iphdr * iph; dhcp_options_t opt; memset(&opt, 0, sizeof(dhcp_options_t)); btph = (struct btphdr *) packet; iph = (struct iphdr *) packet - sizeof(struct udphdr) - sizeof(struct iphdr); if (btph -> op != 2) return -1; // it is not Boot Reply if(response_buffer) { if(packetsize <= 1720) memcpy(response_buffer, packet, packetsize); else memcpy(response_buffer, packet, 1720); } if (memcmp(btph -> vend, dhcp_magic, 4)) { // It is BootP - RFC 951 dhcp_own_ip = htonl(btph -> yiaddr); dhcp_siaddr_ip = htonl(btph -> siaddr); dhcp_server_ip = htonl(iph -> ip_src); if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) { strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, sizeof(btph -> sname)); dhcp_tftp_name[sizeof(btph -> sname)] = 0; } if (strlen((char *) btph -> file)) { strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file)); dhcp_filename[sizeof(btph -> file)] = 0; } dhcp_state = DHCP_STATE_SUCCESS; return 0; } // decode options if (!dhcp_decode_options(btph -> vend, packetsize - sizeof(struct btphdr) + sizeof(btph -> vend), &opt)) { return -1; // can't decode options } if (opt.overload) { int16_t decode_res = 0; uint8_t options[1024]; // buffer for merged options uint32_t opt_len; // move 1-st part of options from vend field into buffer opt_len = packetsize - sizeof(struct btphdr) + sizeof(btph -> vend) - 4; memcpy(options, btph -> vend, opt_len + 4); // add other parts switch (opt.overload) { case DHCP_OVERLOAD_FILE: decode_res = dhcp_merge_options(options + 4, &opt_len, btph -> file, sizeof(btph -> file)); break; case DHCP_OVERLOAD_SNAME: decode_res = dhcp_merge_options(options + 4, &opt_len, btph -> sname, sizeof(btph -> sname)); break; case DHCP_OVERLOAD_BOTH: decode_res = dhcp_merge_options(options + 4, &opt_len, btph -> file, sizeof(btph -> file)); if (!decode_res) break; decode_res = dhcp_merge_options(options + 4, &opt_len, btph -> sname, sizeof(btph -> sname)); break; } if (!decode_res) return -1; // bad options in sname/file fields // decode merged options if (!dhcp_decode_options(options, opt_len + 4, &opt)) { return -1; // can't decode options } } if (!opt.msg_type) { // It is BootP with Extensions - RFC 1497 // retrieve conf. settings from BootP - reply dhcp_own_ip = htonl(btph -> yiaddr); dhcp_siaddr_ip = htonl(btph -> siaddr); if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) { strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, sizeof(btph -> sname)); dhcp_tftp_name[sizeof(btph -> sname)] = 0; } if (strlen((char *) btph -> file)) { strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file)); dhcp_filename[sizeof(btph -> file)] = 0; } // retrieve DHCP-server IP from IP-header dhcp_server_ip = iph -> htonl(ip_src); dhcp_state = DHCP_STATE_SUCCESS; } else { // It is DHCP - RFC 2131 & RFC 2132 // opt contains parameters from server switch (dhcp_state) { case DHCP_STATE_SELECT : if (opt.msg_type == DHCPOFFER) { dhcp_own_ip = htonl(btph -> yiaddr); dhcp_server_ip = opt.server_ID; dhcp_send_request(); dhcp_state = DHCP_STATE_REQUEST; } return 0; case DHCP_STATE_REQUEST : switch (opt.msg_type) { case DHCPNACK : dhcp_own_ip = 0; dhcp_server_ip = 0; dhcp_state = DHCP_STATE_FAULT; break; case DHCPACK : dhcp_own_ip = htonl(btph -> yiaddr); dhcp_server_ip = opt.server_ID; dhcp_siaddr_ip = htonl(btph -> siaddr); if (opt.flag[DHCP_TFTP_SERVER]) { strcpy((char *) dhcp_tftp_name, (char *) opt.tftp_server); } else { strcpy((char *) dhcp_tftp_name, ""); if ((opt.overload != DHCP_OVERLOAD_SNAME && opt.overload != DHCP_OVERLOAD_BOTH) && !dhcp_siaddr_ip) { strncpy((char *) dhcp_tftp_name, (char *) btph->sname, sizeof(btph -> sname)); dhcp_tftp_name[sizeof(btph->sname)] = 0; } } if (opt.flag[DHCP_BOOTFILE]) { strcpy((char *) dhcp_filename, (char *) opt.bootfile); } else { strcpy((char *) dhcp_filename, ""); if (opt.overload != DHCP_OVERLOAD_FILE && opt.overload != DHCP_OVERLOAD_BOTH && strlen((char *) btph -> file)) { strncpy((char *) dhcp_filename, (char *) btph->file, sizeof(btph->file)); dhcp_filename[sizeof(btph -> file)] = 0; } } dhcp_state = DHCP_STATE_SUCCESS; break; default: break; // Unused DHCP-message - do nothing } break; default : return -1; // Illegal DHCP-client state } } if (dhcp_state == DHCP_STATE_SUCCESS) { // initialize network entity with real own_ip // to be able to answer for foreign requests set_ipv4_address(dhcp_own_ip); /* Subnet mask */ if (opt.flag[DHCP_MASK]) { /* Router */ if (opt.flag[DHCP_ROUTER]) { set_ipv4_router(opt.router_IP); set_ipv4_netmask(opt.subnet_mask); } } /* DNS-server */ if (opt.flag[DHCP_DNS]) { dns_init(opt.dns_IP); } } return 0; }
void dhcp_check_state(const uint8_t s) { if(dhcp_state == STATE_DHCP_DISCOVER && DHCP_timeout == 1) { DHCP_timeout = 0; logethw("DHCP timeout, trying again\n\r"); return; } uint32_t len; uint8_t type = 0; if(ethernet_low_level_get_status(s) != ETH_VAL_SN_SR_SOCK_CLOSED) { if((len = ethernet_low_level_get_received_data_length(s)) > 0) { type = dhcp_parse_msg(s, len); } } else { dhcp_create_socket(s); } switch(dhcp_state) { case STATE_DHCP_DISCOVER: { if(type == DHCP_OFFER) { dhcp_reset_time(); dhcp_send_request(s); dhcp_state = STATE_DHCP_REQUEST; } else { dhcp_check_timeout(); } break; } case STATE_DHCP_REQUEST: { if(type == DHCP_ACK) { dhcp_reset_time(); if(dhcp_check_leased_ip()) { dhcp_set_network(); dhcp_state = STATE_DHCP_LEASED; } else { dhcp_state = STATE_DHCP_DISCOVER; } } else if(type == DHCP_NAK) { dhcp_reset_time(); dhcp_state = STATE_DHCP_DISCOVER; } else { dhcp_check_timeout(); } break; } case STATE_DHCP_LEASED: { if((lease_time.l_val != 0xffffffff) && ((lease_time.l_val/2) < dhcp_time)) { type = 0; memcpy(dhcp_old_ip, ethernet_status.ip, 4); dhcp_xid++; dhcp_send_request(s); dhcp_state = STATE_DHCP_REREQUEST; dhcp_reset_time(); } break; } case STATE_DHCP_REREQUEST: { if(type == DHCP_ACK) { memcpy(dhcp_old_ip, ethernet_status.ip, 4); dhcp_reset_time(); dhcp_state = STATE_DHCP_LEASED; } else if(type == DHCP_NAK) { dhcp_reset_time(); dhcp_state = STATE_DHCP_DISCOVER; } else { dhcp_check_timeout(); } break; } case STATE_DHCP_RELEASE: { break; } default: { break; } } }