Beispiel #1
0
static vsf_err_t vsfip_dhcpc_init_msg(struct vsfip_dhcpc_t *dhcpc, uint8_t op)
{
	struct vsfip_netif_t *netif = dhcpc->netif;
	struct vsfip_buffer_t *buf;
	struct vsfip_dhcphead_t *head;

	dhcpc->outbuffer = VSFIP_UDPBUF_GET(sizeof(struct vsfip_dhcphead_t));
	if (NULL == dhcpc->outbuffer)
	{
		return VSFERR_FAIL;
	}
	buf = dhcpc->outbuffer;

	head = (struct vsfip_dhcphead_t *)buf->app.buffer;
	memset(head, 0, sizeof(struct vsfip_dhcphead_t));
	head->op = DHCP_TOSERVER;
	head->htype = netif->drv->hwtype;
	head->hlen = netif->macaddr.size;
	head->xid = dhcpc->xid;
	// shift right 10-bit for div 1000
	head->secs = 0;
	memcpy(head->chaddr, netif->macaddr.addr.s_addr_buf, netif->macaddr.size);
	head->magic = SYS_TO_BE_U32(DHCP_MAGIC);
	dhcpc->optlen = 0;
	vsfip_dhcp_append_opt(buf, &dhcpc->optlen, DHCPOPT_MSGTYPE,
							DHCPOPT_MSGTYPE_LEN, &op);
	{
		uint16_t tmp16 = SYS_TO_BE_U16(576);
		// RFC 2132 9.10, message size MUST be >= 576
		vsfip_dhcp_append_opt(buf, &dhcpc->optlen, DHCPOPT_MAXMSGSIZE,
							DHCPOPT_MAXMSGSIZE_LEN, (uint8_t *)&tmp16);
	}
	{
		uint8_t requestlist[] = {DHCPOPT_SUBNETMASK,
			DHCPOPT_ROUTER, DHCPOPT_DNSSERVER, DHCPOPT_BROADCAST};
		vsfip_dhcp_append_opt(buf, &dhcpc->optlen, DHCPOPT_PARAMLIST,
								sizeof(requestlist), requestlist);
	}
#ifdef VSFIP_CFG_HOSTNAME
	vsfip_dhcp_append_opt(buf, &dhcpc->optlen, DHCPOPT_HOSTNAME,
					strlen(VSFIP_CFG_HOSTNAME), (uint8_t *)VSFIP_CFG_HOSTNAME);
#endif

	return VSFERR_NONE;
}
Beispiel #2
0
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);
}
Beispiel #3
0
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;
}