static void vsfip_dhcpd_input(void *param, struct vsfip_buffer_t *buf) { struct vsfip_dhcpd_t *dhcpd = (struct vsfip_dhcpd_t *)param; struct vsfip_netif_t *netif = dhcpd->netif; struct vsfip_dhcphead_t *head; struct vsfip_ipmac_assoc *assoc; uint8_t optlen, op; uint8_t *optptr; if (netif != buf->netif) { goto exit; } head = (struct vsfip_dhcphead_t *)buf->app.buffer; if ((head->op != DHCP_TOSERVER) || (head->magic != SYS_TO_BE_U32(DHCP_MAGIC)) || (head->htype != VSFIP_ETH_HWTYPE) || (head->hlen != 6)) { goto exit; } optlen = vsfip_dhcp_get_opt(buf, DHCPOPT_MSGTYPE, &optptr); if (optlen != DHCPOPT_MSGTYPE_LEN) { goto exit; } switch (optptr[0]) { case DHCPOP_DISCOVER: assoc = vsfip_dhcpd_get_assoc(netif, head->chaddr); if (NULL == assoc) { goto exit; } op = DHCPOP_OFFER; common_reply: head->op = DHCP_TOCLIENT; head->secs = 0; head->flags = 0; head->yiaddr = assoc->ip.addr.s_addr; head->siaddr = netif->ipaddr.addr.s_addr; buf->app.size = sizeof(*head); dhcpd->optlen = 0; vsfip_dhcp_append_opt(buf, &dhcpd->optlen, DHCPOPT_MSGTYPE, DHCPOPT_MSGTYPE_LEN, &op); vsfip_dhcp_append_opt(buf, &dhcpd->optlen, DHCPOPT_SERVERID, netif->ipaddr.size, netif->ipaddr.addr.s_addr_buf); { uint32_t lease_time = SYS_TO_BE_U32(0x80000000); vsfip_dhcp_append_opt(buf, &dhcpd->optlen, DHCPOPT_LEASE_TIME, netif->ipaddr.size, (uint8_t *)&lease_time); } vsfip_dhcp_append_opt(buf, &dhcpd->optlen, DHCPOPT_SUBNETMASK, netif->netmask.size, netif->netmask.addr.s_addr_buf); vsfip_dhcp_append_opt(buf, &dhcpd->optlen, DHCPOPT_ROUTER, netif->ipaddr.size, netif->ipaddr.addr.s_addr_buf); vsfip_dhcp_append_opt(buf, &dhcpd->optlen, DHCPOPT_DNSSERVER, netif->ipaddr.size, netif->ipaddr.addr.s_addr_buf); #ifdef VSFIP_CFG_HOSTNAME vsfip_dhcp_append_opt(buf, &dhcpd->optlen, DHCPOPT_HOSTNAME, strlen(VSFIP_CFG_HOSTNAME), (uint8_t *)VSFIP_CFG_HOSTNAME); #endif #ifdef VSFIP_CFG_DOMAIN vsfip_dhcp_append_opt(buf, &dhcpd->optlen, DHCPOPT_DOMAIN, strlen(VSFIP_CFG_DOMAIN), (uint8_t *)VSFIP_CFG_DOMAIN); #endif vsfip_dhcp_end_opt(buf, &dhcpd->optlen); dhcpd->sockaddr.sin_addr.addr.s_addr = assoc->ip.addr.s_addr; vsfip_netif_arp_add_assoc(dhcpd->netif, assoc->mac.size, assoc->mac.addr.s_addr_buf, assoc->ip.size, assoc->ip.addr.s_addr_buf); vsfip_udp_async_send(dhcpd->so, &dhcpd->sockaddr, buf); dhcpd->so->remote_sockaddr.sin_addr.addr.s_addr = VSFIP_IPADDR_ANY; return; case DHCPOP_REQUEST: assoc = vsfip_dhcpd_get_assoc(netif, head->chaddr); if (NULL == assoc) { goto exit; } optlen = vsfip_dhcp_get_opt(buf, DHCPOPT_REQIP, &optptr); if ((4 == optlen) && (*(uint32_t *)optptr != assoc->ip.addr.s_addr)) { op = DHCPOP_NAK; } else { op = DHCPOP_ACK; } goto common_reply; } exit: vsfip_buffer_release(buf); }
static struct vsfsm_state_t * vsfip_dhcpc_evt_handler(struct vsfsm_t *sm, vsfsm_evt_t evt) { struct vsfip_dhcpc_t *dhcpc = (struct vsfip_dhcpc_t *)sm->user_data; struct vsfip_netif_t *netif = dhcpc->netif; switch (evt) { case VSFSM_EVT_INIT: dhcpc->ready = true; dhcpc->retry = 0; retry: dhcpc->xid = vsfip_dhcpc.xid++; dhcpc->so = vsfip_socket(AF_INET, IPPROTO_UDP); if (NULL == dhcpc->so) { goto cleanup; } vsfip_socket_cb(dhcpc->so, dhcpc, vsfip_dhcpc_input, NULL); if (vsfip_bind(dhcpc->so, DHCP_CLIENT_PORT)) { goto cleanup; } vsfip_listen(dhcpc->so, 0); // if address already allocated, do resume, send request again if (dhcpc->ipaddr.size != 0) { goto dhcp_request; } // discover memset(&netif->ipaddr, 0, sizeof(netif->ipaddr)); dhcpc->ipaddr.size = 0; if (vsfip_dhcpc_init_msg(dhcpc, (uint8_t)DHCPOP_DISCOVER) < 0) { goto cleanup; } vsfip_dhcp_end_opt(dhcpc->outbuffer, &dhcpc->optlen); dhcpc->sockaddr.sin_addr.addr.s_addr = 0xFFFFFFFF; vsfip_udp_async_send(dhcpc->so, &dhcpc->sockaddr, dhcpc->outbuffer); dhcpc->so->remote_sockaddr.sin_addr.addr.s_addr = VSFIP_IPADDR_ANY; dhcpc->to = vsftimer_create(sm, 5000, 1, VSFIP_DHCP_EVT_TIMEROUT); break; case VSFIP_DHCP_EVT_SEND_REQUEST: dhcp_request: vsftimer_free(dhcpc->to); if (vsfip_dhcpc_init_msg(dhcpc, (uint8_t)DHCPOP_REQUEST) < 0) { goto cleanup; } vsfip_dhcp_append_opt(dhcpc->outbuffer, &dhcpc->optlen, DHCPOPT_REQIP, dhcpc->ipaddr.size, dhcpc->ipaddr.addr.s_addr_buf); vsfip_dhcp_end_opt(dhcpc->outbuffer, &dhcpc->optlen); dhcpc->sockaddr.sin_addr.addr.s_addr = 0xFFFFFFFF; vsfip_udp_async_send(dhcpc->so, &dhcpc->sockaddr, dhcpc->outbuffer); dhcpc->so->remote_sockaddr.sin_addr.addr.s_addr = VSFIP_IPADDR_ANY; dhcpc->to = vsftimer_create(sm, 2000, 1, VSFIP_DHCP_EVT_TIMEROUT); break; case VSFIP_DHCP_EVT_READY: vsftimer_free(dhcpc->to); // update netif->ipaddr dhcpc->ready = 1; netif->ipaddr = dhcpc->ipaddr; netif->gateway = dhcpc->gw; netif->netmask = dhcpc->netmask; netif->dns[0] = dhcpc->dns[0]; netif->dns[1] = dhcpc->dns[1]; // timer out for resume // vsftimer_create(sm, 2000, 1, VSFIP_DHCP_EVT_TIMEROUT); goto cleanup; break; case VSFIP_DHCP_EVT_TIMEROUT: // maybe need to resume, set the ready to false dhcpc->ready = false; cleanup: if (dhcpc->so != NULL) { vsfip_close(dhcpc->so); dhcpc->so = NULL; } if (!dhcpc->ready && (++dhcpc->retry < VSFIP_DHCPC_RETRY_CNT)) { goto retry; } // notify callder if (dhcpc->update_sem.evt != VSFSM_EVT_NONE) { vsfsm_sem_post(&dhcpc->update_sem); } break; } return NULL; }