vsf_err_t vsfip_dhcpd_start(struct vsfip_netif_t *netif, struct vsfip_dhcpd_t *dhcpd) { if ((NULL == netif) || (NULL == dhcpd)) { return VSFERR_FAIL; } dhcpd->alloc_idx = 1; netif->dhcp.dhcpd = dhcpd; dhcpd->netif = netif; memset(&dhcpd->assoc, 0, sizeof(dhcpd->assoc)); dhcpd->sockaddr.sin_port = DHCP_CLIENT_PORT; dhcpd->sockaddr.sin_addr.size = 4; dhcpd->so = vsfip_socket(AF_INET, IPPROTO_UDP); if (NULL == dhcpd->so) { goto cleanup; } vsfip_socket_cb(dhcpd->so, dhcpd, vsfip_dhcpd_input, NULL); if (vsfip_bind(dhcpd->so, DHCP_SERVER_PORT)) { goto cleanup; } return vsfip_listen(dhcpd->so, 0); cleanup: if (dhcpd->so != NULL) { vsfip_close(dhcpd->so); dhcpd->so = NULL; } return VSFERR_FAIL; }
static vsf_err_t vsfip_telnetd_session_tx_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt) { struct vsfip_telnetd_session_t *session = (struct vsfip_telnetd_session_t *)pt->user_data; uint32_t len; vsf_err_t err; vsfsm_pt_begin(pt); session->caller_txpt.sm = pt->sm; while (!session->disconnect) { len = stream_get_data_size(session->stream_tx); if (!len && vsfsm_sem_pend(&session->stream_tx_sem, pt->sm)) { vsfsm_pt_wfe(pt, VSFIP_TELNETD_EVT_STREAM_IN); if (session->disconnect) break; continue; } retry_alloc_buf: session->outbuf = VSFIP_TCPBUF_GET(len); if (NULL == session->outbuf) { vsfsm_pt_delay(pt, 5); if (session->disconnect) break; goto retry_alloc_buf; } session->outbuf->app.size = stream_read(session->stream_tx, &session->outbuf->app); if (!session->outbuf->app.size) { vsfip_buffer_release(session->outbuf); continue; } session->caller_txpt.state = 0; vsfsm_pt_entry(pt); err = vsfip_tcp_send(&session->caller_txpt, evt, session->so, &session->so->remote_sockaddr, session->outbuf, false); if (err > 0) return err; else if (err < 0) { session->disconnect = true; } } // close tcp socket session->caller_txpt.state = 0; vsfsm_pt_entry(pt); err = vsfip_tcp_close(&session->caller_txpt, evt, session->so); if (err > 0) return err; // close socket no matter if tcp closed OK or not vsfip_close(session->so); session->connected = false; vsfsm_pt_end(pt); return VSFERR_NONE; }
static vsf_err_t vsfip_telnetd_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt) { struct vsfip_telnetd_t *telnetd = (struct vsfip_telnetd_t *)pt->user_data; vsf_err_t err = VSFERR_NONE; int i; vsfsm_pt_begin(pt); telnetd->caller_pt.sm = pt->sm; telnetd->so = vsfip_socket(AF_INET, IPPROTO_TCP); if (NULL == telnetd->so) { return VSFERR_FAIL; } if ((vsfip_bind(telnetd->so, telnetd->port) != 0) || (vsfip_listen(telnetd->so, telnetd->session_num) != 0)) { err = VSFERR_FAIL; goto fail_socket_connect; } while (1) { telnetd->caller_pt.state = 0; vsfsm_pt_entry(pt); err = vsfip_tcp_accept(&telnetd->caller_pt, evt, telnetd->so, &telnetd->cur_session); if (err > 0) return err; else if (err < 0) { continue; } // get session for (i = 0; i < telnetd->session_num; i++) { if (!telnetd->sessions[i].connected) { struct vsfip_telnetd_session_t *session = &telnetd->sessions[i]; session->connected = true; session->disconnect = false; session->so = telnetd->cur_session; session->stream_rx->callback_tx.param = session; session->stream_rx->callback_tx.on_inout = vsfip_telnetd_session_stream_on_out; session->stream_tx->callback_rx.param = session; session->stream_tx->callback_rx.on_inout = vsfip_telnetd_session_stream_on_in; stream_connect_tx(session->stream_rx); stream_connect_rx(session->stream_tx); vsfsm_sem_init(&session->stream_tx_sem, 0, VSFIP_TELNETD_EVT_STREAM_IN); vsfsm_sem_init(&session->stream_rx_sem, 0, VSFIP_TELNETD_EVT_STREAM_OUT); session->txpt.thread = vsfip_telnetd_session_tx_thread; session->txpt.user_data = session; session->rxpt.thread = vsfip_telnetd_session_rx_thread; session->rxpt.user_data = session; vsfsm_pt_init(&session->txsm, &session->txpt); vsfsm_pt_init(&session->rxsm, &session->rxpt); break; } } if (i == telnetd->session_num) { telnetd->caller_pt.state = 0; vsfsm_pt_entry(pt); err = vsfip_tcp_close(&telnetd->caller_pt, evt, telnetd->cur_session); if (err > 0) return err; vsfip_close(telnetd->cur_session); } } fail_socket_connect: vsfip_close(telnetd->so); telnetd->so = NULL; vsfsm_pt_end(pt); return VSFERR_NONE; }
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; }