From 2a42ad20b9730706ad371ae3787d4597c4e42276 Mon Sep 17 00:00:00 2001 From: sharath reddy Date: Tue, 4 Jun 2019 11:53:49 +0530 Subject: Feature: 19.04 part-2 Change-Id: I0b52a6bb67c25c7955d58e29eb81a3cc9efea9e9 Signed-off-by: sharath reddy --- stacks/lwip_stack/lwip_src/api/nsfw_msg.c | 23 + stacks/lwip_stack/lwip_src/api/spl_api.c | 50 + stacks/lwip_stack/lwip_src/api/spl_api_msg.c | 3320 +++++++++++++++++++++++++ stacks/lwip_stack/lwip_src/api/spl_netbuf.c | 57 + stacks/lwip_stack/lwip_src/api/spl_netifapi.c | 279 +++ stacks/lwip_stack/lwip_src/api/spl_sbr.c | 477 ++++ stacks/lwip_stack/lwip_src/api/spl_tcpip.c | 1531 ++++++++++++ 7 files changed, 5737 insertions(+) create mode 100644 stacks/lwip_stack/lwip_src/api/nsfw_msg.c create mode 100644 stacks/lwip_stack/lwip_src/api/spl_api.c create mode 100644 stacks/lwip_stack/lwip_src/api/spl_api_msg.c create mode 100644 stacks/lwip_stack/lwip_src/api/spl_netbuf.c create mode 100644 stacks/lwip_stack/lwip_src/api/spl_netifapi.c create mode 100644 stacks/lwip_stack/lwip_src/api/spl_sbr.c create mode 100644 stacks/lwip_stack/lwip_src/api/spl_tcpip.c (limited to 'stacks/lwip_stack/lwip_src/api') diff --git a/stacks/lwip_stack/lwip_src/api/nsfw_msg.c b/stacks/lwip_stack/lwip_src/api/nsfw_msg.c new file mode 100644 index 0000000..338f803 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/nsfw_msg.c @@ -0,0 +1,23 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "nsfw_msg.h" +/* *INDENT-OFF* */ +msg_fun g_msg_module_fun_array[MAX_MODULE_TYPE] = {NULL}; +msg_fun g_msg_module_major_fun_array[MAX_MODULE_TYPE][MAX_MAJOR_TYPE] = {{NULL}}; +msg_fun g_msg_module_major_minor_fun_array[MAX_MODULE_TYPE][MAX_MAJOR_TYPE][MAX_MINOR_TYPE] = {{{NULL}}}; +msg_fun g_msg_unsupport_fun = NULL; +/* *INDENT-ON* */ diff --git a/stacks/lwip_stack/lwip_src/api/spl_api.c b/stacks/lwip_stack/lwip_src/api/spl_api.c new file mode 100644 index 0000000..5f48d15 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/spl_api.c @@ -0,0 +1,50 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "nsfw_init_api.h" +//#include "sockets.h" +//#include + +#include "stackx_spl_share.h" +#include "stackx/spl_api.h" +//#include "stackx/ip.h" +#include "sharedmemory.h" +#include "spl_hal.h" +#include "nsfw_hal_api.h" +#include "alarm_api.h" +#include "nsfw_mt_config.h" +#include "nsfw_recycle_api.h" +#include "nstack_dmm_adpt.h" + +/* main entry for stackx */ +int spl_main_init(void *args) +{ + (void) args; + if (init_by_main_thread() < 0) + { + return -1; + } + + return 0; +} + +/* *INDENT-OFF* */ +NSFW_MODULE_NAME ("STACKX_MAIN") +NSFW_MODULE_PRIORITY (10) +NSFW_MODULE_DEPENDS (NSFW_ALARM_MODULE) +NSFW_MODULE_DEPENDS (NSFW_RECYCLE_MODULE) +NSFW_MODULE_INIT (spl_main_init) +/* *INDENT-ON* */ diff --git a/stacks/lwip_stack/lwip_src/api/spl_api_msg.c b/stacks/lwip_stack/lwip_src/api/spl_api_msg.c new file mode 100644 index 0000000..79ea0b6 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/spl_api_msg.c @@ -0,0 +1,3320 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "nsfw_msg.h" +#include "spl_opt.h" +#include "spl_ip_addr.h" +//#include "stackx_socket.h" +#include "cpuid.h" +//#include "sockets.h" +#include +#include +#include + +#include "stackx_prot_com.h" +#include "spl_api.h" +//#include "stackx/ip.h" +#include "sc_dpdk.h" +#include "spl_sbr.h" +//#include "maintain/spl_dfx.h" +#include "stackx_tx_box.h" +#include "spl_instance.h" +#include "spl_sockets.h" + +#include "nstack_dmm_adpt.h" + +#include "tcp.h" +#include "udp.h" +#include "pbuf.h" +#include "tcp_priv.h" +#include "init.h" +#include "timeouts.h" + +#include "stackx_pbuf_comm.h" +#include "spl_netbuf.h" +#include "spl_hal.h" +#include "sys_arch.h" +#include "tcpip.h" +#include "debug.h" +#ifdef HAL_LIB +#else +#include "rte_memcpy.h" +#endif +#include "nstack_epoll_api.h" + +extern struct tcp_pcb *tcp_bound_pcbs; +extern union tcp_listen_pcbs_t tcp_listen_pcbs; +extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a + state in which they accept or send + data. */ +extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ +extern struct tcp_pcb **const tcp_pcb_lists[NUM_TCP_PCB_LISTS]; +extern stackx_instance *p_def_stack_instance; +extern u16_t g_offSetArry[SPL_PBUF_MAX_LAYER]; + +#define TCP_FN_NULL 0 +#define TCP_FN_DEFAULT 1 +#define TCP_FN_STACKX 2 +#define TCP_FN_MAX 3 + +struct callback_fn tcp_fn[TCP_FN_MAX] = { + {NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {NULL, spl_tcp_recv_null, NULL, NULL, NULL, NULL}, + {spl_sent_tcp, spl_recv_tcp, spl_do_connected, spl_poll_tcp, spl_err_tcp, + NULL, spl_accept_function}, +}; + +// extern int nstack_get_nstack_fd_snapshot_from_proto_fd(int proto_fd); +extern void tcp_drop_conn(spl_netconn_t * conn); +extern void unlink_pcb(struct common_pcb *cpcb); +extern struct queue *get_msgbox(int tos); + +#define SPL_SET_NONBLOCKING_CONNECT(conn, val) \ +do { \ + if (val) \ + { \ + (conn)->flags |= SPL_NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \ + } \ + else \ + { \ + (conn)->flags &= ~SPL_NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \ + } \ + } while (0) + +#define SPL_IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & SPL_NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0) + +extern int tcpip_thread_control; + +void +spl_event_callback(struct spl_netconn *conn, enum spl_netconn_evt evt, + int postFlag) +{ + NSPOL_LOGDBG(SOCK_INFO, "Get event]conn=%p,evt=%d,postFlag=%d", conn, evt, + postFlag); + /* Get socket */ + if (!conn) + { + NSPOL_LOGDBG(SOCK_INFO, "conn=NULL"); + return; + } + + switch (evt) + { + case SPL_NETCONN_EVT_RCVPLUS: + __sync_fetch_and_add(&conn->rcvevent, 1); + if ((conn->epoll_flag) && (postFlag)) + { + NSTACK_EPOLL_EVENT_ADD(ADDR_SHTOL(conn->epInfo), EPOLLIN, + postFlag); + } + break; + case SPL_NETCONN_EVT_RCVMINUS: // This will never be reached + __sync_fetch_and_sub(&conn->rcvevent, 1); + if ((conn->epoll_flag) && (postFlag)) + { + NSTACK_EPOLL_EVENT_ADD(ADDR_SHTOL(conn->epInfo), EPOLLIN, + postFlag); + } + break; + case SPL_NETCONN_EVT_SENDPLUS: + conn->sendevent = 1; + if ((conn->epoll_flag) && (postFlag)) + { + NSTACK_EPOLL_EVENT_ADD(ADDR_SHTOL(conn->epInfo), EPOLLOUT, + postFlag); + } + break; + case SPL_NETCONN_EVT_SENDMINUS: + conn->sendevent = 0; + + if ((conn->epoll_flag) && (postFlag)) + { + NSTACK_EPOLL_EVENT_ADD(ADDR_SHTOL(conn->epInfo), EPOLLOUT, + postFlag); + } + break; + case SPL_NETCONN_EVT_ERROR: + conn->errevent |= EPOLLERR; + if ((conn->epoll_flag) && (postFlag)) + { + NSTACK_EPOLL_EVENT_ADD(ADDR_SHTOL(conn->epInfo), + conn->errevent, postFlag); + conn->errevent = 0; + } + break; +#if 1 + case SPL_NETCONN_EVT_ACCEPT: + __sync_fetch_and_add(&conn->rcvevent, 1); + if ((conn->epoll_flag) && (postFlag)) + { + NSTACK_EPOLL_EVENT_ADD(ADDR_SHTOL(conn->epInfo), EPOLLIN, + postFlag); + } + break; + + case SPL_NETCONN_EVT_HUP: + conn->errevent |= EPOLLHUP; + if ((conn->epoll_flag) && (postFlag)) + { + NSTACK_EPOLL_EVENT_ADD(ADDR_SHTOL(conn->epInfo), + conn->errevent, postFlag); + conn->errevent = 0; + } + break; + case SPL_NETCONN_EVT_RDHUP: + conn->errevent |= EPOLLRDHUP; + if ((conn->epoll_flag) && (postFlag)) + { + NSTACK_EPOLL_EVENT_ADD(ADDR_SHTOL(conn->epInfo), + conn->errevent, postFlag); + conn->errevent = 0; + } + break; +#endif + + default: + NSTCP_LOGERR("unknown event]conn=%p,event=%d", conn, evt); + return; + } + return; +} + +u8 get_shut_op(data_com_msg * m) +{ + if (m && m->param.module_type == MSG_MODULE_SBR + && m->param.major_type == SPL_TCPIP_NEW_MSG_API) + { + if (m->param.minor_type == SPL_API_DO_CLOSE) + return ((msg_close *) (m->buffer))->shut; + + if (m->param.minor_type == SPL_API_DO_DELCON) + return ((msg_delete_netconn *) (m->buffer))->shut; + } + + return SPL_NETCONN_SHUT_RDWR; +} + +/* + Never using head/tail to judge whether need to do enque/deque, just do enque&deque, the return val will tell you ring is full/empty or not + rtp_perf_ring never provid ring_full/ring_empty function; + one more thing the rtp_ring_enque/deque result must be checked. +*/ +err_t accept_enqueue(spl_netconn_t * conn, void *p) +{ + if (conn == NULL) + { + NSPOL_LOGERR("accept_enqueue: invalid input]conn=%p", conn); + return ERR_VAL; + } + + NSPOL_LOGDBG(NEW_RING_DEBUG, "accept_enqueue]conn=%p,p=%p", conn, p); + mring_handle ring = conn->recv_ring; + if (NULL == ring) + { + NSPOL_LOGERR("conn=%p accept new conn=%p enqueue ring addr is null", + conn, p); + return ERR_VAL; + } + + err_t retVal = ERR_MEM; + int enQSucCnt = 0; + int nTryCnt = 0; + do + { + enQSucCnt = nsfw_mem_ring_enqueue(ring, (void *) p); + if (1 == enQSucCnt) + { + retVal = ERR_OK; + break; + } + else if (0 == enQSucCnt) + { + sys_sleep_ns(0, 3000); + nTryCnt++; + } + else + { + retVal = ERR_VAL; + break; + } + } + while (nTryCnt < MAX_TRY_GET_MEMORY_TIMES); + + return retVal; +} + +err_t +accept_dequeue(spl_netconn_t * lconn, void **new_buf, + u32_t timeout /*miliseconds */ ) +{ + struct timespec starttm; + struct timespec endtm; + long timediff; + long timediff_sec; + u32_t timeout_sec = timeout / 1000; + +#define FAST_SLEEP_TIME 10000 +#define SLOW_SLEEP_TIME 500000 +#define FAST_RETRY_COUNT 100 + unsigned int retry_count = 0; + + if (NULL == lconn || NULL == new_buf) + { + NSPOL_LOGERR("accept_dequeue invalid input]conn=%p,newbuf=%p", lconn, + new_buf); + return ERR_ARG; + } + + if (timeout != 0) + { + /* Handle system time change side-effects */ + if (unlikely(0 != clock_gettime(CLOCK_MONOTONIC, &starttm))) + { + //NSPOL_LOGERR("Failed to get time]errno=%d", errno); + } + } + + mring_handle ring = lconn->recv_ring; + if (ring == NULL) + { + NSPOL_LOGERR("Get rtp_perf_ring failed]conn=%p", lconn); + return ERR_ARG; + } + + int nDequeRt; + int retVal; + while (1) + { + if ((lconn->shut_status) && (-1 != (int) timeout)) + { + retVal = ERR_VAL; + break; + } + + nDequeRt = nsfw_mem_ring_dequeue(ring, new_buf); + if (nDequeRt == 1) + { + retVal = ERR_OK; + break; + } + else if (nDequeRt == 0) + { + if ((int) timeout == -1) + { + retVal = ERR_WOULDBLOCK; + break; + } + + if (timeout != 0) + { + /* Handle system time change side-effects */ + if (unlikely(0 != clock_gettime(CLOCK_MONOTONIC, &endtm))) + { + //NSPOL_LOGERR("Failed to get time, errno = %d", errno); + } + timediff_sec = endtm.tv_sec - starttm.tv_sec; + if (timediff_sec >= timeout_sec) + { + timediff = endtm.tv_nsec > starttm.tv_nsec ? + (timediff_sec * 1000) + (endtm.tv_nsec - + starttm.tv_nsec) / + USEC_TO_SEC : (timediff_sec * 1000) - + ((starttm.tv_nsec - endtm.tv_nsec) / USEC_TO_SEC); + + /*NOTE: if user configured the timeout as say 0.5 ms, then timediff value + will be negetive if still 0.5 ms is not elapsed. this is intended and we should + not typecast to any unsigned type during this below if check */ + if (timediff > (long) timeout) + { + retVal = ERR_TIMEOUT; + break; + } + } + } + + /* reduce CPU usage in blocking mode */ + if (retry_count < FAST_RETRY_COUNT) + { + sys_sleep_ns(0, FAST_SLEEP_TIME); + retry_count++; + } + else + { + sys_sleep_ns(0, SLOW_SLEEP_TIME); + } + + continue; + } + else + { + retVal = ERR_VAL; + break; + } + } + + return retVal; +} + +err_t sp_enqueue(struct common_pcb * cpcb, void *p) +{ + mring_handle ring = NULL; + spl_netconn_t *conn = NULL; + int enQueRet = 0; + + if (cpcb == NULL || (NULL == (conn = cpcb->conn))) + { + NSTCP_LOGERR("conn NULL!"); + return ERR_VAL; + } + + NSPOL_LOGDBG(NEW_RING_DEBUG, "]conn=%p,buf=%p", cpcb->conn, p); + ring = conn->recv_ring; + if (NULL == ring) + { + NSPOL_LOGERR("Get rtp_perf_ring failed]conn=%p.", conn); + return ERR_CLSD; + } + + /* clear LOOP_SEND_FLAG to indicate that this pbuf has been given to upper layer */ + struct spl_pbuf *tmpbuf = p; + while (tmpbuf) + { + tmpbuf->res_chk.u8Reserve &= ~LOOP_SEND_FLAG; + tmpbuf = tmpbuf->next; + } + + enQueRet = nsfw_mem_ring_enqueue(ring, p); + if (1 != enQueRet) + { + NS_LOG_CTRL(LOG_CTRL_RECV_QUEUE_FULL, LOGTCP, "NSTCP", NSLOG_WAR, + "ringvbox_enqueue buf is full]conn=%p.", conn); + + return ERR_MEM; + } + + return ERR_OK; +} + +/** + * Receive callback function for UDP netconns. + * Posts the packet to conn->recvmbox or deletes it on memory error. + * + * @see udp.h (struct udp_pcb.recv) for parameters + */ + +static void +spl_recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, + const ip_addr_t * ipaddr, u16_t port) +{ + struct spl_netbuf *buf; + spl_netconn_t *conn = (spl_netconn_t *) arg; + struct spl_pbuf *spl_pb = NULL; //?? + + if (NULL == pcb) + { + NSPOL_LOGERR("recv_udp must have a pcb argument"); + pbuf_free(p); + return; + } + + if (NULL == arg) + { + NSPOL_LOGERR("recv_udp must have an argument"); + pbuf_free(p); + return; + } + /* //@TODO: malloc and Copy splbuf */ + struct common_pcb *cpcb = (struct common_pcb *) (conn->comm_pcb_data); + + u16_t proc_id = spl_get_lcore_id(); + + spl_pb = spl_pbuf_alloc_hugepage(SPL_PBUF_TRANSPORT, + p->tot_len + + g_offSetArry[SPL_PBUF_TRANSPORT], + SPL_PBUF_HUGE, proc_id, conn); + + if (!spl_pb) + { + NSPOL_LOGINF(TCP_DEBUG, "spl_pbuf_alloc_hugepage Failed!!!"); + return; + } + + pbuf_to_splpbuf_copy(spl_pb, p); + pbuf_free(p); + + buf = (struct spl_netbuf *) ((char *) spl_pb + sizeof(struct spl_pbuf)); + buf->p = spl_pb; + spl_ip_addr_set(&buf->addr, ipaddr); + buf->port = port; + + err_t ret = sp_enqueue(cpcb, (void *) spl_pb); + if (ret != ERR_OK) + { + NSPOL_LOGDBG(UDP_DEBUG, "mbox post failed"); + spl_netbuf_delete(buf); + return; + } + else + { + /* Register event with callback */ + NSPOL_LOGDBG(UDP_DEBUG | LWIP_DBG_TRACE, + "recv a udp packet: and api_event"); + SPL_API_EVENT(cpcb->conn, SPL_NETCONN_EVT_RCVPLUS, 1); + } +} + +/** + * Receive callback function for TCP netconns. + * Posts the packet to conn->recvmbox, but doesn't delete it on errors. + * + * @see tcp.h (struct tcp_pcb.recv) for parameters and return value + */ + +err_t spl_recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + struct spl_pbuf *spl_pb = NULL; + u32_t len; + + if (NULL == pcb) + { + NSTCP_LOGERR("recv_tcp must have a pcb argument"); + pbuf_free(p); + return ERR_ARG; + } + + if (NULL == arg) + { + NSTCP_LOGERR("must have an argument]pcb=%p", pcb); + pbuf_free(p); + return ERR_ARG; + } + + spl_netconn_t *conn = (spl_netconn_t *) arg; + + /* Unlike for UDP or RAW pcbs, don't check for available space + using recv_avail since that could break the connection + (data is already ACKed) */ + /* don't overwrite fatal errors! */ + (void) err; + if (p == NULL) + { + return ERR_OK; + } + + len = p->tot_len; + + u16_t proc_id = spl_get_lcore_id(); + + spl_pb = spl_pbuf_alloc_hugepage(SPL_PBUF_TRANSPORT, + p->tot_len + + g_offSetArry[SPL_PBUF_TRANSPORT], + SPL_PBUF_HUGE, proc_id, conn); + + if (!spl_pb) + { + NSPOL_LOGINF(TCP_DEBUG, "spl_pbuf_alloc_hugepage Failed!!!"); + return ERR_MEM; + } + + pbuf_to_splpbuf_copy(spl_pb, p); + pbuf_free(p); + + if (sp_enqueue((struct common_pcb *) conn->comm_pcb_data, (void *) spl_pb) + != ERR_OK) + { + NSPOL_LOGDBG(TCP_DEBUG, "sp_enqueue!=ERR_OK]conn=%p", conn); + spl_pbuf_free(spl_pb); + return ERR_MEM; + } + + SPL_API_EVENT(conn, SPL_NETCONN_EVT_RCVPLUS, 1); + conn->recv_avail_prod += len; + + return ERR_OK; +} + +/** + * Poll callback function for TCP netconns. + * Wakes up an application thread that waits for a connection to close + * or data to be sent. The application thread then takes the + * appropriate action to go on. + * + * Signals the conn->sem. + * netconn_close waits for conn->sem if closing failed. + * + * @see tcp.h (struct tcp_pcb.poll) for parameters and return value + */ +err_t spl_poll_tcp(void *arg, struct tcp_pcb * pcb) +{ + spl_netconn_t *conn = (spl_netconn_t *) arg; + struct tcp_pcb *tpcb = NULL; + + if (NULL == conn) + { + NSPOL_LOGERR("conn==NULL"); + return ERR_VAL; + } + + if (conn->state == SPL_NETCONN_WRITE) + { + (void) do_writemore(conn); + + /* do_close_internal, can release th PCB + and connection CB. so checking NETCONN_FLAG_CHECK_WRITESPACE should not be + done after do_close_internal. anyway this flag is used with data send.(do_writemore) */ + /* Did a nonblocking write fail before? Then check available write-space. */ + if (conn->flags & SPL_NETCONN_FLAG_CHECK_WRITESPACE) + { + tpcb = (struct tcp_pcb *) conn->private_data; + /* If the queued byte- or pbuf-count drops below the configured low-water limit, + let select mark this pcb as writable again. */ + if ((tpcb != NULL) && (tcp_sndbuf(tpcb) > TCP_SNDLOWAT) && + (tcp_sndqueuelen(tpcb) < TCP_SNDQUEUELOWAT)) + { + conn->flags &= ~SPL_NETCONN_FLAG_CHECK_WRITESPACE; + SPL_API_EVENT(conn, SPL_NETCONN_EVT_SENDPLUS, 1); + } + } + } + else if (conn->state == SPL_NETCONN_CLOSE) + { + (void) do_close_internal((struct common_pcb *) conn->comm_pcb_data, + 0); + } + + /* @todo: implement connect timeout here? */ + return ERR_OK; +} + +/** + * Default receive callback that is called if the user didn't register + * a recv callback for the pcb. + */ +err_t +spl_tcp_recv_null(void *arg, struct tcp_pcb * pcb, struct pbuf * p, err_t err) +{ + LWIP_UNUSED_ARG(arg); + + if (p != NULL) + { + tcp_recved(pcb, p->tot_len); + pbuf_free(p); + } + else if (err == ERR_OK) + { + return tcp_close(pcb); + } + + return ERR_OK; +} + +/** + * Sent callback function for TCP netconns. + * Signals the conn->sem and calls API_EVENT. + * netconn_write waits for conn->sem if send buffer is low. + * + * @see tcp.h (struct tcp_pcb.sent) for parameters and return value + */ +err_t spl_sent_tcp(void *arg, struct tcp_pcb * pcb, u16_t len) +{ + spl_netconn_t *conn = (spl_netconn_t *) arg; + + if (NULL == conn) + { + NSPOL_LOGERR("conn==NULL"); + return ERR_VAL; + } + + if (conn->state == SPL_NETCONN_WRITE) + { + (void) do_writemore(conn); + } + else if (conn->state == SPL_NETCONN_CLOSE) + { + (void) do_close_internal((struct common_pcb *) conn->comm_pcb_data, + 0); + } + + /* conn is already checked for NULL above with ASSERT */ + /* If the queued byte- or pbuf-count drops below the configured low-water limit, + let select mark this pcb as writable again. */ + if (conn->snd_buf > TCP_SNDLOWAT) + { + conn->flags &= ~SPL_NETCONN_FLAG_CHECK_WRITESPACE; + if (((struct common_pcb *) conn->comm_pcb_data)->model == + SOCKET_STACKX) + SPL_API_EVENT(conn, SPL_NETCONN_EVT_SENDPLUS, 1); + } + + return ERR_OK; +} + +/** + * Error callback function for TCP netconns. + * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. + * The application thread has then to decide what to do. + * + * @see tcp.h (struct tcp_pcb.err) for parameters + */ +void spl_err_tcp(void *arg, err_t err) +{ + spl_netconn_t *conn; + enum spl_netconn_state old_state; + data_com_msg *forFree = NULL; + + struct common_pcb *cpcb; + + NSTCP_LOGINF("Enter err_tcp."); + + conn = (spl_netconn_t *) arg; + cpcb = (struct common_pcb *) (conn->comm_pcb_data); + + old_state = conn->state; + conn->state = SPL_NETCONN_NONE; + + /* Call unlink pcb no matter what */ + unlink_pcb(cpcb); + if (old_state == SPL_NETCONN_CLOSE) + { + /* RST during close: let close return success & dealloc the netconn */ + err = ERR_OK; + SPL_NETCONN_SET_SAFE_ERR(conn, ERR_OK); + } + else + { + SPL_NETCONN_SET_SAFE_ERR(conn, err); + } + + NSTCP_LOGWAR("inform HUP and ERROR event."); + SPL_API_EVENT(conn, SPL_NETCONN_EVT_RCVPLUS, 0); + SPL_API_EVENT(conn, SPL_NETCONN_EVT_SENDPLUS, 0); + SPL_API_EVENT(conn, SPL_NETCONN_EVT_ERROR, 0); + SPL_API_EVENT(conn, SPL_NETCONN_EVT_HUP, 1); + + if ((old_state == SPL_NETCONN_WRITE) || (old_state == SPL_NETCONN_CLOSE) + || (old_state == SPL_NETCONN_CONNECT)) + { + int was_nonblocking_connect = spl_netconn_is_nonblocking(conn); + SPL_SET_NONBLOCKING_CONNECT(conn, 0); + + if (!was_nonblocking_connect) + { + /* set error return code */ + if (NULL == cpcb->current_msg) + { + NSPOL_LOGERR("conn->current_msg==NULL"); + return; + } + + /* current msg could be connect msg or write_buf_msg */ + SET_MSG_ERR(cpcb->current_msg, err); + /* signal app to exit */ + if (old_state == SPL_NETCONN_CONNECT + && !spl_netconn_is_nonblocking(conn)) + { + SYNC_MSG_ACK(cpcb->current_msg); + } + + /* no matter it's connect msg or write msg, we will no process it any more */ + cpcb->current_msg = NULL; + + /* but, if msg is write_buf_msg, then we should release the pbuf in msg */ + if (cpcb->msg_head != NULL) + { + /* current_msg should be write_buf_msg */ + msg_write_buf *tmp_msg = cpcb->msg_head; + while (tmp_msg != NULL) + { + + forFree = MSG_ENTRY(tmp_msg, data_com_msg, buffer); + spl_pbuf_free(tmp_msg->p); + tmp_msg = tmp_msg->next; + + // free msg + ASYNC_MSG_FREE(forFree); + } + cpcb->current_msg = NULL; + cpcb->msg_head = cpcb->msg_tail = NULL; + } + } + } + else + { + + } +} + +/** + * Setup a tcp_pcb with the correct callback function pointers + * and their arguments. + * + * @param conn the TCP netconn to setup + */ +NSTACK_STATIC void setup_tcp(struct tcp_pcb *pcb, spl_netconn_t * conn) +{ + struct common_pcb *cpcb = (struct common_pcb *) conn->comm_pcb_data; + + /* callback have the same value as cpcb->conn */ + cpcb->conn = conn; + tcp_arg(pcb, (void *) conn); + tcp_recv(pcb, tcp_fn[TCP_FN_STACKX].recv_fn); + tcp_sent(pcb, tcp_fn[TCP_FN_STACKX].sent_fn); + tcp_poll(pcb, tcp_fn[TCP_FN_STACKX].poll_fn, 4); + tcp_err(pcb, tcp_fn[TCP_FN_STACKX].err_fn); + +} + +/** + * Accept callback function for TCP netconns. + * Allocates a new netconn and posts that to conn->acceptmbox. + * + * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value + */ +err_t spl_accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + spl_netconn_t *newconn; + spl_netconn_t *lconn = (spl_netconn_t *) arg; /* listen conneciton */ + struct common_pcb *cpcb = NULL; + + NSPOL_LOGDBG(API_MSG_DEBUG, "]state=%s", + tcp_debug_state_str(newpcb->state)); + + if (lconn == NULL) + { + NSPOL_LOGERR("accept_function: conn is NULL"); + return ERR_VAL; + } + + /* We have to set the callback here even though + * the new socket is unknown. conn->socket is marked as -1. */ + newconn = ss_malloc_conn(lconn->conn_pool, SPL_NETCONN_TCP); + if (newconn == NULL) + { + NSPOL_LOGERR("conn alloc failed"); + return ERR_MEM; + } + + cpcb = alloc_common_pcb(SPL_NETCONN_TCP); + if (cpcb == NULL) + { + return ERR_MEM; + } + + /* used by application to recycle conn */ + newconn->recycle.accept_from = lconn; + newconn->conn_pool = lconn->conn_pool; + + newconn->recv_obj = (i64) & newconn->private_data; + newconn->private_data = (i64) newpcb; + newconn->comm_pcb_data = (i64) cpcb; + + NSFW_LOGINF("alloc accept conn]conn=%p,pcb=%p,lconn=%p", newconn, newpcb, + lconn); + newconn->shut_status = 0xFFFF; + newconn->last_err = ERR_OK; + newconn->CanNotReceive = 0; + newconn->flags = 0; + + newconn->state = SPL_NETCONN_NONE; + newconn->mss = newpcb->mss; + newconn->remote_ip.addr = newpcb->remote_ip.addr; + newconn->remote_port = newpcb->remote_port; + ss_set_local_ip(newconn, newpcb->local_ip.addr); + ss_set_local_port(newconn, newpcb->local_port); + + setup_tcp(newpcb, newconn); + newpcb->state = ESTABLISHED; + update_tcp_state(newconn, ESTABLISHED); + + /*Initialize flow control variables */ + newconn->tcp_sndbuf = CONN_TCP_MEM_DEF_LINE; + newconn->tcp_wmem_alloc_cnt = 0; + newconn->tcp_wmem_sbr_free_cnt = 0; + newconn->tcp_wmem_spl_free_cnt = 0; + newconn->snd_buf = 0; + + newconn->bind_thread_index = lconn->bind_thread_index; + ss_set_msg_box(newconn, + ss_get_instance_msg_box(newconn->bind_thread_index, 0)); + + /* no protection: when creating the pcb, the netconn is not yet known + to the application thread */ + newconn->last_err = err; + + NSPOL_LOGDBG(TCP_DEBUG, + "trypost]newconn=%p, tcp=%p state=%d conn state=%d ", + newconn, newpcb, newpcb->state, newconn->state); + if (accept_enqueue(lconn, (void *) newconn) != ERR_OK) + { + /* remove all references to this netconn from the pcb */ + NSPOL_LOGERR("sp_enqueue!=ERR_OK]ring = %p", newconn->recv_ring); + + tcp_arg(newpcb, NULL); + tcp_recv(newpcb, tcp_fn[TCP_FN_NULL].recv_fn); + tcp_sent(newpcb, tcp_fn[TCP_FN_NULL].sent_fn); + tcp_poll(newpcb, tcp_fn[TCP_FN_NULL].poll_fn, 0); + tcp_err(newpcb, tcp_fn[TCP_FN_NULL].err_fn); + /* drop conn */ + tcp_drop_conn(newconn); + return ERR_MEM; + } + + SPL_API_EVENT(lconn, SPL_NETCONN_EVT_ACCEPT, 1); + /* tcp_accepted_with_return_value(newpcb); */ + + return ERR_OK; +} + +int common_pcb_init(struct common_pcb *cpcb) +{ + // u32 threadnum = p_lwip_instance->rss_queue_id + 1;//0 for app + + cpcb->hostpid = get_sys_pid(); + + cpcb->socket = 0; + /* run and close repeatly nstackmain coredum */ + cpcb->close_progress = 0; + cpcb->model = SOCKET_STACKX; + cpcb->current_msg = NULL; + cpcb->msg_head = cpcb->msg_tail = NULL; + cpcb->write_offset = 0; + + cpcb->recv_timeout = cpcb->send_timeout = 0; + + cpcb->sk_rcvlowat = 1; + + cpcb->l4_tick = 0; + cpcb->dataSentFlag = 0; + cpcb->recv_ring_not_empty = 0; + + return 0; +} + +int common_pcb_reset(struct common_pcb *cpcb) +{ + cpcb->conn = NULL; + cpcb->hostpid = 0; + + cpcb->socket = 0; + /* run and close repeatly nstackmain coredum */ + cpcb->close_progress = 0; + cpcb->model = 0; + cpcb->current_msg = NULL; + cpcb->msg_head = cpcb->msg_tail = NULL; + cpcb->write_offset = 0; + + cpcb->recv_timeout = cpcb->send_timeout = 0; + + cpcb->sk_rcvlowat = 0; + + cpcb->l4_tick = 0; + cpcb->dataSentFlag = 0; + cpcb->recv_ring_not_empty = 0; + + return 0; +} + +void unlink_pcb(struct common_pcb *cpcb) +{ + if (cpcb && cpcb->conn) + { + /* whatever the private data will be reset */ + cpcb->conn->private_data = 0; + update_tcp_state(cpcb->conn, CLOSED); + } + else + { + NSPOL_LOGINF(API_MSG_DEBUG, "conn is detached already!"); + } +} + +void unlink_recv_ring(spl_netconn_t * conn) +{ + if (conn) + conn->recv_ring_valid = 0; +} + +void recycle_tmr(void *arg) +{ + if (arg == NULL) + { + NSPOL_LOGERR("recycle_message is NULL!"); + } + else + { + (void) ss_recycle_conn(arg, do_try_delconn); + } +} + +/** + * Create a new pcb of a specific type. + * Called from do_newconn(). + * + * @param msg the api_msg_msg describing the connection type + * @return msg->conn->err, but the return value is currently ignored + */ +int spl_pcb_new(msg_new_netconn * pmsg) +{ + u16_t thread_index = spl_get_lcore_id(); + struct common_pcb *cpcb = NULL; + enum lwip_ip_addr_type iptype = IPADDR_TYPE_V4; + + /* Allocate a PCB for this connection */ + switch (SPL_NETCONNTYPE_GROUP(pmsg->type)) + { + case SPL_NETCONN_UDP: + { + struct udp_pcb *u = udp_new_ip_type(iptype); + if (u == NULL) + { + return ERR_MEM; + } + + if (pmsg->type == SPL_NETCONN_UDPNOCHKSUM) + { + udp_setflags(u, UDP_FLAGS_NOCHKSUM); + } + + cpcb = + (struct common_pcb *) alloc_common_pcb(SPL_NETCONN_UDP); + if (cpcb == NULL) + { + return ERR_MEM; + } + + pmsg->conn->comm_pcb_data = (i64) cpcb; + pmsg->conn->private_data = (i64) u; + udp_recv(u, spl_recv_udp, (void *) pmsg->conn); + break; + } + + case SPL_NETCONN_TCP: + { + struct tcp_pcb *t = tcp_new_ip_type(iptype); + if (t == NULL) + { + return ERR_MEM; + } + + cpcb = alloc_common_pcb(SPL_NETCONN_TCP); + if (cpcb == NULL) + { + return ERR_MEM; + } + + pmsg->conn->comm_pcb_data = (i64) cpcb; + pmsg->conn->private_data = (i64) t; + setup_tcp(t, pmsg->conn); + break; + } + + default: + /* Unsupported netconn type, e.g. protocol disabled */ + NSPOL_LOGERR("Unsupported netconn type!"); + return ERR_VAL; + } + + /* type and socket value for all type */ + cpcb->socket = pmsg->socket; + cpcb->conn = pmsg->conn; + cpcb->bind_thread_index = thread_index; + + /* used to find pcb when a msg is received */ + return ERR_OK; +} + +/** + * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in + * these mboxes + * + * @param conn the netconn to free + * @bytes_drained bytes drained from recvmbox + * @accepts_drained pending connections drained from acceptmbox + */ +int netconn_drain(enum spl_netconn_type type, spl_netconn_t * conn) +{ + int i, n; + mring_handle ring = NULL; + void *addr[32] = { 0 }; + int not_empty = 0; + + /* This runs in tcpip_thread, so we don't need to lock against rx packets */ + ring = conn->recv_ring; + do + { + /*every times get atmost 32 to release */ + n = nsfw_mem_ring_dequeuev(ring, addr, 32); + for (i = 0; i < n; i++) + { + /* if the con is UDP, buffer type also is struct spl_netbuf,it is same as RAW */ + if ((type == SPL_NETCONN_RAW) || (type == SPL_NETCONN_UDP)) + { + spl_pbuf_free((struct spl_pbuf *) addr[i]); + if (type == SPL_NETCONN_UDP) + { + UDP_STATS_INC(udp.drop); + } + } + else + { + spl_pbuf_free((struct spl_pbuf *) addr[i]); + } + + if (not_empty == 0) + not_empty = 1; + } + } + while (0 != n); + return not_empty; +} + +/* need free mbuf inside recv ring before free conn */ +void free_conn_by_spl(spl_netconn_t * conn) +{ + struct common_pcb *cpcb = (struct common_pcb *) conn->comm_pcb_data; + + free_common_pcb(cpcb); + + (void) netconn_drain(conn->type, conn); + ss_free_conn(conn); +} + +int +do_close_finished(struct common_pcb *cpcb, u8_t close_finished, u8_t shut, + err_t err, int OpShutDown) +{ + struct tcp_pcb *tpcb = (struct tcp_pcb *) cpcb->conn->private_data; + spl_netconn_t *conn = cpcb->conn; + + if (!close_finished) + { + /* Closing succeeded */ + /* Closing failed, restore some of the callbacks */ + /* Closing of listen pcb will never fail! */ + if (LISTEN == tpcb->state) + { + NSPOL_LOGERR("Closing a listen pcb may not fail!"); + return ERR_VAL; + } + + tcp_sent(tpcb, tcp_fn[TCP_FN_STACKX].sent_fn); + tcp_poll(tpcb, tcp_fn[TCP_FN_STACKX].poll_fn, 1); + tcp_err(tpcb, tcp_fn[TCP_FN_STACKX].err_fn); + tcp_arg(tpcb, conn); + /* don't restore recv callback: we don't want to receive any more data */ + } + else + { + /* Closing done (succeeded, non-memory error, nonblocking error or timeout) */ + if (cpcb->current_msg) + { + SET_MSG_ERR(cpcb->current_msg, err); + cpcb->current_msg = NULL; + } + + conn->state = SPL_NETCONN_NONE; + NSTCP_LOGINF("release pcb]conn=%p,pcb=%p", conn, tpcb); + unlink_pcb(cpcb); + } + + return ERR_OK; +} + +NSTACK_STATIC void +reset_tcp_callback(struct tcp_pcb *tpcb, struct common_pcb *cpcb, u8 shut) +{ + spl_netconn_t *conn = cpcb->conn; + + /* some callbacks have to be reset if tcp_close is not successful */ + if (shut & SPL_NETCONN_SHUT_RD) + { + conn->CanNotReceive = 1; + tcp_recv(tpcb, tcp_fn[TCP_FN_NULL].recv_fn); + tcp_accept(tpcb, tcp_fn[TCP_FN_NULL].accept_fn); + } + + if (shut & SPL_NETCONN_SHUT_WR) + { + tcp_sent(tpcb, tcp_fn[TCP_FN_NULL].sent_fn); + } + + if (shut == SPL_NETCONN_SHUT_RDWR) + { + tcp_poll(tpcb, tcp_fn[TCP_FN_NULL].poll_fn, 0); + tcp_err(tpcb, tcp_fn[TCP_FN_NULL].err_fn); + } +} + +/** + * Internal helper function to close a TCP netconn: since this sometimes + * doesn't work at the first attempt, this function is called from multiple + * places. + * + * @param conn the TCP netconn to close + */ +err_t do_close_internal(struct common_pcb *cpcb, int OpShutDown) +{ + err_t err; + u8_t shut, ucclose; + u8_t close_finished = 0; + + if (NULL == cpcb) + { + NSTCP_LOGERR("invalid conn"); + return ERR_ARG; + } + + spl_netconn_t *conn = cpcb->conn; + if (SPL_NETCONN_TCP != cpcb->type || SPL_NETCONN_CLOSE != conn->state) + { + NSTCP_LOGERR("conn=%p, err_type=%d, error_state=%d", + conn, cpcb->type, conn->state); + return ERR_VAL; + } + + struct tcp_pcb *tpcb = (struct tcp_pcb *) (conn->private_data); + + if (cpcb->current_msg != NULL) + shut = get_shut_op(cpcb->current_msg); + else + shut = SPL_NETCONN_SHUT_RDWR; + + /* shutting down both ends is the same as closing */ + ucclose = (shut == SPL_NETCONN_SHUT_RDWR); + + /* Set back some callback pointers */ + if (ucclose) + { + conn->CanNotReceive = 1; + tcp_arg(tpcb, conn); + } + + if (tpcb->state == LISTEN) + { + tcp_accept(tpcb, tcp_fn[TCP_FN_NULL].accept_fn); + } + else + { + reset_tcp_callback(tpcb, cpcb, shut); + } + + /* Try to close the connection */ + if (shut == SPL_NETCONN_SHUT_RDWR && !OpShutDown) + { + err = tcp_close(tpcb); + } + else + { + err = + tcp_shutdown(tpcb, shut & SPL_NETCONN_SHUT_RD, + shut & SPL_NETCONN_SHUT_WR); + } + + if (err == ERR_OK) + { + close_finished = 1; + } + else + { + if (err == ERR_MEM) + { + /* Blocking close, check the timeout */ + close_finished = 1; + if (ucclose) + { + /* in this case, we want to RST the connection */ + tcp_abort(tpcb); + err = ERR_OK; + } + } + else + { + /* Closing failed for a non-memory error: give up */ + close_finished = 1; + } + } + + err_t err1 = do_close_finished(cpcb, close_finished, + shut, err, OpShutDown); + if (err1 != ERR_OK) + { + NSTCP_LOGERR("return err1]pcb=%p,err1=%d", tpcb, err1); + return err1; + } + return err; + + /* If closing didn't succeed, we get called again either + from poll_tcp or from sent_tcp */ +} + +void do_try_delconn(void *close_data, u32 delay_sec) +{ + msg_delete_netconn *dmsg = (msg_delete_netconn *) close_data; + data_com_msg *m = MSG_ENTRY(dmsg, data_com_msg, buffer); + struct common_pcb *cpcb = NULL; + + spl_netconn_t *conn = dmsg->conn; + + /* no receiver in some recycle cases */ + if (0 == m->param.comm_receiver) + { + if (NULL == conn) + { + NSFW_LOGERR("release err conn!]pid=%d", dmsg->pid); + /* need to free pbufs which are attached to msg */ + do_pbuf_free(dmsg->buf); + return; + } + + cpcb = (struct common_pcb *) conn->comm_pcb_data; + } + else + { + cpcb = COMM_PRIVATE_PTR(m); + } + + /* no pcb in some recycle cases */ + if (conn->private_data == 0) + { + /* though pcb is gone, still need to clean the mbox */ + if (conn != NULL) + (void) netconn_drain(conn->type, conn); + + NSFW_LOGWAR("release conn pcb null]pcb=%p", m->param.receiver); + /* need to free pbufs which are attached to msg */ + do_pbuf_free(dmsg->buf); + return; + } + + if (delay_sec) + { + NSFW_LOGWAR("delay to recycle!]pcb=%p, msg=%d", cpcb, dmsg); + sys_timeout(delay_sec * 1000, recycle_tmr, dmsg); + return; + } + + do_delconn(cpcb, dmsg); + + /* after the do_delconn, the PCB maybe released, but the conn is ok */ + sys_sem_s_signal(&dmsg->conn->close_completed); + + return; +} + +/** + * Delete the pcb inside a netconn. + * Called from netconn_delete. + * + * @param msg the api_msg_msg pointing to the connection + */ +void do_delconn(struct common_pcb *cpcb, msg_delete_netconn * dmsg) +{ + spl_netconn_t *conn = cpcb->conn; + data_com_msg *pmsg = MSG_ENTRY(dmsg, data_com_msg, buffer); + + /*if already close, just return */ + /* run and close repeatly nstackmain coredum */ + if (1 == cpcb->close_progress) + { + SET_MSG_ERR(pmsg, ERR_OK); + return; + } + cpcb->close_progress = 1; + + /* Pbuf free should be done in network stack */ + do_pbuf_free(dmsg->buf); + + /* @todo TCP: abort running write/connect? */ + if ((conn->state != SPL_NETCONN_NONE) + && (conn->state != SPL_NETCONN_LISTEN) + && (conn->state != SPL_NETCONN_CONNECT)) + { + /* this only happens for TCP netconns */ + if (SPL_NETCONN_TCP != cpcb->type) + { + NSTCP_LOGERR("msg->conn->type error!]conn=%p,msg->conn->type=%d", + conn, cpcb->type); + SET_MSG_ERR(pmsg, ERR_VAL); + return; + } + NSPOL_LOGINF(SOCK_INFO, "conn is not for free state]conn=%p,state=%d", + conn, conn->state); + + //need to release pcb + if (cpcb->current_msg != NULL && cpcb->msg_tail != NULL) + { + NSPOL_LOGINF(SOCK_INFO, + "conn there is data in conn->current_msg when close the conn]conn=%p,state=%d", + conn, conn->state); + (void) do_writemore(cpcb->conn); + } + } + + /* + the accpet connections waiting in listen queue will be clear in + netconn_drain. + */ + if (conn->state == SPL_NETCONN_LISTEN) + { + /* This function does nothing in original code. */ + } + else + { + /* Drain pbuf from non-listen mboxes */ + if (netconn_drain(cpcb->type, conn)) + { + cpcb->recv_ring_not_empty = 1; + + NSPOL_LOGWAR(SOCK_INFO, + "still some data leave in recv ring when close"); + } + } + + /* conn will be released outside */ + + switch (SPL_NETCONNTYPE_GROUP(cpcb->type)) + { + + case SPL_NETCONN_UDP: + { + struct udp_pcb *upcb = + (struct udp_pcb *) cpcb->conn->private_data; + upcb->recv_arg = NULL; + udp_remove(upcb); + break; + } + + case SPL_NETCONN_TCP: + { + conn->state = SPL_NETCONN_CLOSE; + dmsg->shut = SPL_NETCONN_SHUT_RDWR; + cpcb->current_msg = pmsg; + + if (ERR_INPROGRESS == do_close_internal(cpcb, 0)) + { + return; + } + } + default: + break; + } + + /* tcp netconns don't come here! */ + +} + +/** + * Bind a pcb contained in a netconn + * Called from netconn_bind. + * + * @param msg the api_msg_msg pointing to the connection and containing + * the IPaddress and port to bind to + */ +void do_bind(struct common_pcb *cpcb, msg_bind * bmsg) +{ + spl_netconn_t *conn = cpcb->conn; + data_com_msg *pmsg = MSG_ENTRY(bmsg, data_com_msg, buffer); + ip_addr_t stIpaddr; + + stIpaddr.addr = bmsg->ipaddr.addr; + + if (SPL_ERR_IS_FATAL(conn->last_err) + && ERR_CANTASSIGNADDR != conn->last_err) + { + NSTCP_LOGERR("bind but conn has err]pcb=%p,conn=%p,err=%d", cpcb, + conn, conn->last_err); + SET_MSG_ERR(pmsg, conn->last_err); + } + else + { + if (!ip_addr_isany(&bmsg->ipaddr) + && !ip_addr_ismulticast(&bmsg->ipaddr)) + { + if (!get_netif_by_ip(bmsg->ipaddr.addr) + && !netif_check_broadcast_addr(&bmsg->ipaddr)) + { + NSPOL_LOGERR("ip is not exist]pcb=%p,ip=%u", cpcb, + bmsg->ipaddr.addr); + SET_MSG_ERR(pmsg, ERR_CANTASSIGNADDR); + return; + } + } + + SET_MSG_ERR(pmsg, ERR_VAL); + switch (SPL_NETCONNTYPE_GROUP(cpcb->type)) + { + case SPL_NETCONN_UDP: + SET_MSG_ERR(pmsg, + udp_bind((struct udp_pcb *) (cpcb-> + conn->private_data), + &stIpaddr, bmsg->port)); + + /* Set local Ip, willbe used during connect */ + struct udp_pcb *upcb = + (struct udp_pcb *) cpcb->conn->private_data; + ss_set_local_ip(cpcb->conn, upcb->local_ip.addr); + ss_set_local_port(cpcb->conn, upcb->local_port); + NSTCP_LOGINF("updated Ip to spl_netconn_t] %x", + upcb->local_ip.addr); + + NSUDP_LOGINF + ("udp_bind return]pcb=%p,IP=%u.%u.%u.%u,port=%u,err=%d", + (struct udp_pcb *) cpcb->conn->private_data, + &bmsg->ipaddr == NULL ? 0 : ip4_addr1_16(&stIpaddr), + &bmsg->ipaddr == NULL ? 0 : ip4_addr2_16(&stIpaddr), + &bmsg->ipaddr == NULL ? 0 : ip4_addr3_16(&stIpaddr), + &bmsg->ipaddr == NULL ? 0 : ip4_addr4_16(&stIpaddr), + bmsg->port, GET_MSG_ERR(pmsg)); + break; + + case SPL_NETCONN_TCP: + SET_MSG_ERR(pmsg, + tcp_bind((struct tcp_pcb *) cpcb-> + conn->private_data, &stIpaddr, + bmsg->port)); + + /* Set local Ip, willbe used during connect */ + struct tcp_pcb *tpcb = + (struct tcp_pcb *) cpcb->conn->private_data; + NSTCP_LOGINF("updated Ip to spl_netconn_t] %x", + tpcb->local_ip.addr); + ss_set_local_ip(cpcb->conn, tpcb->local_ip.addr); + ss_set_local_port(cpcb->conn, tpcb->local_port); + + NSTCP_LOGINF + ("tcp_bind return]pcb=%p,IP=%u.%u.%u.%u,port=%u,err=%d", + (struct tcp_pcb *) cpcb->conn->private_data, + &bmsg->ipaddr == NULL ? 0 : ip4_addr1_16(&stIpaddr), + &bmsg->ipaddr == NULL ? 0 : ip4_addr2_16(&stIpaddr), + &bmsg->ipaddr == NULL ? 0 : ip4_addr3_16(&stIpaddr), + &bmsg->ipaddr == NULL ? 0 : ip4_addr4_16(&stIpaddr), + bmsg->port, GET_MSG_ERR(pmsg)); + break; + default: + break; + } + } + + conn->last_err = GET_MSG_ERR(pmsg); + NSPOL_LOGDBG(TESTSOCKET_DEBUG | LWIP_DBG_TRACE, "the msg is doing bind"); + NSTCP_LOGINF("the msg is doing bind"); +} + +/** + * TCP callback function if a connection (opened by tcp_connect/do_connect) has + * been established (or reset by the remote host). + * + * @see tcp.h (struct tcp_pcb.connected) for parameters and return values + */ +err_t spl_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) +{ + spl_netconn_t *conn = (spl_netconn_t *) arg; + struct common_pcb *cpcb = (struct common_pcb *) conn->comm_pcb_data; + data_com_msg *m = cpcb->current_msg; + int was_blocking; + + if (conn == NULL) + { + NSTCP_LOGERR("conn is NULL!]arg=%p", arg); + return ERR_ARG; + } + + if (SPL_NETCONN_CONNECT != conn->state) + { + NSTCP_LOGERR("conn->state error!]conn=%p,state=%d", conn, + conn->state); + return ERR_VAL; + } + + if ((NULL == m) && (0 == spl_netconn_is_nonblocking(conn))) + { + NSTCP_LOGERR("conn->current_msg!]conn=%p,current_msg=%p", conn, m); + return ERR_VAL; + } + + if (m != NULL) + { + SET_MSG_ERR(m, err); + } + + if ((cpcb->type == SPL_NETCONN_TCP) && (err == ERR_OK)) + { + setup_tcp(pcb, conn); + } + + ss_set_local_ip(conn, pcb->local_ip.addr); + ss_set_local_port(conn, pcb->local_port); + conn->remote_ip.addr = pcb->remote_ip.addr; + conn->remote_port = pcb->remote_port; + + conn->mss = pcb->mss; + cpcb->current_msg = NULL; + + was_blocking = !SPL_IN_NONBLOCKING_CONNECT(conn); + SPL_SET_NONBLOCKING_CONNECT(conn, 0); + conn->state = SPL_NETCONN_NONE; + SPL_NETCONN_SET_SAFE_ERR(conn, ERR_OK); + + update_tcp_state(pcb->callback_arg, ESTABLISHED); + SPL_API_EVENT(conn, SPL_NETCONN_EVT_SENDPLUS, 1); + + if (was_blocking && m != NULL) + { + SYNC_MSG_ACK(m); + } + + return ERR_OK; +} + +int +do_internal_tcp_connect(struct common_pcb *cpcb, struct tcp_pcb *tpcb, + msg_connect * cmsg) +{ + spl_netconn_t *conn = cpcb->conn; + data_com_msg *pmsg = MSG_ENTRY(cmsg, data_com_msg, buffer); + ip_addr_t ip_addr; + + ip_addr.addr = cmsg->ipaddr.addr; + + /* Prevent connect while doing any other action. */ + if (conn->state != SPL_NETCONN_NONE) + { + if (conn->state == SPL_NETCONN_CONNECT + || conn->state == SPL_NETCONN_WRITE) + { + if (tpcb->state != ESTABLISHED) + { + SET_MSG_ERR(pmsg, ERR_ALREADY); + } + else + { + SET_MSG_ERR(pmsg, ERR_ISCONN); + } + } + else + { + SET_MSG_ERR(pmsg, ERR_ISCONN); + } + + NSTCP_LOGINF + ("tcp_connect]pcb=%p,state=%d,remote_ip=%u.%u.%u.%u,remote_port=%u,local_ip=%u.%u.%u.%u,local_port=%u,err=%d", + tpcb, conn->state, ip4_addr1_16(&ip_addr), + ip4_addr2_16(&ip_addr), ip4_addr3_16(&ip_addr), + ip4_addr4_16(&ip_addr), cmsg->port, + ip4_addr1_16(&tpcb->local_ip), ip4_addr2_16(&tpcb->local_ip), + ip4_addr3_16(&tpcb->local_ip), ip4_addr4_16(&tpcb->local_ip), + tpcb->local_port, GET_MSG_ERR(pmsg)); + } + else + { + setup_tcp(tpcb, conn); + SET_MSG_ERR(pmsg, + tcp_connect(tpcb, &ip_addr, cmsg->port, + tcp_fn[TCP_FN_STACKX].connected_fn)); + conn->mss = tpcb->mss; + SPL_API_EVENT(conn, NETCONN_EVT_SENDMINUS, 1); + SPL_API_EVENT(conn, NETCONN_EVT_RCVMINUS, 1); + + NSTCP_LOGINF + ("tcp_connect]pcb=%p,state=%d,remote_ip=%u.%u.%u.%u,remote_port=%u,local_ip=%u.%u.%u.%u,local_port=%u,err=%d", + tpcb, conn->state, ip4_addr1_16(&ip_addr), + ip4_addr2_16(&ip_addr), ip4_addr3_16(&ip_addr), + ip4_addr4_16(&ip_addr), cmsg->port, + ip4_addr1_16(&tpcb->local_ip), ip4_addr2_16(&tpcb->local_ip), + ip4_addr3_16(&tpcb->local_ip), ip4_addr4_16(&tpcb->local_ip), + tpcb->local_port, GET_MSG_ERR(pmsg)); + if (GET_MSG_ERR(pmsg) == ERR_OK) + { + int nonblock = spl_netconn_is_nonblocking(conn); + SPL_SET_NONBLOCKING_CONNECT(conn, nonblock); + conn->state = SPL_NETCONN_CONNECT; + if (nonblock) + { + SET_MSG_ERR(pmsg, ERR_INPROGRESS); + } + else + { + cpcb->current_msg = pmsg; + /* sys_sem_signal() is called from do_connected (or err_tcp()), + * when the connection is established! */ + return -1; + } + } + } + + return 0; +} + +/** + * Connect a pcb contained inside a netconn + * Called from netconn_connect. + * + * @param msg the api_msg_msg pointing to the connection and containing + * the IPaddress and port to connect to + */ +void do_connect(struct common_pcb *cpcb, msg_connect * cmsg) +{ + data_com_msg *pmsg = MSG_ENTRY(cmsg, data_com_msg, buffer); + ip_addr_t ipaddr; + + SET_MSG_ERR(pmsg, ERR_OK); + + if (cpcb == NULL) + { + /* This may happen when calling netconn_connect() a second time */ + NSTCP_LOGERR("conn connect but conn has err]msg=%p", pmsg); + SET_MSG_ERR(pmsg, ERR_CLSD); + return; + } + + ipaddr.addr = cmsg->ipaddr.addr; + switch (SPL_NETCONNTYPE_GROUP(cpcb->type)) + { + case SPL_NETCONN_UDP: + { + struct udp_pcb *upcb = + (struct udp_pcb *) (cpcb->conn->private_data); + if (ip_addr_isany(&upcb->local_ip)) + { + upcb->local_ip.addr = cmsg->local_ip.addr; + ss_set_local_ip(cpcb->conn, upcb->local_ip.addr); + } + + SET_MSG_ERR(pmsg, udp_connect(upcb, &ipaddr, cmsg->port)); + if (ERR_OK == pmsg->param.err) + { + cpcb->conn->remote_ip.addr = cmsg->ipaddr.addr; + cpcb->conn->remote_port = cmsg->port; + } + break; + } + case SPL_NETCONN_TCP: + { + struct tcp_pcb *tpcb = + (struct tcp_pcb *) (cpcb->conn->private_data); + if (ip_addr_isany(&tpcb->local_ip)) + { + tpcb->local_ip.addr = cmsg->local_ip.addr; + ss_set_local_ip(cpcb->conn, tpcb->local_ip.addr); + } + + if (0 != do_internal_tcp_connect(cpcb, tpcb, cmsg)) + { + return; + } + + } + break; + default: + NSPOL_LOGERR("Invalid netconn type]type=%d", cpcb->type); + SET_MSG_ERR(pmsg, ERR_VAL); + break; + } + + /* For all other protocols, netconn_connect() calls TCPIP_APIMSG(), + so use TCPIP_APIMSG_ACK() here. + Do as lwip-2.0.0. set conn->last_error here. */ + SPL_NETCONN_SET_SAFE_ERR(cpcb->conn, GET_MSG_ERR(pmsg)); +} + +/* Pbuf free should be done in network stack */ +void do_pbuf_free(struct spl_pbuf *buf) +{ + if (buf) + { + struct spl_pbuf *pCur = buf; + while (buf) + { + pCur = buf; + buf = buf->freeNext; + spl_pbuf_free(pCur); + } + } +} + +/** + * Set a TCP pcb contained in a netconn into listen mode + * Called from netconn_listen. + * + * @param msg the api_msg_msg pointing to the connection + */ +void do_listen(struct common_pcb *cpcb, msg_listen * lmsg) +{ + err_t err = ERR_OK; + spl_netconn_t *conn = cpcb->conn; + data_com_msg *pmsg = MSG_ENTRY(lmsg, data_com_msg, buffer); + + if (SPL_ERR_IS_FATAL(conn->last_err)) + { + NSTCP_LOGERR("conn listern but conn has err]conn=%p,err=%d", + conn, conn->last_err); + SET_MSG_ERR(pmsg, conn->last_err); + } + else + { + SET_MSG_ERR(pmsg, ERR_CONN); + + if (cpcb->type == SPL_NETCONN_TCP) + { + if (conn->state == SPL_NETCONN_NONE) + { + struct tcp_pcb *lpcb; + if (((struct tcp_pcb *) (cpcb->conn->private_data))->state != + CLOSED) + { + /* connection is not closed, cannot listen */ + SET_MSG_ERR(pmsg, ERR_VAL);; + } + else + { + u8_t backlog = TCP_DEFAULT_LISTEN_BACKLOG; + + lpcb = + tcp_listen_with_backlog_and_err((struct tcp_pcb + *) (cpcb-> + conn->private_data), + backlog, &err); + if (lpcb == NULL) + { + /* in this case, the old pcb is still allocated */ + SET_MSG_ERR(pmsg, err); + } + else + { + SET_MSG_ERR(pmsg, ERR_OK); + /* conn now is put on lpcb */ + conn->state = SPL_NETCONN_LISTEN; + + /* NOTE: pmsg->conn->comm_pcb_data == (i64)cpcb; should be already same. */ + conn->private_data = (i64) lpcb; + + tcp_arg(lpcb, conn); + tcp_accept(lpcb, tcp_fn[TCP_FN_STACKX].accept_fn); + + SPL_API_EVENT(conn, NETCONN_EVT_SENDMINUS, 1); + SPL_API_EVENT(conn, NETCONN_EVT_RCVMINUS, 1); + } + } + } + else if (conn->state == SPL_NETCONN_LISTEN) + { + SET_MSG_ERR(pmsg, ERR_OK); + } + } + NSTCP_LOGINF("listen]conn=%p,pcb=%p,connstate=%d,err=%d", + conn, cpcb, conn->state, GET_MSG_ERR(pmsg)); + + } + +} + +/** + * Send some data on UDP pcb contained in a netconn + * Called from do_send + * + * @param msg the api_msg_msg pointing to the connection + */ +void spl_udp_send(struct common_pcb *cpcb, msg_send_buf * smsg) +{ + struct spl_pbuf *p_from = smsg->p; + spl_netconn_t *conn = cpcb->conn; + struct udp_pcb *upcb = (struct udp_pcb *) (cpcb->conn->private_data); + data_com_msg *m = MSG_ENTRY(smsg, data_com_msg, buffer); + struct pbuf *p_to = NULL; + err_t err = ERR_OK; + + //allocate pbuf and copy spl_pbuf, send , free pbuf and spl_pbuf + do + { + p_to = pbuf_alloc(PBUF_TRANSPORT, p_from->len, PBUF_RAM); + if (NULL == p_to) + { + NSPOL_LOGERR("pbuf is NULL]conn=%p,pcb=%p", conn, upcb); + return; + } + + err = splpbuf_to_pbuf_transport_copy(p_to, p_from); + if (err != ERR_OK) + { + SET_MSG_ERR(m, conn->last_err); + return; + } + + if (ip_addr_isany(&smsg->addr)) + { + SET_MSG_ERR(m, udp_send(upcb, p_to)); + } + else + { + SET_MSG_ERR(m, + udp_sendto(upcb, p_to, (ip_addr_t *) & smsg->addr, + smsg->port)); + } + + p_from = (struct spl_pbuf *) ADDR_SHTOL(p_from->next_a); + } + while (p_from != NULL); + +} + +/** + * Send some data on a RAW or UDP pcb contained in a netconn + * Called from netconn_send + * + * @param msg the api_msg_msg pointing to the connection + */ +void do_send(struct common_pcb *cpcb, msg_send_buf * smsg) +{ + struct spl_pbuf *p = smsg->p; + data_com_msg *m = MSG_ENTRY(smsg, data_com_msg, buffer); + spl_netconn_t *conn = cpcb->conn; + + pbuf_set_recycle_flg(p, MBUF_HLD_BY_SPL); /* release buf hold by app on abnormal exit */ + + if (SPL_ERR_IS_FATAL(conn->last_err)) + { + SET_MSG_ERR(m, conn->last_err); + NSPOL_LOGERR("Invalid param]msg->conn=%p", conn); + goto err_return; + } + + switch (SPL_NETCONNTYPE_GROUP(cpcb->type)) + { + case SPL_NETCONN_UDP: + { + struct udp_pcb *upcb = + (struct udp_pcb *) (cpcb->conn->private_data); + if (ip_addr_isany(&upcb->local_ip)) + { + upcb->local_ip.addr = smsg->local_ip.addr; + ss_set_local_ip(conn, smsg->local_ip.addr); + } + + spl_udp_send(cpcb, smsg); + + break; + } + + default: + SET_MSG_ERR(m, ERR_CONN); + break; + } + + err_return: + pbuf_free_safe(smsg->p); + ASYNC_MSG_FREE(m); + + return; +} + +/** + * Indicate data has been received from a TCP pcb contained in a netconn + * Called from netconn_recv + * + * @param msg the api_msg_msg pointing to the connection + */ +void do_recv(struct common_pcb *cpcb, msg_recv_buf * rmsg) +{ + data_com_msg *m = MSG_ENTRY(rmsg, data_com_msg, buffer); + SET_MSG_ERR(m, ERR_OK); + struct tcp_pcb *tpcb = (struct tcp_pcb *) cpcb->conn->private_data; + + if (NULL == tpcb) + { + if (rmsg->p) + { + NSPOL_LOGDBG(TCP_DEBUG, + "When pcb was freed: do recv, and free pbuf"); + spl_pbuf_free(rmsg->p); + rmsg->p = NULL; + } + + return; + } + + if (cpcb->conn->type == SPL_NETCONN_TCP) + { + /* Pbuf free should be done in network stack */ + if (rmsg->p) + { + NSPOL_LOGDBG(TCP_DEBUG, "do recv, and free pbuf"); + spl_pbuf_free(rmsg->p); + rmsg->p = NULL; + } + tcp_recved(tpcb, rmsg->len * TCP_MSS); + } +} + +/** + * See if more data needs to be written from a previous call to netconn_write. + * Called initially from do_write. If the first call can't send all data + * (because of low memory or empty send-buffer), this function is called again + * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the + * blocking application thread (waiting in netconn_write) is released. + * + * @param conn netconn (that is currently in state NETCONN_WRITE) to process + * @return ERR_OK + * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished + */ + +/** + * See if more data needs to be written from a previous call to netconn_write. + * Called initially from do_write. If the first call can't send all data + * (because of low memory or empty send-buffer), this function is called again + * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the + * blocking application thread (waiting in netconn_write) is released. + * + * @param conn netconn (that is currently in state NETCONN_WRITE) to process + * @return ERR_OK + * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished + */ +err_t do_writemore(struct spl_netconn *conn) +{ + err_t err = ERR_OK; + u16_t len = 0, available; + u8_t write_finished = 0; + struct tcp_pcb *tpcb = (struct tcp_pcb *) conn->private_data; + common_pcb *cpcb = (struct common_pcb *) conn->comm_pcb_data; + size_t diff; + const void *dataptr; + + if ((NULL == tpcb) || (NULL == conn) || (SPL_NETCONN_WRITE != conn->state) + || (NULL == cpcb->current_msg)) + { + NSPOL_LOGERR("conn=NULL"); + return ERR_ARG; + } + + msg_write_buf *wmsg = (msg_write_buf *) cpcb->current_msg->buffer; + start_write: + + if (NULL == wmsg->p) + { + NSPOL_LOGERR("wmsg->p is NULL]conn=%p,pcb=%p", conn, tpcb); + return ERR_VAL; + } + + u8_t apiflags = wmsg->apiflags; + struct spl_pbuf *current_w_pbuf = wmsg->p; + current_w_pbuf->res_chk.u8Reserve |= NEED_ACK_FLAG; + wmsg->p = current_w_pbuf->next; + current_w_pbuf->next = NULL; + + dataptr = (const u8_t *) current_w_pbuf->payload + cpcb->write_offset; + diff = current_w_pbuf->len - cpcb->write_offset; + + if (diff > 0xffffUL) + { + len = 0xffff; + apiflags |= TCP_WRITE_FLAG_MORE; + } + else + { + len = (u16_t) diff; + } + + available = tcp_sndbuf(tpcb); + if (!available) + { + err = ERR_MEM; + goto err_mem; + } + + if (available < len) + { + /* don't try to write more than sendbuf */ + len = available; + apiflags |= TCP_WRITE_FLAG_MORE; + } + + err = tcp_write(tpcb, dataptr, len, apiflags); + if ((err == ERR_OK) || (err == ERR_MEM)) + { + err_mem: + if ((tcp_sndbuf(tpcb) <= TCP_SNDLOWAT) || + (tcp_sndqueuelen(tpcb) >= TCP_SNDQUEUELOWAT)) + { + SPL_API_EVENT(conn, NETCONN_EVT_SENDMINUS, 1); + } + } + if (err == ERR_OK) + { + cpcb->write_offset += len; + tcp_output(tpcb); + + if (cpcb->write_offset == current_w_pbuf->len) + { + cpcb->write_offset = 0; + spl_pbuf_free(current_w_pbuf); + if (NULL == wmsg->p) + { + /* this message is finished */ + cpcb->write_offset = 0; + SET_MSG_ERR(cpcb->current_msg, err); + + /* go to next msg */ + data_com_msg *forFreemsg = cpcb->current_msg; + msg_write_buf *msg_head_prev = cpcb->msg_head; + cpcb->msg_head = cpcb->msg_head->next; + + /* no msg remain */ + if (cpcb->msg_head == NULL) + { + write_finished = 1; + if (cpcb->msg_tail != NULL + && msg_head_prev != cpcb->msg_tail) + { + NSPOL_LOGWAR(TCP_DEBUG, + "err maybe lost one mesg]conn=%p,pcb=%p", + conn, tpcb); + } + cpcb->msg_tail = NULL; + cpcb->current_msg = NULL; + conn->state = SPL_NETCONN_NONE; + } + else /* go to handle next message */ + { + + cpcb->current_msg = + MSG_ENTRY(cpcb->msg_head, data_com_msg, buffer); + wmsg = cpcb->msg_head; + write_finished = 0; + } + + ASYNC_MSG_FREE(forFreemsg); + } + + } + else + { + if (cpcb->write_offset > current_w_pbuf->len) + { + NSPOL_LOGERR + ("Big trouble write_offset > current_w_pbuf->len"); + } + + current_w_pbuf->next = wmsg->p; + wmsg->p = current_w_pbuf; + } + if ((write_finished == 0) && (NULL != wmsg->p)) + { + goto start_write; + } + } + else if (err == ERR_MEM) + { + current_w_pbuf->next = wmsg->p; + wmsg->p = current_w_pbuf; + tcp_output(tpcb); + } + else + { + NSPOL_LOGERR("]pcb=%p, error when send %d", tpcb, err); + write_finished = 1; + cpcb->write_offset = 0; + current_w_pbuf->next = wmsg->p; + wmsg->p = current_w_pbuf; + tcp_abort(tpcb); + return err; + } + NSTCP_LOGINF("do_writemore finished with err %d", err); + return ERR_OK; +} + +/** + * Send some data on a TCP pcb contained in a netconn + * Called from netconn_write + * + * @param msg the api_msg_msg pointing to the connection + */ +void do_write(struct common_pcb *cpcb, msg_write_buf * wmsg) +{ + struct tcp_pcb *tpcb = (struct tcp_pcb *) cpcb->conn->private_data; + spl_netconn_t *conn = cpcb->conn; + data_com_msg *m = MSG_ENTRY(wmsg, data_com_msg, buffer); + + pbuf_set_recycle_flg(wmsg->p, MBUF_HLD_BY_SPL); /* release buf hold by app on abnormal exit */ + + int tcpState = -1; + + /* if msg->conn is null, then return */ + if (NULL == conn) + { + NSPOL_LOGERR("Invalid param]msg->conn=%p", conn); + SET_MSG_ERR(m, ERR_VAL); + goto err_return; + } + + tcpState = tpcb->state; + + if ((SPL_ERR_IS_FATAL(conn->last_err)) + && !((ERR_CLSD == conn->last_err) && (CLOSE_WAIT == tcpState))) + { + SET_MSG_ERR(m, conn->last_err); + } + else + { + if (cpcb->type == SPL_NETCONN_TCP) + { + if (cpcb->current_msg != NULL) + { + if (NULL == cpcb->msg_head || NULL == cpcb->msg_tail) + { + /* if possible only if connect is not finished and it's + blocking, then the current_msg is connect msg. + */ + NSPOL_LOGERR("netconn do_write msg is null]msg_type=%d", + cpcb->current_msg->param.minor_type); + goto err_return; + } + + /* only msg_write_buf will be in msg_head-msg_tail queue */ + wmsg->next = NULL; + cpcb->msg_tail->next = wmsg; + cpcb->msg_tail = wmsg; + (void) do_writemore(conn); + NSTCP_LOGINF("do_write finished...."); + return; + } + + if (conn->state != SPL_NETCONN_NONE) + { + /* netconn is connecting, closing or in blocking write */ + NSPOL_LOGINF(TCP_DEBUG, + "msg->conn->state != SPL_NETCONN_NONE..netconn is connecting, " + "closing or in blocking write]conn=%p", conn); + SET_MSG_ERR(m, ERR_INPROGRESS); + } + /* this means we should start to process this message */ + else if (tpcb != NULL) + { + conn->state = SPL_NETCONN_WRITE; + + /* set all the variables used by do_writemore */ + if (0 != cpcb->write_offset) + { + NSPOL_LOGERR("already writing or closing]conn=%p", conn); + goto err_return; + } + + if (0 == wmsg->len) + { + NSPOL_LOGERR("msg->msg.w.len=0]conn=%p", conn); + goto err_return; + } + + /* record the msg will be processed */ + cpcb->current_msg = m; + if (cpcb->msg_head != NULL || cpcb->msg_tail != NULL) + { + NSPOL_LOGERR("error maybe lost mesg]conn=%p", conn); + } + cpcb->msg_head = cpcb->msg_tail = wmsg; + wmsg->next = NULL; + cpcb->write_offset = 0; + + (void) do_writemore(conn); + + if ((conn->snd_buf) > TCP_SNDLOWAT) + { + if (cpcb->model == SOCKET_STACKX) + SPL_API_EVENT(conn, SPL_NETCONN_EVT_SENDPLUS, 1); + } + NSTCP_LOGINF("do_write finished %d", conn->snd_buf); + + /* for both cases: if do_writemore was called, don't ACK the APIMSG + since do_writemore ACKs it! */ + return; + } + else + { + SET_MSG_ERR(m, ERR_CONN); + } + } + else + { + SET_MSG_ERR(m, ERR_VAL); + } + } + NSTCP_LOGINF("do_write finished"); + + err_return: + pbuf_free_safe(wmsg->p); + ASYNC_MSG_FREE(m); + + return; +} + +void do_getsockname(struct common_pcb *cpcb, msg_getaddrname * amsg) +{ + spl_netconn_t *conn; + struct tcp_pcb *tcp; + struct udp_pcb *udp; + struct sockaddr_in *paddr = (struct sockaddr_in *) &amsg->sock_addr; + + data_com_msg *m = MSG_ENTRY(amsg, data_com_msg, buffer); + + if ((NULL == cpcb) || !(conn = cpcb->conn)) + { + NSTCP_LOGERR("failed to get sock"); + paddr->sin_family = 0; + paddr->sin_port = 0; + paddr->sin_addr.s_addr = 0; + SET_MSG_ERR(m, ERR_CONN); + return; + } + + NS_LOG_CTRL(LOG_CTRL_GETSOCKNAME, LOGTCP, "NSTCP", NSLOG_DBG, + "cpcb=%p,conn=%p,cmd=%u", cpcb, cpcb->conn, amsg->cmd); + + paddr->sin_family = AF_INET; + SET_MSG_ERR(m, ERR_OK); + + if (amsg->cmd == 0) + { + if (cpcb->type == SPL_NETCONN_TCP) + { + tcp = (struct tcp_pcb *) cpcb->conn->private_data; + /* add judgement:(NETCONN_LISTEN == conn->state) in following if words */ + /* If connect is not done in TCP then the remote address will not be there so need to update proper error code + if the application call the getpeername in TCP mode */ + if ((SPL_NETCONN_LISTEN == conn->state) + || (tcp->remote_ip.addr == 0) || (tcp->remote_port == 0)) + { + paddr->sin_family = 0; + paddr->sin_port = 0; + paddr->sin_addr.s_addr = 0; + SET_MSG_ERR(m, ERR_CONN); + } + else + { + paddr->sin_port = spl_htons(tcp->remote_port); + paddr->sin_addr.s_addr = tcp->remote_ip.addr; + } + } + else if (cpcb->type == SPL_NETCONN_UDP) + { + udp = (struct udp_pcb *) cpcb->conn->private_data; + /* If connect is not done in UDP then the remote address will not be there so need to update proper error code + if the application call the getpeername in UDP mode + */ + if ((udp->remote_ip.addr == 0) || (udp->remote_port == 0)) + { + paddr->sin_family = 0; + paddr->sin_port = 0; + paddr->sin_addr.s_addr = 0; + SET_MSG_ERR(m, ERR_CONN); + } + else + { + paddr->sin_port = spl_htons(udp->remote_port); + paddr->sin_addr.s_addr = udp->remote_ip.addr; + } + } + } + else + { + if (cpcb->type == SPL_NETCONN_TCP) + { + tcp = (struct tcp_pcb *) cpcb->conn->private_data; + paddr->sin_port = spl_htons(tcp->local_port); + paddr->sin_addr.s_addr = tcp->local_ip.addr; + } + else if (cpcb->type == SPL_NETCONN_UDP) + { + udp = (struct udp_pcb *) cpcb->conn->private_data; + paddr->sin_port = spl_htons(udp->local_port); + paddr->sin_addr.s_addr = udp->local_ip.addr; + } + } +} + +/** + * Close a TCP pcb contained in a netconn + * Called from netconn_close + * + * @param msg the api_msg_msg pointing to the connection + */ +void do_close(struct common_pcb *cpcb, msg_close * cmsg) +{ + spl_netconn_t *conn = cpcb->conn; + data_com_msg *m = MSG_ENTRY(cmsg, data_com_msg, buffer); + + NSTCP_LOGDBG("msg->conn=%p,state=%d", conn, conn->state); + + /* @todo: abort running write/connect? */ + if ((conn->state != SPL_NETCONN_NONE) + && (conn->state != SPL_NETCONN_LISTEN) + && (conn->state != SPL_NETCONN_CONNECT)) + { + if (SPL_NETCONN_TCP != cpcb->type) + { + NSTCP_LOGERR("msg->conn=%p,type=%d", conn, cpcb->type); + return; + } + NSTCP_LOGWAR("msg->conn=%p,state=%d", conn, conn->state); + SET_MSG_ERR(m, ERR_INPROGRESS); + } + else if (cpcb->type == SPL_NETCONN_TCP) //clear codeDEX warning , CID:24336, cpcb can't be null. + { + struct tcp_pcb *tpcb = (struct tcp_pcb *) cpcb->conn->private_data; + + if (tpcb == NULL) + { + NSTCP_LOGERR("tpcb null msg->conn=%p,type=%d", conn, cpcb->type); + return; + } + if ((cmsg->shut != SPL_NETCONN_SHUT_RDWR) + && (conn->state == SPL_NETCONN_LISTEN)) + { + /* LISTEN doesn't support half shutdown */ + NSTCP_LOGERR + ("LISTEN doesn't support half shutdown!]conn=%p,pcb=%p,state=%d", + conn, tpcb, conn->state); + SET_MSG_ERR(m, ERR_CONN); + } + else + { + if (cmsg->shut & SPL_NETCONN_SHUT_RD) + { + /* Drain and delete mboxes */ + (void) netconn_drain(cpcb->type, conn); + unlink_recv_ring(conn); + } + + if (((NULL != cpcb->current_msg) + && (conn->state != SPL_NETCONN_CONNECT)) + || (0 != cpcb->write_offset)) + { + NSTCP_LOGERR + ("already writing or closing]conn=%p,pcb=%p,offset=%zu,curmsg=%p", + conn, tpcb, cpcb->write_offset, cpcb->current_msg); + SET_MSG_ERR(m, ERR_CONN); + return; + } + + if (conn->state == SPL_NETCONN_CONNECT) + { + if (cpcb->current_msg != NULL + && cpcb->current_msg->param.minor_type == + SPL_API_DO_CONNECT) + { + SET_MSG_ERR(m, ERR_RST); + SYNC_MSG_ACK(cpcb->current_msg); + } + else + { + NSTCP_LOGINF + ("already in connecting]conn=%p,cpcb=%p,msg=%p", conn, + cpcb, cpcb->current_msg); + } + /* maybe need to clean cpcb->msg_head */ + } + + conn->state = SPL_NETCONN_CLOSE; + cpcb->current_msg = m; + (void) do_close_internal(cpcb, 1); + + if (SPL_NETCONN_SHUT_RD == cmsg->shut + || SPL_NETCONN_SHUT_RDWR == cmsg->shut) + { + SPL_API_EVENT(conn, SPL_NETCONN_EVT_RCVPLUS, 1); + } + + return; + } + } + else + { + SET_MSG_ERR(m, ERR_VAL); + } +} + +/*trans kerner option to stackx option*/ +int ks_to_stk_opt(int opt) +{ + int stack_opt = opt; + switch (opt) + { + case SO_DEBUG: + stack_opt = SOF_DEBUG; + break; + case SO_ACCEPTCONN: + stack_opt = SOF_ACCEPTCONN; + break; + case SO_BROADCAST: + stack_opt = SOF_BROADCAST; + break; + case SO_KEEPALIVE: + stack_opt = SOF_KEEPALIVE; + break; + case SO_REUSEADDR: + stack_opt = SOF_REUSEADDR; + break; + case SO_DONTROUTE: + stack_opt = SOF_DONTROUTE; + break; + case SO_USELOOPBACK: + stack_opt = SOF_USELOOPBACK; + break; + case SO_OOBINLINE: + stack_opt = SOF_OOBINLINE; + break; + default: + stack_opt = opt; + break; + } + return stack_opt; +} + +void +do_get_tcpproto_getsockopt_internal(struct common_pcb *cpcb, + msg_setgetsockopt * smsg) +{ + int optname; + void *optval; + struct tcp_pcb *tpcb = (struct tcp_pcb *) cpcb->conn->private_data; + data_com_msg *m = MSG_ENTRY(smsg, data_com_msg, buffer); + + optname = smsg->optname; + optval = &smsg->optval; + + switch (optname) + { + case SPL_TCP_NODELAY: + *(int *) optval = tcp_nagle_disabled(tpcb); + NSPOL_LOGDBG(SOCKETS_DEBUG, "]fd=%d,TCP_NODELAY=%s", + cpcb->socket, (*(int *) optval) ? "on" : "off"); + break; + + case SPL_TCP_KEEPIDLE: + *(int *) optval = (int) (tpcb->keep_idle / 1000); + NSPOL_LOGDBG(SOCKETS_DEBUG, "]fd=%d,SPL_TCP_KEEPIDLE=%d", + cpcb->socket, *(int *) optval); + break; + case SPL_TCP_KEEPINTVL: + *(int *) optval = (int) (tpcb->keep_intvl / 1000); + NSPOL_LOGDBG(SOCKETS_DEBUG, "]fd=%d,SPL_TCP_KEEPINTVL=%d", + cpcb->socket, *(int *) optval); + break; + case SPL_TCP_KEEPCNT: + *(int *) optval = (int) tpcb->keep_cnt; + NSPOL_LOGDBG(SOCKETS_DEBUG, "]fd=%d,SPL_TCP_KEEPCNT=%d", + cpcb->socket, *(int *) optval); + break; + case SPL_TCP_INFO: + ((struct tcp_info *) optval)->tcpi_total_retrans = + (int) tpcb->nrtx; + ((struct tcp_info *) optval)->tcpi_snd_mss = (int) tpcb->mss; + ((struct tcp_info *) optval)->tcpi_rtt = (int) tpcb->sa; + ((struct tcp_info *) optval)->tcpi_snd_cwnd = (int) tpcb->cwnd; + break; + default: + NSPOL_LOGDBG(SOCKETS_DEBUG, "unsupported]optname=%d", optname); + SET_MSG_ERR(m, EOPNOTSUPP); + break; + } +} + +void +do_get_ipproto_getsockopt_internal(struct common_pcb *cpcb, + msg_setgetsockopt * smsg) +{ + int optname; + u32_t optlen; + void *optval; + + struct ip_pcb *ipcb = (struct ip_pcb *) (cpcb); + data_com_msg *m = MSG_ENTRY(smsg, data_com_msg, buffer); + + optname = smsg->optname; + optval = &smsg->optval; + optlen = smsg->optlen; + + switch (optname) + { + case IP_TTL: + *(int *) optval = ipcb->ttl; + NSPOL_LOGDBG(SOCKETS_DEBUG, "]fd=%d,IP_TTL=%d", + cpcb->socket, *(int *) optval); + break; + case IP_TOS: + smsg->optlen = + (optlen < sizeof(u32_t)) ? sizeof(u8_t) : sizeof(u32_t); + if (smsg->optlen == sizeof(u8_t)) + { + *(u8_t *) optval = ipcb->tos; + } + else + { + *(u32_t *) optval = (u32_t) ipcb->tos; + } + NSPOL_LOGDBG(SOCKETS_DEBUG, "]fd=%d,IP_TOS=%d", + cpcb->socket, *(int *) optval); + break; + default: + SET_MSG_ERR(m, ERR_VAL); + NSPOL_LOGDBG(SOCKETS_DEBUG, "unsupported]optname=%d", optname); + break; + } +} + +void +do_get_solsocket_getsockopt_internal(struct common_pcb *cpcb, + msg_setgetsockopt * smsg) +{ + int optname; + void *optval; + struct tcp_pcb *tpcb = NULL; + data_com_msg *m = MSG_ENTRY(smsg, data_com_msg, buffer); + struct tcp_pcb *pcb = (struct tcp_pcb *) cpcb->conn->private_data; + + optname = smsg->optname; + optval = &smsg->optval; + + switch (optname) + { + /* The option flags */ + case SO_BROADCAST: + case SO_KEEPALIVE: + case SO_REUSEADDR: + *(int *) optval = + (ip_get_option + ((struct ip_pcb *) cpcb, ks_to_stk_opt(optname))) ? 1 : 0; + NSPOL_LOGDBG(SOCKETS_DEBUG, "]fd=%d,optname=%d,optval=%s", + cpcb->socket, optname, + (*(int *) optval ? "on" : "off")); + break; + case SO_ACCEPTCONN: + tpcb = (struct tcp_pcb *) cpcb->conn->private_data; + if ((smsg->optlen < sizeof(int)) || (NULL == tpcb)) + { + SET_MSG_ERR(m, ERR_VAL); + NSPOL_LOGDBG(SOCKETS_DEBUG, + "(SOL_SOCKET, SO_ACCEPTCONN) failed]fd=%d,tcp=%p,optlen=%u", + cpcb->socket, cpcb, smsg->optlen); + break; + } + if (tpcb->state == LISTEN) + { + *(int *) optval = 1; + } + else + { + *(int *) optval = 0; + } + NSPOL_LOGDBG(SOCKETS_DEBUG, + "(SOL_SOCKET, SO_ACCEPTCONN)]fd=%d,optval=%d", + cpcb->socket, *(int *) optval); + break; + case SO_TYPE: + switch (cpcb->type) + { + case SPL_NETCONN_RAW: + *(int *) optval = SOCK_RAW; + break; + case SPL_NETCONN_TCP: + *(int *) optval = SOCK_STREAM; + break; + case SPL_NETCONN_UDP: + *(int *) optval = SOCK_DGRAM; + break; + default: /* unrecognized socket type */ + *(int *) optval = cpcb->type; + NSPOL_LOGDBG(SOCKETS_DEBUG, + "(SOL_SOCKET, SO_TYPE): unrecognized socket type]fd=%d,optval=%d", + cpcb->socket, *(int *) optval); + } /* switch (sock->conn->type) */ + NSPOL_LOGDBG(SOCKETS_DEBUG, + "(SOL_SOCKET, SO_TYPE)]fd=%d,optval=%d", + cpcb->socket, *(int *) optval); + break; + case SO_RCVTIMEO: + (*(struct timeval *) optval).tv_sec = + spl_netconn_get_recvtimeout(cpcb) / 1000; + (*(struct timeval *) optval).tv_usec = + (spl_netconn_get_recvtimeout(cpcb) % 1000) * 1000; + NSPOL_LOGDBG(SOCKETS_DEBUG, + "stackx_getsockopt(SOL_SOCKET, SO_RCVTIMEO)]fd=%d,sec=%ld,usec=%ld", + cpcb->socket, (*(struct timeval *) optval).tv_sec, + (*(struct timeval *) optval).tv_usec); + break; + case SO_SNDTIMEO: + (*(struct timeval *) optval).tv_sec = + spl_netconn_get_sendtimeout(cpcb) / 1000; + (*(struct timeval *) optval).tv_usec = + (spl_netconn_get_sendtimeout(cpcb) % 1000) * 1000; + NSPOL_LOGDBG(SOCKETS_DEBUG, + "(SOL_SOCKET, SO_SNDTIMEO)]fd=%dsec=%ld,usec=%ld", + cpcb->socket, (*(struct timeval *) optval).tv_sec, + (*(struct timeval *) optval).tv_usec); + break; + case SO_SNDBUF: + { + u16_t mss = (pcb->mss > TCP_MSS + || pcb->mss == 0) ? TCP_MSS : pcb->mss; + *(int *) optval = + spl_netconn_get_sendbufsize(cpcb->conn) * mss; + /*If user has not configured any sendbuffer value then we should return minimum + promissed for the connection based on the flow control. */ + if (*(int *) optval == 0) + { + *(int *) optval = CONN_TCP_MEM_MIN_LINE * mss; + } + NSPOL_LOGDBG(SOCKETS_DEBUG, + "(SOL_SOCKET, SO_SNDBUF)]fd=%d,optval=%d", + cpcb->socket, *(int *) optval); + break; + } + case SO_NO_CHECK: + *(int *) optval = + (udp_flags((struct udp_pcb *) cpcb->conn->private_data) & + UDP_FLAGS_NOCHKSUM) ? 1 : 0; + NSPOL_LOGDBG(SOCKETS_DEBUG, + "(SOL_SOCKET, SO_NO_CHECK)fd=%d,optval=%d", + cpcb->socket, *(int *) optval); + break; + case SO_SNDLOWAT: + *(int *) optval = 1; + NSPOL_LOGDBG(SOCKETS_DEBUG, + "(SOL_SOCKET, SO_SNDLOWAT)fd=%d,optval=%d", + cpcb->socket, *(int *) optval); + break; + + case SO_RCVLOWAT: + *(int *) optval = spl_netconn_get_reclowbufsize(cpcb); + NSPOL_LOGDBG(SOCKETS_DEBUG, + "(SOL_SOCKET, SO_RCVLOWAT)fd=%d,optval=%d", + cpcb->socket, *(int *) optval); + break; + case SO_ERROR: + *(int *) optval = GET_MSG_ERR(m); + SET_MSG_ERR(m, 0); + NSPOL_LOGDBG(SOCKETS_DEBUG, "SOL_SOCKET]fd=%d,optval=%d", + cpcb->socket, *(int *) optval); + break; + default: + SET_MSG_ERR(m, ERR_VAL); + NSPOL_LOGDBG(SOCKETS_DEBUG, "unsupported opt]optname=%d", + optname); + break; + } +} + +void do_getsockopt_internal(struct common_pcb *cpcb, msg_setgetsockopt * smsg) +{ + int level; + + if (NULL == smsg) + { + NSTCP_LOGERR("arg NULL"); + return; + } + + data_com_msg *m = MSG_ENTRY(smsg, data_com_msg, buffer); + + level = smsg->level; + switch (level) + { + /* Level: SOL_SOCKET */ + case SOL_SOCKET: + do_get_solsocket_getsockopt_internal(cpcb, smsg); + + break; + + /* Level: IPPROTO_IP */ + case IPPROTO_IP: + do_get_ipproto_getsockopt_internal(cpcb, smsg); + + break; + /* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + do_get_tcpproto_getsockopt_internal(cpcb, smsg); + + break; + default: + SET_MSG_ERR(m, ERR_VAL); + NSPOL_LOGDBG(SOCKETS_DEBUG, "unsupported level]level=%d", level); + break; + } /* switch (level) */ +} + +void do_tcpsock_setsockopt(spl_netconn_t * conn, msg_setgetsockopt * smsg) +{ + const void *optval; + int optname; + struct common_pcb *cpcb = (struct common_pcb *) conn->comm_pcb_data; + struct tcp_pcb *tpcb = (struct tcp_pcb *) conn->private_data; + + data_com_msg *m = MSG_ENTRY(smsg, data_com_msg, buffer); + + optname = smsg->optname; + optval = &smsg->optval; + + switch (optname) + { + case SPL_TCP_NODELAY: + if (*(int *) optval) + { + tcp_nagle_disable(tpcb); + } + else + { + tcp_nagle_enable(tpcb); + } + + NSTCP_LOGDBG("IPPROTO_TCP, TCP_NODELAY]fd=%d,optval=%s", + cpcb->socket, (*(int *) optval) ? "on" : "off"); + break; + + case SPL_TCP_KEEPIDLE: + /* CID 52121 (#2 of 3): Other violation (HW_VPP_C_FIND_OPERATORS_2_1_1_3) */ + if ((u32_t) (*(int *) optval) >= INT_MAX / 1000) + { + NSTCP_LOGWAR("optval too big]optval=%u", + (u32_t) (*(int *) optval)); + *(int *) optval = INT_MAX / 1000; + } + + tpcb->keep_idle = 1000 * (u32_t) (*(int *) optval); + + if (tpcb->keep_idle > TCP_KEEPIDLE_DEFAULT) + { + NSTCP_LOGWAR + ("(%d, IPPROTO_TCP, SPL_TCP_KEEPIDLE. value bigger than 7200000UL so setting to default 7200000UL) requested is -> %" + U32_F " ", cpcb->socket, tpcb->keep_idle); + tpcb->keep_idle = TCP_KEEPIDLE_DEFAULT; + } + + NSTCP_LOGDBG("IPPROTO_TCP, SPL_TCP_KEEPIDLE](fd=%d,keep_idle=%" + U32_F " ", cpcb->socket, tpcb->keep_idle); + + /* Not required lwip_slowtmr will take care about timer. */ + break; + case SPL_TCP_KEEPINTVL: + /* CID 52121 (#1 of 3): Other violation (HW_VPP_C_FIND_OPERATORS_2_1_1_3) */ + if ((u32_t) (*(int *) optval) >= INT_MAX / 1000) + { + NSTCP_LOGWAR("optval too big]optval=%u", + (u32_t) (*(int *) optval)); + *(int *) optval = INT_MAX / 1000; + } + + tpcb->keep_intvl = 1000 * (u32_t) (*(int *) optval); + + if (tpcb->keep_intvl > TCP_KEEPIDLE_DEFAULT) /*max timer value supported */ + { + NSTCP_LOGWAR + ("(%d, IPPROTO_TCP, SPL_TCP_KEEPINTVL. value bigger than 7200000UL so setting to default 7200000UL) requested is -> %" + U32_F " ", cpcb->socket, tpcb->keep_intvl); + tpcb->keep_intvl = TCP_KEEPIDLE_DEFAULT; + } + NSTCP_LOGDBG("IPPROTO_TCP, SPL_TCP_KEEPINTVL]fd=%d,keep_intvl=%" + U32_F " ", cpcb->socket, tpcb->keep_intvl); + break; + case SPL_TCP_KEEPCNT: + tpcb->keep_cnt = (u32_t) (*(int *) optval); + NSTCP_LOGDBG("IPPROTO_TCP, SPL_TCP_KEEPCNT]fd=%d,keep_cnt=%" U32_F + " ", cpcb->socket, tpcb->keep_cnt); + break; + default: + SET_MSG_ERR(m, ERR_VAL); + NSPOL_LOGDBG(SOCKETS_DEBUG, "unsupported]optname=%d", optname); + break; + } +} + +void do_ipsock_setsockopt(struct common_pcb *cpcb, msg_setgetsockopt * smsg) +{ + const void *optval; + u32_t optlen; + int optname; + + data_com_msg *m = MSG_ENTRY(smsg, data_com_msg, buffer); + + struct udp_pcb *upcb = (struct udp_pcb *) cpcb->conn->private_data; + struct ip_pcb *ipcb = (struct ip_pcb *) upcb; + + optname = smsg->optname; + optval = &smsg->optval; + optlen = smsg->optlen; + + int val = 0; + int bNotAllowSet = 0; + switch (optname) + { + case IP_TTL: + ipcb->ttl = (u8_t) (*(int *) optval); + NSIP_LOGDBG("IPPROTO_IP,IP_TTL]fd=%d,ttl=%u", cpcb->socket, + ipcb->ttl); + break; + case IP_TOS: + bNotAllowSet = (cpcb->dataSentFlag != 0) + && ((SPL_NETCONN_TCP == cpcb->type) + || (SPL_NETCONN_UDP == cpcb->type) + || (SPL_NETCONN_RAW == cpcb->type)); + /*not allow set tos value when sending data */ + if (bNotAllowSet) + { + SET_MSG_ERR(m, ERR_VAL); + break; + } + + if (optlen >= sizeof(u32_t)) + { + val = (int) (*(const int *) optval); + } + else if (optlen >= sizeof(u8_t)) + { + val = (int) (*(const u8_t *) optval); + } + + if (SPL_NETCONN_TCP == cpcb->type) + { + val &= ~INET_ECN_MASK; + val |= ipcb->tos & INET_ECN_MASK; + } + ipcb->tos = (u8_t) (val); + + smsg->msg_box = (get_msgbox((u8_t) val))->llring; + + NSIP_LOGDBG("IPPROTO_IP,IP_TOS]]fd=%d,tos=%u", cpcb->socket, + ipcb->tos); + break; + default: + SET_MSG_ERR(m, ERR_VAL); + NSPOL_LOGDBG(SOCKETS_DEBUG, "unsupported]optname=%d", optname); + break; + } +} + + /*Made seperate functions to reduce code complexity */ +void +do_setsockopt_recvtimeout_internal(const void *optval, + struct common_pcb *cpcb) +{ + if ((*(struct timeval *) optval).tv_sec < 0) + { + spl_netconn_set_recvtimeout(cpcb, 0); + } + else + { + spl_netconn_set_recvtimeout(cpcb, MAX_WAIT_TIMEOUT); + if ((*(struct timeval *) optval).tv_sec != 0 + || (*(struct timeval *) optval).tv_usec != 0) + { + if ((*(struct timeval *) optval).tv_sec < + ((MAX_WAIT_TIMEOUT / 1000) - 1)) + { + spl_netconn_set_recvtimeout(cpcb, + (*(struct timeval *) + optval).tv_sec * 1000 + + (*(struct timeval *) + optval).tv_usec / 1000); + } + } + } + + NSPOL_LOGDBG(SOCKETS_DEBUG, + "SOL_SOCKET, SO_RCVTIMEO]conn=%p,fd=%d,optval=%d", cpcb, + cpcb->socket, cpcb->recv_timeout); +} + +void +do_setsockopt_sndtimeout_internal(const void *optval, struct common_pcb *cpcb) +{ + if ((*(struct timeval *) optval).tv_sec < 0) + { + spl_netconn_set_sendtimeout(cpcb, 0); + } + else + { + spl_netconn_set_sendtimeout(cpcb, MAX_WAIT_TIMEOUT); + if ((*(struct timeval *) optval).tv_sec != 0 + || (*(struct timeval *) optval).tv_usec != 0) + { + if ((*(struct timeval *) optval).tv_sec < + ((MAX_WAIT_TIMEOUT / 1000) - 1)) + { + spl_netconn_set_sendtimeout(cpcb, + (*(struct timeval *) + optval).tv_sec * 1000 + + (*(struct timeval *) + optval).tv_usec / 1000); + } + } + } + + NSPOL_LOGDBG(SOCKETS_DEBUG, + "SOL_SOCKET, SO_SNDTIMEO]conn=%p,fd=%d,optval=%d", cpcb, + cpcb->socket, cpcb->send_timeout); +} + +#define IS_TCP_PCB(cpcb) (cpcb && (cpcb->conn) && (SPL_NETCONN_TCP == cpcb->conn->type)) +NSTACK_STATIC inline void +set_opt_sol_socket(struct common_pcb *cpcb, struct tcp_pcb *pcb, + data_com_msg * m, int level, int optname, + const void *optval) +{ + switch (optname) + { + /* The option flags */ + case SO_BROADCAST: + + /* UNIMPL case SO_DEBUG: */ + /* UNIMPL case SO_DONTROUTE: */ + case SO_KEEPALIVE: + case SO_REUSEADDR: + + if (NULL == pcb) + { + NSPOL_LOGERR("conn->pcb.ip is null"); + break; + } + + if (*(const int *) optval) + { + ip_set_option((struct ip_pcb *) pcb, ks_to_stk_opt(optname)); + } + else + { + ip_reset_option((struct ip_pcb *) pcb, + ks_to_stk_opt(optname)); + } + + NSPOL_LOGDBG(SOCKETS_DEBUG, + "]conn=%p,fd=%d,optname=0x%x,optval=%s", cpcb, + cpcb->socket, optname, + (*(const int *) optval ? "on" : "off")); + + /* No use now, since tcp_slowtmr will take care about not sending/sending of keepalive */ + break; + + case SO_RCVLOWAT: + spl_netconn_set_reclowbufsize(cpcb, *(int *) optval); + NSPOL_LOGDBG(SOCKETS_DEBUG, + "SOL_SOCKET, SO_RCVLOWAT]conn=%p,fd=%d,optval=%d", + cpcb, cpcb->socket, cpcb->sk_rcvlowat); + break; + + case SO_RCVTIMEO: + /*to reduce code complexity */ + do_setsockopt_recvtimeout_internal(optval, cpcb); + break; + + case SO_SNDTIMEO: + /*to reduce code complexity */ + do_setsockopt_sndtimeout_internal(optval, cpcb); + break; + + case SO_SNDBUF: + { + /* udp pcb invalid access will cause coredump */ + if (!IS_TCP_PCB(cpcb)) + { + NSPOL_LOGDBG(SOCKETS_DEBUG, + "not support for non tcp socket]optname=%d, level=%d", + optname, level); + return; + } + + u16_t mss = (pcb->mss > TCP_MSS + || pcb->mss == 0) ? TCP_MSS : pcb->mss; + + if (*(int *) optval < (int) mss) + { + /*set value of one TCP_MSS */ + spl_netconn_set_sendbufsize(cpcb->conn, 1); + } + else + { + spl_netconn_set_sendbufsize(cpcb->conn, + (*(int *) optval) / + (int) mss); + } + + NSPOL_LOGDBG(SOCKETS_DEBUG, + "SOL_SOCKET, SO_SNDBUF]conn=%p,fd=%d,optval=%d", + cpcb, cpcb->socket, + cpcb->conn->send_bufsize * mss); + break; + } + + case SO_NO_CHECK: + /* How udp is coming here.. ?? @TODO: May be move to someother function.? */ + /* solve segment issue when the PCB is not exist */ + if (NULL == cpcb) + { + NSPOL_LOGERR("conn->pcb.udp is null"); + break; + } + + struct udp_pcb *upcb = (struct udp_pcb *) pcb; + + if (*(int *) optval) + { + udp_setflags(upcb, udp_flags(upcb) | UDP_FLAGS_NOCHKSUM); + } + else + { + udp_setflags(upcb, udp_flags(upcb) & ~UDP_FLAGS_NOCHKSUM); + } + + NSPOL_LOGDBG(SOCKETS_DEBUG, + "SOL_SOCKET, SO_NO_CHECK]conn=%p,fd=%d,optval=0x%x", + cpcb, cpcb->socket, upcb->flags); + break; + + default: + SET_MSG_ERR(m, ERR_VAL); + NSPOL_LOGDBG(SOCKETS_DEBUG, "unsupported]optname=%d", optname); + break; + } /* switch (optname) */ + +} + +void do_setsockopt_internal(struct common_pcb *cpcb, msg_setgetsockopt * smsg) +{ + int level, optname; + const void *optval; + + data_com_msg *m = MSG_ENTRY(smsg, data_com_msg, buffer); + struct tcp_pcb *pcb = (struct tcp_pcb *) cpcb->conn->private_data; + + if (NULL == smsg) + { + NSTCP_LOGERR("arg null!"); + return; + } + + level = smsg->level; + optname = smsg->optname; + optval = &smsg->optval; + + switch (level) + { + /* Level: SOL_SOCKET */ + case SOL_SOCKET: + set_opt_sol_socket(cpcb, pcb, m, SOL_SOCKET, optname, optval); + break; + + /* Level: IPPROTO_IP */ + case IPPROTO_IP: + + if (NULL == cpcb) + { + NSPOL_LOGERR("conn->pcb.ip is null"); + break; + } + + do_ipsock_setsockopt(cpcb, smsg); + + break; + /* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + /* udp pcb invalid access will cause coredump */ + if (!IS_TCP_PCB(cpcb)) + { + SET_MSG_ERR(m, ERR_VAL); + NSPOL_LOGDBG(SOCKETS_DEBUG, + "not support for non tcp socket]optname=%d,level=%d", + optname, level); + return; + } + + if (NULL == cpcb) + { + NSPOL_LOGERR("conn->pcb.tcp is null"); + break; + } + + do_tcpsock_setsockopt(cpcb->conn, smsg); + + break; + default: + SET_MSG_ERR(m, ERR_VAL); + NSPOL_LOGDBG(SOCKETS_DEBUG, "unsupported]level=%d", level); + break; + } /* switch (level) */ +} + +/*app send its version info to nStackMain */ +void do_app_touch(msg_app_touch * smsg) +{ + //write app version info to running.log + NSPOL_LOGINF(SOCKETS_DEBUG, "hostpid=%u,app_version=%s", smsg->hostpid, + smsg->app_version); +} + +void tcp_free_accept_ring(spl_netconn_t * conn) +{ + err_t de_err = ERR_OK; + spl_netconn_t *newconn; + while (1) + { + newconn = NULL; + /* -1 means nonblocking */ + de_err = accept_dequeue(conn, (void **) &newconn, (u32_t) - 1); + if (de_err == ERR_WOULDBLOCK || newconn == NULL) + return; + + tcp_drop_conn(newconn); + } +} + +void tcp_drop_conn(spl_netconn_t * conn) +{ + /* usually we should not access pcb by recv_obj, but no choice */ + struct tcp_pcb *pcb = (struct tcp_pcb *) conn->private_data; + + /* free conn first, even pcb is NULL */ + free_conn_by_spl(conn); + + if (pcb == NULL) + { + NSTCP_LOGWAR + ("a tcp connection in accept queue without pcb!]newconn=%p", + conn); + return; + } + + /* tell peer conneciton is reset */ + NSTCP_LOGWAR("sending RST in accept waiting queue!]pcb=%p", pcb); + + tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + pcb->local_port, pcb->remote_port); + + tcp_pcb_remove(&tcp_active_pcbs, pcb); + memp_free(MEMP_TCP_PCB, pcb); +} + +void update_tcp_state(spl_netconn_t * conn, enum tcp_state state) +{ + spl_tcp_state_t spl_state; + + if (conn != NULL) + { + switch (state) + { + case CLOSED: + spl_state = SPL_CLOSED; + break; + case LISTEN: + spl_state = SPL_LISTEN; + break; + case SYN_SENT: + spl_state = SPL_SYN_SENT; + break; + case SYN_RCVD: + spl_state = SPL_SYN_RCVD; + break; + case ESTABLISHED: + spl_state = SPL_ESTABLISHED; + break; + case FIN_WAIT_1: + spl_state = SPL_FIN_WAIT_1; + break; + case FIN_WAIT_2: + spl_state = SPL_FIN_WAIT_2; + break; + case CLOSE_WAIT: + spl_state = SPL_CLOSE_WAIT; + break; + case CLOSING: + spl_state = SPL_CLOSING; + break; + case LAST_ACK: + spl_state = SPL_LAST_ACK; + break; + case TIME_WAIT: + spl_state = SPL_TIME_WAIT; + break; + default: + spl_state = SPL_CLOSED; + break; + } + if (conn->tcp_state != spl_state) + { + conn->tcp_state = spl_state; + NSTCP_LOGINF("conn=%p,private_data=%p,state=%d", conn, + conn->private_data, spl_state); + } + } +} + +void do_update_pcbstate() +{ + struct tcp_pcb *tpcb; + int i; + for (i = 0; i < NUM_TCP_PCB_LISTS; i++) + { + for (tpcb = *tcp_pcb_lists[i]; tpcb != NULL; tpcb = tpcb->next) + { + if (tpcb->callback_arg) + { + update_tcp_state((spl_netconn_t *) tpcb->callback_arg, + tpcb->state); + } + } + } + + return; +} + +void init_stackx_lwip() +{ + lwip_init(); + sys_timeouts_init(); + return; +} + +void free_common_pcb(struct common_pcb *cpcb) +{ + if (res_free(&cpcb->res_chk)) + { + NSFW_LOGERR("conn refree!]conn=%p", cpcb->conn); + return; + } + + common_pcb_reset(cpcb); + + mring_handle pool = p_def_stack_instance->cpcb_seg; + if (nsfw_mem_ring_enqueue(pool, (void *) cpcb) != 1) + { + NSSBR_LOGERR("nsfw_mem_ring_enqueue failed,this can not happen"); + } + return; +} + +struct common_pcb *alloc_common_pcb(enum spl_netconn_type type) +{ + struct common_pcb *cpcb = NULL; + + if (nsfw_mem_ring_dequeue(p_def_stack_instance->cpcb_seg, (void **) &cpcb) + != 1) + { + NSSBR_LOGERR("malloc conn failed"); + return NULL; + } + + NSFW_LOGINF("alloc_common_pcb]cpcb=%p", cpcb); + + common_pcb_init(cpcb); + cpcb->type = type; + + res_alloc(&cpcb->res_chk); + return cpcb; +} diff --git a/stacks/lwip_stack/lwip_src/api/spl_netbuf.c b/stacks/lwip_stack/lwip_src/api/spl_netbuf.c new file mode 100644 index 0000000..602e48d --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/spl_netbuf.c @@ -0,0 +1,57 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ +//#include "sc_dpdk.h" +#include "spl_netbuf.h" + +void spl_netbuf_delete(struct spl_netbuf *buf) +{ + if (likely(buf != NULL)) + { + spl_pbuf_free(PTR_SHTOL(struct spl_pbuf *, buf->p)); + } +} diff --git a/stacks/lwip_stack/lwip_src/api/spl_netifapi.c b/stacks/lwip_stack/lwip_src/api/spl_netifapi.c new file mode 100644 index 0000000..82ac27b --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/spl_netifapi.c @@ -0,0 +1,279 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "spl_opt.h" + +#if STACKX_NETIF_API + +#include "nsfw_msg_api.h" +#include "netifapi.h" +#include +//#include + +#include "stackx_spl_share.h" +#include "spl_sbr.h" +#include "stackx/spl_api.h" +#include "tcpip.h" +#include "sc_dpdk.h" +#include "spl_instance.h" +#include "spl_hal.h" +#include "spl_def.h" +#include + +struct netifExt *gNetifExt = NULL; + +/** + * common operation for sbr message. + * + * @param msg the api_msg_msg describing the connection type + */ +int do_halmsg(data_com_msg * m) +{ + NSPOL_LOGDBG(TESTSOCKET_DEBUG | STACKX_DBG_TRACE, + "the msg is from HAL module, minor(%u)", + m->param.minor_type); + return 0; +} + +static int _do_add_netif(data_com_msg * m) +{ + NSPOL_LOGINF(NETIF_DEBUG, "_do_add_netif\n"); + + m->param.err = ERR_OK; + msg_add_netif *_m = (msg_add_netif *) m->buffer; + _m->function(_m); + SYNC_MSG_ACK(m); + return 0; +} + +struct netif *find_netif_by_if_name(char *if_name) +{ + + struct netifExt *netifEx = gNetifExt; + struct netif *netif = NULL; + + while (netifEx != NULL) + { + if (!(strcmp(netifEx->if_name, if_name))) + { + for (netif = netif_list; netif != NULL; netif = netif->next) + { + if (netifEx->id == netif->num) + return netif; + } + + } + netifEx = netifEx->next; + } + + return NULL; +} + +/*@TODO: May be moved to some other file ? Like HAL*/ +struct netif *get_netif_by_ip(unsigned int ip) +{ + struct netif *netif; + + if (ip == 0) + { + return NULL; + } + + for (netif = netif_list; netif != NULL; netif = netif->next) + { + if (ip == netif->ip_addr.addr) + { + NSPOL_LOGINF(NETIF_DEBUG, "netif_find: found %x %c %c", ip, + netif->name[0], netif->name[1]); + return netif; + } + } + NSPOL_LOGINF(NETIF_DEBUG, "netif_find: Not found %x", ip); + return NULL; +} + +/* +@TODO: +*/ +struct netif *netif_check_broadcast_addr(spl_ip_addr_t * addr) +{ + return NULL; +} + +struct netifExt *getNetifExt(u16_t id) +{ + + struct netifExt *netifEx; + netifEx = gNetifExt; + + while (netifEx != NULL) + { + if (netifEx->id == id) + { + return netifEx; + } + netifEx = netifEx->next; + } + + return NULL; +} + +int netifExt_add(struct netif *netif) +{ + + /* If Netif Ext already created for it then just return sucess */ + if (getNetifExt(netif->num)) + return 0; + + struct netifExt *netifEx = malloc(sizeof(struct netifExt)); + if (!netifEx) + { + return -1; + } + + if (memset(netifEx, 0, sizeof(struct netifExt)) < 0) + { + return -1; + } + + NSPOL_LOGINF(NETIF_DEBUG, "netifExt_added \n"); + + netifEx->id = netif->num; + + /* add this netif to the list */ + netifEx->next = gNetifExt; + gNetifExt = netifEx; + return 0; +} + +void do_netifapi_netif_add(msg_add_netif * pmsg) +{ + struct netif *netif = NULL; + ip_addr_t ipaddr; + ip_addr_t netmask; + ip_addr_t gw; + + data_com_msg *m = MSG_ENTRY(pmsg, data_com_msg, buffer); + ipaddr.addr = pmsg->ipaddr->addr; + netmask.addr = pmsg->netmask->addr; + gw.addr = pmsg->gw->addr; + + NSPOL_LOGINF(NETIF_DEBUG, "do_netifapi_netif_add \n"); + netif = netif_add(pmsg->netif, + &ipaddr, + &netmask, &gw, pmsg->state, pmsg->init, pmsg->input); + + if (NULL == netif) + { + SET_MSG_ERR(m, ERR_IF); + } + else + { + + SET_MSG_ERR(m, ERR_OK); + NSPOL_LOGINF(NETIF_DEBUG, "netif created name %c%c%d\n", + netif->name[0], netif->name[1], netif->num); + pmsg->voidfunc(pmsg->netif); + add_disp_netif(pmsg->netif); + } + +} + +err_t +spl_netifapi_netif_add(struct netif *pnetif, + spl_ip_addr_t * ipaddr, + spl_ip_addr_t * netmask, + spl_ip_addr_t * gw, + void *state, + netif_init_fn init, + netif_input_fn input, netifapi_void_fn voidfunc) +{ + msg_add_netif stmsg; + + stmsg.function = do_netifapi_netif_add; + stmsg.netif = pnetif; + stmsg.ipaddr = ipaddr; + stmsg.netmask = netmask; + stmsg.gw = gw; + stmsg.state = state; + stmsg.init = init; + stmsg.input = input; + stmsg.voidfunc = voidfunc; + return tcpip_netif_add(&stmsg); +} + +int add_netif_ip(char *netif_name, unsigned int ip, unsigned int mask) +{ + struct netif *pnetif; + int retval; + + if (get_netif_by_ip(ip)) + { + NSPOL_LOGERR("ip is exist]IP=%s", inet_ntoa(ip)); + return -1; + } + NSPOL_LOGINF(NETIF_DEBUG, "add_netif_ip] IP=%s", inet_ntoa(ip)); + + pnetif = find_netif_by_if_name(netif_name); + if (pnetif == NULL) + { + return -1; + } + + pnetif->ip_addr.addr = ip; + pnetif->netmask.addr = mask; + + if (ip) + { + retval = etharp_request(pnetif, &pnetif->ip_addr); + + if (ERR_OK != retval) + { + NSPOL_LOGERR("etharp_request failed]retval=%d,netif=%p,ip=%u", retval, pnetif, pnetif->ip_addr.addr); //inet_ntoa is not thread-safe, print u32 instead. + } + } + + NSPOL_LOGINF(NETIF_DEBUG, "add_netif_ip]netif_name=%s,IP=%s,mask=0x%08x", + netif_name, inet_ntoa(ip), spl_htonl(mask)); + return 0; +} + +/*lint -e438*/ +int del_netif_ip(char *netif_name, unsigned int ip) +{ + struct netif *pnetif; + //struct netif* vnetif = NULL; + //struct netif** ref; + + pnetif = find_netif_by_if_name(netif_name); + if (NULL == pnetif) + { + return -1; + } + + NSPOL_LOGINF(NETIF_DEBUG, "del_netif_ip] IP=%s", inet_ntoa(ip)); + + pnetif->ip_addr.addr = 0; + pnetif->netmask.addr = 0; + return 0; +} + +REGIST_MSG_MODULE_MAJOR_FUN(MSG_MODULE_HAL, SPL_TCPIP_MSG_NETIFAPI, + do_halmsg); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_HAL, SPL_TCPIP_MSG_NETIFAPI, + NETIF_DO_ADD, _do_add_netif); + +#endif /* STACKX_NETIF_API */ diff --git a/stacks/lwip_stack/lwip_src/api/spl_sbr.c b/stacks/lwip_stack/lwip_src/api/spl_sbr.c new file mode 100644 index 0000000..58c25a1 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/spl_sbr.c @@ -0,0 +1,477 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "stackx_spl_share.h" +#include "spl_api.h" +#include "ip.h" +#include "spl_api_msg.h" +#include "stackx_spl_msg.h" +#include "internal_msg.h" +#include "spl_sbr.h" +#include "spl_pbuf.h" + +/** + * common operation for sbr message. + * + * @param msg the api_msg_msg describing the connection type + */ +int do_sbrmsg(data_com_msg * m) +{ + return 0; +} + +/** + * Create a new pcb of a specific type inside a netconn. + * Called from netconn_new_with_proto_and_callback. + * + * @param msg the api_msg_msg describing the connection type + */ +static int _do_newconn(data_com_msg * m) +{ + m->param.err = ERR_OK; + + msg_new_netconn *_m = (msg_new_netconn *) m->buffer; + m->param.err = spl_pcb_new(_m); + + if (ERR_OK != m->param.err) + { + NSPOL_LOGERR("pcb_new err]conn=%p,pid=%u,err=%d", _m->conn, + m->param.recycle_pid, m->param.err); + goto ERROR; + } + + NSFW_LOGINF("alloc pcb]conn=%p,pcb=%p,pid=%u", _m->conn, + _m->conn->private_data, m->param.recycle_pid); + + /* sbr use it to set receiver after new connction */ + m->param.receiver = (i64) & _m->conn->private_data; + m->param.comm_receiver = (i64) & _m->conn->comm_pcb_data; + _m->conn->recv_obj = m->param.receiver; + + SYNC_MSG_ACK(m); + return 0; + + ERROR: + SYNC_MSG_ACK(m); + return 0; +} + +int _do_connect(data_com_msg * m) +{ + m->param.err = ERR_OK; + + struct common_pcb *cpcb = COMM_PRIVATE_PTR(m); + if (cpcb == NULL) + { + m->param.err = ERR_CLSD; + SYNC_MSG_ACK(m); + return 0; + } + + msg_connect *_m = (msg_connect *) m->buffer; + do_connect(cpcb, _m); + + /** + * err == ERR_OK only applies for blocking connction, so others mean + * in progress for nonblocking connection or failed to connect + * cpcb may be NULL, so don't change the order of the 2 ifs. + */ + if (m->param.err != ERR_OK || cpcb->type != SPL_NETCONN_TCP) + SYNC_MSG_ACK(m); + + return 0; +} + +/** + * Close a TCP pcb contained in a netconn + * Called from netconn_close + * + * @param msg the api_msg_msg pointing to the connection + */ +int _do_close(data_com_msg * m) +{ + m->param.err = ERR_OK; + + struct common_pcb *cpcb = COMM_PRIVATE_PTR(m); + if (cpcb != NULL) + { + msg_close *_m = (msg_close *) m->buffer; + do_close(cpcb, _m); + } + + /* if cpcb == NULL, assuming the close is okay, err = ERR_OK */ + SYNC_MSG_ACK(m); + + return 0; +} + +/** + * Delete the pcb inside a netconn. + * Called from netconn_delete. + * + * @param msg the data_com_msg to handle + */ +static int _do_delconn(data_com_msg * m) +{ + m->param.err = ERR_OK; + msg_delete_netconn *_m = (msg_delete_netconn *) m->buffer; + + if (0 == (--_m->msg_box_ref)) + { + /* the aync msg is released inside */ + ss_recycle_conn((void *) _m, do_try_delconn); + } + + return 0; +} + +/** + * handle message to send UDP packets. + * + * @param msg the data_com_msg to handle + */ +static int _do_send(data_com_msg * m) +{ + m->param.err = ERR_OK; + + struct common_pcb *cpcb = COMM_PRIVATE_PTR(m); + msg_send_buf *_m = (msg_send_buf *) m->buffer; + if (cpcb == NULL) + { + NS_LOG_CTRL(LOG_CTRL_SEND, STACKPOOL, "NSLWIP", NSLOG_ERR, + "failed to find target pcb, drop the message]" + "module=%u, major=%u, minor=%u", + m->param.module_type, + m->param.major_type, m->param.minor_type); + + spl_pbuf_free(_m->p); + _m->p = NULL; + ASYNC_MSG_FREE(m); + return -1; + } + + do_send(cpcb, _m); + + ASYNC_MSG_FREE(m); + + return 0; +} + +/** + * handle message to send TCP packets. + * + * @param msg the data_com_msg to handle + */ +static int _do_write(data_com_msg * m) +{ + m->param.err = ERR_OK; + + void *tpcb = TCP_PRIVATE_PTR(m); + struct common_pcb *cpcb = COMM_PRIVATE_PTR(m); + + msg_write_buf *_m = (msg_write_buf *) m->buffer; + if ((tpcb == NULL) || (cpcb == NULL)) + { + NS_LOG_CTRL(LOG_CTRL_WRITE, STACKPOOL, "NSLWIP", NSLOG_ERR, + "failed to find target pcb, drop the message]" + "module=%u, major=%u, minor=%u", + m->param.module_type, + m->param.major_type, m->param.minor_type); + + spl_pbuf_free(_m->p); + _m->p = NULL; + ASYNC_MSG_FREE(m); + return -1; + } + + do_write(cpcb, _m); + + return 0; +} + +/** + * handle message to receive. + * + * @param msg the data_com_msg to handle + */ +static int _do_recv(data_com_msg * m) +{ + m->param.err = ERR_OK; + + msg_recv_buf *_m = (msg_recv_buf *) m->buffer; + void *tpcb = TCP_PRIVATE_PTR(m); + struct common_pcb *cpcb = COMM_PRIVATE_PTR(m); + + if ((tpcb == NULL) || (cpcb == NULL)) + { + NS_LOG_CTRL(LOG_CTRL_RECV, STACKPOOL, "NSLWIP", NSLOG_ERR, + "failed to find target pcb, drop the message]" + "module=%u, major=%u, minor=%u", + m->param.module_type, + m->param.major_type, m->param.minor_type); + + spl_pbuf_free(_m->p); + _m->p = NULL; + ASYNC_MSG_FREE(m); + return -1; + } + + do_recv(cpcb, _m); + ASYNC_MSG_FREE(m); + return 0; +} + +/** + * handle message to bind local address. + * + * @param msg the data_com_msg to handle + */ +static int _do_bind(data_com_msg * m) +{ + m->param.err = ERR_OK; + + struct common_pcb *cpcb = COMM_PRIVATE_PTR(m); + if (cpcb == NULL) + { + NSPOL_LOGERR("failed to find target pcb, drop the message]" + "module=%u, major=%u, minor=%u", + m->param.module_type, + m->param.major_type, m->param.minor_type); + + m->param.err = ERR_VAL; + SYNC_MSG_ACK(m); + return -1; + } + + msg_bind *_m = (msg_bind *) m->buffer; + do_bind(cpcb, _m); + + SYNC_MSG_ACK(m); + + return 0; +} + +/** + * handle message to listen for new connection. + * + * @param msg the data_com_msg to handle + */ +static int _do_listen(data_com_msg * m) +{ + m->param.err = ERR_OK; + + struct common_pcb *cpcb = COMM_PRIVATE_PTR(m); + if (cpcb == NULL) + { + NSPOL_LOGERR("failed to find target pcb, drop the message]" + "module=%u, major=%u, minor=%u", + m->param.module_type, + m->param.major_type, m->param.minor_type); + + m->param.err = ERR_CONN; + SYNC_MSG_ACK(m); + return -1; + } + + msg_listen *_m = (msg_listen *) m->buffer; + do_listen(cpcb, _m); + + /* Update since pcb may have been changed */ + //m->param.receiver = (i64)&_m->conn->private_data; + SYNC_MSG_ACK(m); + return 0; +} + +/** + * handle message to set socket option. + * + * @param msg the data_com_msg to handle + */ +static int _do_setsockopt(data_com_msg * m) +{ + m->param.err = ERR_OK; + + struct common_pcb *cpcb = COMM_PRIVATE_PTR(m); + if (cpcb == NULL) + { + + NSPOL_LOGERR("failed to find target pcb, drop the message]" + "module=%u, major=%u, minor=%u", + m->param.module_type, + m->param.major_type, m->param.minor_type); + + m->param.err = ERR_VAL; + SYNC_MSG_ACK(m); + return -1; + } + + msg_setgetsockopt *_m = (msg_setgetsockopt *) m->buffer; + do_setsockopt_internal(cpcb, _m); + + SYNC_MSG_ACK(m); + + return 0; +} + +/** + * handle message to get socket option. + * + * @param msg the data_com_msg to handle + */ +static int _do_getsockopt(data_com_msg * m) +{ + m->param.err = ERR_OK; + + struct common_pcb *cpcb = COMM_PRIVATE_PTR(m); + if (cpcb == NULL) + { + NSPOL_LOGERR("failed to find target pcb, drop the message]" + "module=%u, major=%u, minor=%u", + m->param.module_type, + m->param.major_type, m->param.minor_type); + + m->param.err = ERR_VAL; + SYNC_MSG_ACK(m); + return -1; + } + + msg_setgetsockopt *_m = (msg_setgetsockopt *) m->buffer; + do_getsockopt_internal(cpcb, _m); + + SYNC_MSG_ACK(m); + + return 0; +} + +/** + * handle message to free pbuf which never used afterwards by application. + * + * @param msg the data_com_msg to handle + */ + +static int _do_pbuf_free(data_com_msg * m) +{ + m->param.err = ERR_OK; + + msg_free_buf *_m = (msg_free_buf *) m->buffer; + do_pbuf_free(_m->buf); + + ASYNC_MSG_FREE(m); + + return 0; +} + +static int _do_getsock_name(data_com_msg * m) +{ + m->param.err = ERR_OK; + + struct common_pcb *cpcb = COMM_PRIVATE_PTR(m); + if (cpcb == NULL) + { + NSPOL_LOGERR("failed to find target pcb, drop the message]" + "module=%u, major=%u, minor=%u", + m->param.module_type, + m->param.major_type, m->param.minor_type); + + m->param.err = ERR_VAL; + SYNC_MSG_ACK(m); + return -1; + } + + msg_getaddrname *_m = (msg_getaddrname *) m->buffer; + do_getsockname(cpcb, _m); + + SYNC_MSG_ACK(m); + + return 0; +} + +/* app send its version info to nStackMain */ +static int _do_app_touch(data_com_msg * m) +{ + m->param.err = ERR_OK; + + msg_app_touch *_m = (msg_app_touch *) m->buffer; + do_app_touch(_m); + + ASYNC_MSG_FREE(m); + return 0; +} + +/** + * process message from sbr module, all the processing function + * is registered when nstack is up. + * + * @param msg the api_msg_msg pointing to the connection + */ +int spl_sbr_process(data_com_msg * m) +{ + if (m == NULL) + { + NSPOL_LOGERR("message is NULL"); + return -1; + } + + return call_msg_fun(m); +} + +int spl_unsupport_process(data_com_msg * m) +{ + NSPOL_LOGINF(TCPIP_DEBUG, "module_type=%u,major_type=%u,minor_type=%u", + m->param.module_type, m->param.major_type, + m->param.minor_type); + if (MSG_SYN_POST == m->param.op_type) + { + m->param.err = ERR_EPROTONOSUPPORT; + SYNC_MSG_ACK(m); + } + else + { + ASYNC_MSG_FREE(m); + } + + return -1; +} + +REGIST_MSG_UNSUPPORT_FUN(spl_unsupport_process); +REGIST_MSG_MODULE_MAJOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, do_sbrmsg); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_NEWCONN, _do_newconn); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_CONNECT, _do_connect); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_CLOSE, _do_close); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_DELCON, _do_delconn); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_SEND, _do_send); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_WRITE, _do_write); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_RECV, _do_recv); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_BIND, _do_bind); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_LISTEN, _do_listen); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_GET_SOCK_OPT, _do_getsockopt); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_SET_SOCK_OPT, _do_setsockopt); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_PBUF_FREE, _do_pbuf_free); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, + SPL_API_DO_GETSOCK_NAME, _do_getsock_name); +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_SBR, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_APP_TOUCH, _do_app_touch); /* app send its version info to nStackMain */ diff --git a/stacks/lwip_stack/lwip_src/api/spl_tcpip.c b/stacks/lwip_stack/lwip_src/api/spl_tcpip.c new file mode 100644 index 0000000..f3f0e70 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/spl_tcpip.c @@ -0,0 +1,1531 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "spl_opt.h" +#include +#include +#include +#include "memp.h" +#include "mem.h" +#include "spl_pbuf.h" +//#include "sockets.h" +//#include + +#include "stackx_spl_share.h" +#include "spl_api.h" +#include "spl_tcpip.h" +#include "init.h" +#include "stackx/internal_msg.h" +#include "netif/sc_dpdk.h" +#include "sharedmemory.h" +#include "stackx_instance.h" +#include "netif/common.h" +//#include "nettool/nettool.h" +#include "nstack_log.h" +#include "nstack_securec.h" +#include "spl_hal.h" +#include "spl_sbr.h" +#include "spl_tcpip.h" + +#include "spl_instance.h" +#include "nsfw_mem_api.h" +#include "nsfw_msg_api.h" +#include "configuration_reader.h" + +#include "nsfw_ps_api.h" +#include "alarm_api.h" +#include "nstack_share_res.h" +#include "spl_timers.h" + +#include "etharp.h" +#include "raw.h" +#include "udp.h" +#include "tcp.h" +#include "igmp.h" +#include "memp.h" +#include "inet.h" +#include "sys_arch.h" + +#include "sys.h" + +#define NSTACK_MAIN_MAX_PARA 32 +#define NSTACK_MAIN_MIN_PARA 1 + +#define DPDK_DEFAULT_EAL_MEM_SIZE (1024) + +#define OPT_EAL_MEM_SIZE "--eal-mem-size=" + +/********************/ +/* extern variables */ +/********************/ +extern mring_handle spl_get_msg_pool(); +extern mring_handle spl_get_conn_pool(); +extern u32 spl_get_conn_num(); +extern err_t ethernet_input(struct pbuf *p, struct netif *netif); +extern int nstack_epoll_init(int flag, int ns_sync_mod); + +/* tcpip main thread sleep time, configured by user(nStackMain "-sleep" option) */ +extern int g_tcpip_thread_sleep_time; + +/* netif related */ +extern struct stackx_port_info *head_used_port_list; + +extern u32_t uStackArgIndex; + +extern int g_tcpip_thread_stat; + +/********************/ +/* global variables */ +/********************/ + +/* timer thread id */ +sys_thread_t g_timerThread_id = 0; + +/*Add an associative mapping relationship to p_stackx_instance based on lcore_id */ + +int globalArgc = 0; + +/* Set different mem args to PAL and EAL */ +char **gArgv = NULL; + +int g_dpdk_argc = 0; +char **g_dpdk_argv = NULL; + +/*The sum of the four queue processing messages does not exceed TASK_BURST*/ +static u32 g_highestMboxNum = 12; +static u32 g_mediumMboxNum = 8; +static u32 g_lowestMboxNum = 4; +static u32 g_primaryMboxNum = 8; + +/* [set ip_tos2prio size to IPTOS_TOS_MASK >> 1) + 1] */ +u8_t ip_tos2prio[(IPTOS_TOS_MASK >> 1) + 1] = { + TC_PRIO_BESTEFFORT, + ECN_OR_COST(FILLER), + TC_PRIO_BESTEFFORT, + ECN_OR_COST(BESTEFFORT), + TC_PRIO_BULK, + ECN_OR_COST(BULK), + TC_PRIO_BULK, + ECN_OR_COST(BULK), + TC_PRIO_INTERACTIVE, + ECN_OR_COST(INTERACTIVE), + TC_PRIO_INTERACTIVE, + ECN_OR_COST(INTERACTIVE), + TC_PRIO_INTERACTIVE_BULK, + ECN_OR_COST(INTERACTIVE_BULK), + TC_PRIO_INTERACTIVE_BULK, + ECN_OR_COST(INTERACTIVE_BULK) +}; + +/********************/ +/* extern functions */ +/********************/ +extern err_t ethernetif_init(struct netif *pnetif); +extern int nstack_stackx_init(int flag); +extern void tcp_sys_rmem_init(); +extern void ethernetif_packets_input(struct netif *pstnetif); + +/********************************/ +/* function forward declaration */ +/********************************/ + +static inline u32 priority_sched_mbox(struct stackx_stack *share_memory, + void **box, u32 n); +static inline char rt_tos2priority(u8_t tos) +{ + return ip_tos2prio[IPTOS_TOS(tos) >> 1]; +} + +u64 timer_get_threadid() +{ + return g_timerThread_id; +} + +#if (DPDK_MODULE != 1) +NSTACK_STATIC inline void +do_recv_task(struct disp_netif_list *dnlist, u16 index_task) +{ + struct netifExt *pnetifExt = NULL; + + while (dnlist) + { + struct netif *currentNetif = dnlist->netif; + dnlist = dnlist->next; + + pnetifExt = getNetifExt(currentNetif->num); + if (NULL == pnetifExt) + return; + + if (currentNetif != NULL && pnetifExt->num_packets_recv > index_task) + { + ethernetif_packets_input(currentNetif); + } + } +} + +static inline int is_valid_sleep_time(int sleep_time) +{ +#define TCP_IP_THREAD_MAX_SLEEP_TIME 500 + if ((sleep_time < 0) || (sleep_time > TCP_IP_THREAD_MAX_SLEEP_TIME)) + { + return 0; + } + + return 1; +} + +static int thread_init() +{ + sigset_t mask; + + if (0 != sigemptyset(&mask)) + { + NSTCP_LOGERR("sigemptyset function call error"); + return -1; + } + + if (0 != sigaddset(&mask, SIGRTMIN)) + { + NSTCP_LOGERR("sigaddset function call error"); + return -1; + } + + if ((pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0) + || (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) != 0)) + { + NSTCP_LOGERR("pthread setcancel function call error"); + return -1; + } + + if (pthread_sigmask(SIG_BLOCK, &mask, NULL) != 0) + { + NSPOL_LOGERR("pthread_sigmask function call error"); + return -1; + } + + return 0; +} + +alarm_result spl_socket_resource_check_func(void) +{ + + mring_handle conn_ring = spl_get_conn_pool(); + unsigned int rate_use = 0; + alarm_result ret_alarm; + u32 ring_size = 0, ring_not_used_count = 0; + u32 socket_num = spl_get_conn_num(); + + ring_size = nsfw_mem_ring_size(conn_ring); + + if (0 == socket_num) + { + /* assign a valid id, then return */ + ret_alarm.alarm_id_get = ALARM_EVENT_MAX; + return ret_alarm; + } + + ring_not_used_count = nsfw_mem_ring_using_count(conn_ring); + + rate_use = (ring_size - ring_not_used_count) * 100 / socket_num; + + ret_alarm.alarm_id_get = ALARM_EVENT_NSTACK_RESOURCE_ALARM; + + if (rate_use >= USEAGE_HIGHT) + { + ret_alarm.alarm_flag_get = ALARM_PRODUCT; + ret_alarm.alarm_id_get = ALARM_EVENT_NSTACK_RESOURCE_ALARM; + NSPOL_LOGWAR(TCPIP_DEBUG, + "app using too much socket resources,the rate is bigger than 80%"); + } + else if (rate_use <= USEAGE_LOW) + { + ret_alarm.alarm_flag_get = ALARM_CLEAN; + ret_alarm.alarm_id_get = ALARM_EVENT_NSTACK_RESOURCE_ALARM; + } + else + { + ret_alarm.alarm_id_get = ALARM_EVENT_MAX; + } + + ret_alarm.alarm_reason_get = ALARM_REASON_SOCKET; + + return ret_alarm; + +} + +alarm_result spl_msg_buf_resource_check_func(void) +{ + + mring_handle msg_ring = spl_get_msg_pool(); + unsigned int rate_use = 0; + alarm_result ret_alarm; + u32 ring_size = 0, ring_not_used_count = 0; + + ring_size = nsfw_mem_ring_size(msg_ring); + + if (0 == ring_size) + { + /* assign a valid id, then return */ + ret_alarm.alarm_id_get = ALARM_EVENT_MAX; + return ret_alarm; + } + + ring_not_used_count = nsfw_mem_ring_using_count(msg_ring); + + rate_use = (ring_size - ring_not_used_count) * 100 / ring_size; + + ret_alarm.alarm_id_get = ALARM_EVENT_NSTACK_RESOURCE_ALARM; + + if (rate_use >= USEAGE_HIGHT) + { + ret_alarm.alarm_flag_get = ALARM_PRODUCT; + ret_alarm.alarm_id_get = ALARM_EVENT_NSTACK_RESOURCE_ALARM; + } + else if (rate_use <= USEAGE_LOW) + { + ret_alarm.alarm_flag_get = ALARM_CLEAN; + ret_alarm.alarm_id_get = ALARM_EVENT_NSTACK_RESOURCE_ALARM; + } + else + { + ret_alarm.alarm_id_get = ALARM_EVENT_MAX; + } + + ret_alarm.alarm_reason_get = ALARM_REASON_MSG_BUF; + + return ret_alarm; + +} + +NSTACK_STATIC int tcpip_thread_init() +{ + if (thread_init() != 0) + { + return -1; + } + + if (!is_valid_sleep_time(g_tcpip_thread_sleep_time)) + { + g_tcpip_thread_sleep_time = 0; + } + + alarm_para tcp_alarm_para; + tcp_alarm_para.period_alarm.time_length = 5; /* 5 second period */ + tcp_alarm_para.alarm_reason_count = 2; /*both resource */ + tcp_alarm_para.func_alarm_check_period[0] = + spl_socket_resource_check_func; + tcp_alarm_para.alarm_reason_set[0] = ALARM_REASON_SOCKET; + tcp_alarm_para.func_alarm_check_period[1] = + spl_msg_buf_resource_check_func; + tcp_alarm_para.alarm_reason_set[1] = ALARM_REASON_MSG_BUF; + (void) ns_reg_alarm(ALARM_EVENT_NSTACK_RESOURCE_ALARM, ALARM_PERIOD_CHECK, + &tcp_alarm_para); + + ns_send_init_alarm(ALARM_EVENT_NSTACK_RESOURCE_ALARM); + + printmeminfo(); + return 0; +} + +sys_mbox_t get_primary_box() +{ + return &p_def_stack_instance->lstack.primary_mbox; +} + +NSTACK_STATIC inline u16 tcpip_netif_recv(struct disp_netif_list * nif_list) +{ + + u16 num_recv_task = 0, netif_packet_num; + + struct netif *tmpnetif = NULL; + struct netifExt *pnetifExt = NULL; + + while (nif_list) + { + tmpnetif = nif_list->netif; + + netif_packet_num = spl_hal_recv(tmpnetif, 0); + pnetifExt = getNetifExt(tmpnetif->num); + if (NULL == pnetifExt) + return 0; + + /* store the packet number in each netif */ + pnetifExt->num_packets_recv = netif_packet_num; + + /** + * num_recv_task is the maximum packets of the netif among + * all the netifs. + */ + if (num_recv_task < netif_packet_num) + { + num_recv_task = netif_packet_num; + } + + nif_list = nif_list->next; + } + + return num_recv_task; +} + +NSTACK_STATIC inline void no_task_in_one_loop() +{ +} + +#endif + +/** + * Pass a received packet to tcpip_thread for input processing + * + * @param p the received packet, p->payload pointing to the Ethernet header or + * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or + * SPL_NETIF_FLAG_ETHERNET flags) + * @param inp the network interface on which the packet was received + */ +err_t spl_tcpip_input(struct pbuf *p, struct netif *inp) +{ + err_t ret; + NSPOL_LOGINF(TCPIP_DEBUG, "PACKET]p=%p,inp=%p", (void *) p, (void *) inp); + print_pbuf_payload_info(p, false); + + /* every netif has been set NETIF_FLAG_ETHARP flag, no need else branch */ + ret = ethernet_input(p, inp); + return ret; +} + +int _do_spl_callback_msg(data_com_msg * m) +{ + NSPOL_LOGDBG(TCPIP_DEBUG, "tcpip_thread: CALLBACK]msg=%p", (void *) m); + + m->param.err = ERR_OK; + + msg_internal_callback *callback = (msg_internal_callback *) (m->buffer); + if (!callback->function) + { + NSTCP_LOGERR("function ptr is null in SPL_TCPIP_MSG_CALLBACK msg"); + ASYNC_MSG_FREE(m); + return 0; + } + + callback->function(callback->ctx); + ASYNC_MSG_FREE(m); + + return 0; +} + +/***************************************************************************** +* Prototype : get_msgbox +* Description : According to the socket tos value to determine which priority queue to send +* Input : struct stackx_stack *sharedmemory, struct netconn *conn, enum api_msg_type type +* Output : Queue pointer +* Return Value : Queue pointer +* Calls : +* Called By : +* +*****************************************************************************/ +struct queue *get_msgbox(int tos) +{ + struct stackx_stack *sharedmemory = &p_def_stack_instance->lstack; + + if ((MSG_PRIO_QUEUE_NUM < 3) || (0 == tos)) + { + return &sharedmemory->primary_mbox; + } + + char prio = rt_tos2priority((u8_t) tos); + if ((TC_PRIO_INTERACTIVE == prio)) + { + NSPOL_LOGDBG(SOCKETS_DEBUG, "sent to the highest mbox....."); + return &sharedmemory->priority_mbox[0]; + } + else if ((TC_PRIO_BESTEFFORT == prio) + || (TC_PRIO_INTERACTIVE_BULK == prio)) + { + NSPOL_LOGDBG(SOCKETS_DEBUG, "sent to the medium mbox....."); + return &sharedmemory->priority_mbox[1]; + } + else if ((TC_PRIO_BULK == prio) || (TC_PRIO_FILLER == prio)) + { + NSPOL_LOGDBG(SOCKETS_DEBUG, "sent to the lowest mbox....."); + return &sharedmemory->priority_mbox[2]; + } + + NSPOL_LOGDBG(SOCKETS_DEBUG, "sent to the primary mbox....."); + return &sharedmemory->primary_mbox; +} + +/***************************************************************************** +* Prototype : priority_sched_mbox +* Description : According to the priority from the message queue to take +* the message to deal with each cycle to take the total number of messages +* not exceed to TASK_BURST +* Input : struct stackx_stack *sharedmemory, struct netconn *conn, enum api_msg_type type +* Output : Queue pointer +* Return Value : Queue pointer +* Calls : +* Called By : +* +*****************************************************************************/ +static inline u32 +priority_sched_mbox(struct stackx_stack *share_memory, void **box, u32 n) +{ + /* high:primary:medium:low -> 3:2:2:1(total:TASK_BURST) */ + if (unlikely + ((g_highestMboxNum + g_mediumMboxNum + g_primaryMboxNum + + g_lowestMboxNum) != n)) + { + g_mediumMboxNum = n >> 2; + g_lowestMboxNum = n >> 3; + g_primaryMboxNum = n >> 2; + g_highestMboxNum = + n - g_mediumMboxNum - g_primaryMboxNum - g_lowestMboxNum; + } + + u32 highestMboxNum = g_highestMboxNum; + u32 primaryMboxNum = g_primaryMboxNum; + u32 lowestMboxNum = g_lowestMboxNum; + u32 mediumMboxNum = g_mediumMboxNum; + + u32 totalNum = 0; + u32 num = 0; + u32 oldLowestNum = 0; + + num = nsfw_mem_ring_dequeuev(share_memory->priority_mbox[0].llring, + (box + totalNum), highestMboxNum); + if (unlikely(num > highestMboxNum)) + { + num = highestMboxNum; + NSTCP_LOGERR + ("something wrong:num>highestMboxNum]num=%u,highestMboxNum=%u", + num, highestMboxNum); + } + + totalNum += num; + + u32 temp = highestMboxNum - num; + /* bisect the left number of highest */ + primaryMboxNum += (temp >> 1); + mediumMboxNum += temp - (temp >> 1); + + num = nsfw_mem_ring_dequeuev(share_memory->priority_mbox[1].llring, + (box + totalNum), mediumMboxNum); + if (unlikely(num > mediumMboxNum)) + { + num = mediumMboxNum; + NSTCP_LOGERR + ("something wrong.num>mediumMboxNum]num=%u,mediumMboxNum=%u", num, + mediumMboxNum); + } + + totalNum += num; + primaryMboxNum += mediumMboxNum - num; //occupy the left number of medium + + /* dynamically adjust g_mediumMboxNum and g_highestMboxNum, according to 'num' */ + oldLowestNum = g_mediumMboxNum; + if (0 == num) + { + g_mediumMboxNum = 1; + } + else if (num < g_mediumMboxNum) + { + g_mediumMboxNum = num; + } + else + { + g_mediumMboxNum = n >> 2; + } + + g_highestMboxNum += oldLowestNum - g_mediumMboxNum; + + num = nsfw_mem_ring_dequeuev(share_memory->primary_mbox.llring, + (box + totalNum), primaryMboxNum); + if (unlikely(num > primaryMboxNum)) + { + num = primaryMboxNum; + NSTCP_LOGERR + ("something wrong.num>primaryMboxNum]num=%u,primaryMboxNum=%u", + num, primaryMboxNum); + } + + totalNum += num; + lowestMboxNum += primaryMboxNum - num; //occupy the left number of primary + + /* dynamically adjust g_primaryMboxNum and g_highestMboxNum, according to 'num' */ + oldLowestNum = g_primaryMboxNum; + if (0 == num) + { + g_primaryMboxNum = 1; + } + else if (num < g_primaryMboxNum) + { + g_primaryMboxNum = num; + } + else + { + g_primaryMboxNum = n >> 2; + } + + g_highestMboxNum += oldLowestNum - g_primaryMboxNum; + + if (lowestMboxNum > (n - totalNum)) + { + lowestMboxNum = n - totalNum; + } + + num = nsfw_mem_ring_dequeuev(share_memory->priority_mbox[2].llring, + (box + totalNum), lowestMboxNum); + if (unlikely(num > lowestMboxNum)) + { + num = lowestMboxNum; + NSTCP_LOGERR + ("something wrong.num>lowestMboxNum]num=%u,lowestMboxNum=%u", num, + lowestMboxNum); + } + + totalNum += num; + + /* dynamically adjust g_lowestMboxNum and g_highestMboxNum, according to 'num' */ + oldLowestNum = g_lowestMboxNum; + if (0 == num) + { + g_lowestMboxNum = 1; + } + else if (num < g_lowestMboxNum) + { + g_lowestMboxNum = num; + } + else + { + g_lowestMboxNum = n >> 3; + } + + g_highestMboxNum += oldLowestNum - g_lowestMboxNum; + + return totalNum; +} + +/** + * call ltt_apimsg in STACKX TIMER THREAD + * + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return error code given back by the function that was called + */ +err_t ltt_apimsg(sys_timeout_handler h, void *arg) +{ + data_com_msg *p_msg_entry; + sys_mbox_t mbox = get_primary_box(); + if (sys_mbox_valid(&mbox)) + { + if (-1 == spl_msg_malloc(&p_msg_entry)) + { + NSPOL_LOGERR("ltt_apimsg:spl_msg_malloc failed."); + return -1; + } + + p_msg_entry->param.module_type = MSG_MODULE_TIMER; + p_msg_entry->param.major_type = SPL_TCPIP_MSG_TIMER; + p_msg_entry->param.minor_type = TIMER_MSG_TIMEOUT; + p_msg_entry->param.op_type = MSG_ASYN_POST; + + sys_sem_init(&p_msg_entry->param.op_completed); + + msg_timer *tmsg = (msg_timer *) (p_msg_entry->buffer); + tmsg->act = h; + tmsg->arg = arg; + + if (msg_post(p_msg_entry, mbox->llring) < 0) + { + NSPOL_LOGERR + ("msg post is failed]module_type=%u, major_type=%u, minor_type=%u", + p_msg_entry->param.module_type, + p_msg_entry->param.major_type, + p_msg_entry->param.minor_type); + spl_msg_free(p_msg_entry); + return ERR_VAL; + } + + return ERR_OK; + } + + NSPOL_LOGERR("mbox is invalid"); + return ERR_VAL; +} + +int _do_spl_timer_msg(data_com_msg * m) +{ + NSPOL_LOGDBG(TESTSOCKET_DEBUG | STACKX_DBG_TRACE, + "the msg is from TIMER module, minor(%u)", + m->param.minor_type); + return 0; +} + +static int _do_timeout_handle(data_com_msg * m) +{ + m->param.err = ERR_OK; + msg_timer *tmo_msg = (msg_timer *) m->buffer; + if (!tmo_msg->act) + { + NSTCP_LOGERR("TIMER_MSG_TIMEOUT msg act is NULL"); + ASYNC_MSG_FREE(m); + return -1; + } + + timeout_phandler(tmo_msg->act, tmo_msg->arg); + ASYNC_MSG_FREE(m); + return 0; +} + +static int _do_clear_timer(data_com_msg * m) +{ + NSTCP_LOGDBG("TIMER_CLEAR API]msg=%p", (void *) m); + + msg_timer *handle = (msg_timer *) (m->buffer); + if (!handle->act) + { + NSTCP_LOGERR("function ptr is null in TIMER_MSG_CLEAR msg"); + SET_MSG_ERR(m, ERR_VAL); + return 0; + } + + //stackxTcpPcbClearTimer((struct tcp_pcb *)handle->act, (unsigned long)handle->arg); + spl_msg_free(m); + + return 0; +} + +err_t ltt_clearTmrmsg(void *pcb, void *arg) +{ + data_com_msg *p_msg_entry; + sys_mbox_t mbox = get_primary_box(); + if (sys_mbox_valid(&mbox)) + { + if (-1 == spl_msg_malloc(&p_msg_entry) || (NULL == p_msg_entry)) + { + NSPOL_LOGERR("ltt_clearTmrmsg:spl_msg_malloc failed."); + return -1; + } + + p_msg_entry->param.module_type = MSG_MODULE_TIMER; + p_msg_entry->param.major_type = SPL_TCPIP_MSG_TIMER; + p_msg_entry->param.minor_type = TIMER_MSG_CLEAR; + p_msg_entry->param.op_type = MSG_ASYN_POST; + p_msg_entry->param.receiver = 0; + sys_sem_init(&p_msg_entry->param.op_completed); + + msg_timer *tmo = (msg_timer *) (p_msg_entry->buffer); + tmo->act = pcb; + tmo->arg = arg; + + if (msg_post(p_msg_entry, mbox->llring) < 0) + { + NSPOL_LOGERR + ("msg post is failed]module_type=%u, major_type=%u, minor_type=%u", + p_msg_entry->param.module_type, + p_msg_entry->param.major_type, + p_msg_entry->param.minor_type); + spl_msg_free(p_msg_entry); + return ERR_VAL; + } + + return ERR_OK; + } + + NSPOL_LOGERR("mbox is invalid"); + return ERR_VAL; +} + +#if STACKX_NETIF_API +err_t tcpip_netif_post(data_com_msg * m) +{ + err_t err = ERR_OK; + sys_mbox_t mbox = get_primary_box(); + + if (NULL == mbox || !sys_mbox_valid(&mbox)) + { + NSPOL_LOGERR("mbox not initialed well"); + err = ERR_MEM; + goto err_exit; + } + + if (NULL == mbox->llring) + { + int tryCount = 0; +#define TCP_NETIF_WAITINIT_MAX_COUNT 10 + NSPOL_LOGWAR(TCPIP_DEBUG, "mbox->llring not initialed yet..."); + sys_sleep_ns(0, 100000000); + while (!mbox->llring && (++tryCount < TCP_NETIF_WAITINIT_MAX_COUNT)) + { + NSPOL_LOGWAR(TCPIP_DEBUG, "mbox->llring not initialed yet..."); + sys_sleep_ns(0, 100000000); + } + + if (NULL == mbox->llring) + { + NSPOL_LOGERR("failed to get a valid mbox->llring"); + err = ERR_MEM; + goto err_exit; + } + } + + NSPOL_LOGINF(TCPIP_DEBUG, "post tcpip_netif_msg..."); + + if (msg_post_with_lock_rel(m, mbox->llring) < 0) + { + err = ERR_VAL; + } + else + { + err = m->param.err; + } + + err_exit: + /* it's a sync message */ + spl_msg_free(m); + return err; +} + +/** + * Much like tcpip_apimsg, but calls the lower part of a netifapi_* + * function. + * + * @param netifapimsg a struct containing the function to call and its parameters + * @return error code given back by the function that was called + */ +err_t tcpip_netif_add(msg_add_netif * tmp) +{ + data_com_msg *p_msg_entry = NULL; + msg_add_netif *nmsg = NULL; + + if (spl_msg_malloc(&p_msg_entry) == -1) + { + NSPOL_LOGERR("tcpip_netifapi:spl_msg_malloc failed."); + return ERR_MEM; + } + + p_msg_entry->param.module_type = MSG_MODULE_HAL; + p_msg_entry->param.major_type = SPL_TCPIP_MSG_NETIFAPI; + p_msg_entry->param.minor_type = NETIF_DO_ADD; + p_msg_entry->param.op_type = MSG_SYN_POST; + p_msg_entry->param.receiver = 0; + sys_sem_init(&p_msg_entry->param.op_completed); + + nmsg = (msg_add_netif *) p_msg_entry->buffer; + nmsg->function = tmp->function; + nmsg->netif = tmp->netif; + nmsg->ipaddr = tmp->ipaddr; + nmsg->netmask = tmp->netmask; + nmsg->gw = tmp->gw; + nmsg->state = tmp->state; + nmsg->init = tmp->init; + nmsg->input = tmp->input; + nmsg->voidfunc = tmp->voidfunc; + + return tcpip_netif_post(p_msg_entry); +} + +#endif /* STACKX_NETIF_API */ + +/* Added for congestion control, maybe not used end */ + +extern err_t init_ptimer(void); +extern struct cfg_item_info g_cfg_item_info[CFG_SEG_MAX][MAX_CFG_ITEM]; + +/*=========== set share config for nStackMain =============*/ +static inline mzone_handle create_mem_zone(nsfw_mem_zone * zone_info) +{ + return nsfw_mem_zone_create(zone_info); +} + +static inline int +set_zone_info(nsfw_mem_zone * zone_info, nsfw_mem_name * name_info, u32 len) +{ + if (EOK != + memcpy_s(&(zone_info->stname), sizeof(nsfw_mem_name), name_info, + sizeof(nsfw_mem_name))) + { + NSPOL_DUMP_LOGERR("create pool failed, MEMCPY_S failed."); + return -1; + } + + zone_info->lenth = len; + zone_info->isocket_id = NSFW_SOCKET_ANY; + + return 0; +} + +int set_share_config() +{ + static nsfw_mem_name g_cfg_mem_info = + { NSFW_SHMEM, NSFW_PROC_MAIN, NSTACK_SHARE_CONFIG }; + + nsfw_mem_zone zone_info; + if (set_zone_info(&zone_info, &g_cfg_mem_info, get_cfg_share_mem_size()) < + 0) + { + return -1; + } + + mzone_handle base_cfg_mem = create_mem_zone(&zone_info); + if (NULL == base_cfg_mem) + { + NSPOL_LOGERR("get config share mem failed."); + return -1; + } + + if (set_share_cfg_to_mem(base_cfg_mem) < 0) + { + NSPOL_LOGERR("set share config failed."); + return -1; + } + + return 0; +} + +int init_by_tcpip_thread() +{ + if (spl_init_app_res() != 0) + { + NSPOL_LOGERR("spl_init_app_res failed"); + return -1; + } + + if (init_instance() != 0) + { + return -1; + } + if (tcpip_thread_init() != 0) + { + NSTCP_LOGERR("tcpip_thread_init failed!"); + return -1; + } + + init_stackx_lwip(); + + return 0; +} + +void spl_tcpip_thread(void *arg) +{ + g_tcpip_thread_stat = 1; + + if (init_by_tcpip_thread() != 0) + { + return; + } + + struct stackx_stack *share_memory = &p_def_stack_instance->lstack; + struct disp_netif_list **iflist = &p_def_stack_instance->netif_list; + + u32 run_count = 0; + u16 task_loop; + u16 num_recv_task = 0, num_send_timer_task = 0; + u16 index_task = 0; + //int tcpip_thread_sleep_interval = g_tcpip_thread_sleep_time * 1000; + void *task_queue[TASK_BURST]; + data_com_msg *msg; + + while (1) + { + /* try to receive packet from hal layer */ + num_recv_task = tcpip_netif_recv(*iflist); + + /* try to receive message from sbr layer */ + num_send_timer_task = priority_sched_mbox(share_memory, + task_queue, TASK_BURST); + + if (num_recv_task) + { + NSPOL_LOGINF(TCPIP_DEBUG, "num_recv_task %d", num_recv_task); + } + + /* Statistics the total number of messages */ + + /* Separate statistics on socket api messages */ + /* handle the request from upper layer and lower layer one by one */ + task_loop = (num_send_timer_task > num_recv_task ? + num_send_timer_task : num_recv_task); + if (task_loop == 0) + { + no_task_in_one_loop(); + + if (run_count++ > 20) + { + //sys_sleep_ns (0, tcpip_thread_sleep_interval); + } + continue; + } + + run_count = 0; + index_task = 0; + + /* at least one task to be handled */ + while (task_loop > index_task) + { + /* handle one packet from hal layer (for multi-nic case, do it for each) */ + if (num_recv_task > index_task) + { + do_recv_task(*iflist, index_task); + } + + /* handle one message from sbr layer */ + if (num_send_timer_task > index_task) + { + msg = (data_com_msg *) (task_queue[index_task]); + + spl_process(msg); + } + + do_update_pcbstate(); + + index_task++; + } + } +} + +int create_tcpip_thread() +{ + int ret; + u64 arg = 0; + + /* main tcpip thread */ + char thread_name[32] = TCPIP_THREAD_NAME; + + sys_thread_t thread = sys_thread_new(thread_name, spl_tcpip_thread, + (void *) arg, + TCPIP_THREAD_STACKSIZE, + g_cfg_item_info[CFG_SEG_PRI] + [CFG_ITEM_THREAD_PRI_PRI].value); + + cpu_set_t cpuset; + CPU_ZERO(&cpuset); /*lint !e534 */ + CPU_SET(g_nstack_bind_cpu, &cpuset); /*lint !e522 */ + ret = pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset); + if (ret != 0) + { + NSPOL_LOGERR("pthread_setaffinity_np failed]thread_name=%s,ret=%d", + TCPIP_THREAD_NAME, ret); + } + + return 0; +} + +int create_timer_thread() +{ +#if 1 + if (init_ptimer() != ERR_OK) + { + NSPOL_LOGERR("init_ptimer failed"); + return -1; + } + + sys_thread_t thread_timer = + sys_thread_new(PTIMER_THREAD_NAME, ptimer_thread, NULL, + TCPIP_THREAD_STACKSIZE, 0); + cpu_set_t cpuset_timer; + CPU_ZERO(&cpuset_timer); + CPU_SET(1, &cpuset_timer); + int ret = pthread_setaffinity_np(thread_timer, sizeof(cpuset_timer), + &cpuset_timer); + if (ret != 0) + { + NSPOL_LOGERR("TCP init Timer Trhead Failed!"); + } + + g_timerThread_id = thread_timer; +#endif + return 0; +} + +int init_ip_module_reader() +{ + output_api api = { 0 }; + api.post_to = post_ip_module_msg; + api.add_netif_ip = add_netif_ip; + api.del_netif_ip = del_netif_ip; + regist_output_api(&api); + + if (init_configuration_reader() < 0) + { + NSPOL_LOGERR("init_configuration_reader failed"); + return -1; + } + + return 0; +} + +extern int init_unmatch_version(void); +extern int init_stackx_global_tick(void); + +int init_by_main_thread() +{ + NSPOL_LOGINF(TCPIP_DEBUG, "init_by_main_thread start version 1.4"); + + uStackArgIndex++; + if (spl_hal_init(g_dpdk_argc, (char **) g_dpdk_argv) < 0) + { + NSPOL_LOGERR("spl_hal_init failed"); + return -1; + } + NSPOL_LOGINF(TCPIP_DEBUG, "stage 1"); + + if (init_unmatch_version() != 0) + { + return -1; + } + + NSPOL_LOGINF(TCPIP_DEBUG, "stage 2"); + if (init_stackx_global_tick() != 0) + { + return -1; + } + NSPOL_LOGINF(TCPIP_DEBUG, "stage 3"); + + if (spl_init_group_array() != 0) + { + NSPOL_LOGERR("spl_init_group_array failed"); + return -1; + } + NSPOL_LOGINF(TCPIP_DEBUG, "stage 4"); + + if (nstack_epoll_init(0, 0) != 0) + { + NSPOL_LOGERR("nstack_epoll_init failed"); + return -1; + } + + if (set_share_config() != 0) + { + NSPOL_LOGERR("set_share_config failed."); + return -1; + } + NSPOL_LOGINF(TCPIP_DEBUG, "stage 5"); + + if (create_timer_thread() != 0) + { + //NSPOL_LOGERR(TCPIP_DEBUG,"init_timer_thread failed."); + return -1; + } + NSPOL_LOGINF(TCPIP_DEBUG, "stage 6"); + + if (create_tcpip_thread() != 0) + { + NSPOL_LOGERR("init_tcpip_thread failed."); + return -1; + } + NSPOL_LOGINF(TCPIP_DEBUG, "stage 7"); + + if (init_ip_module_reader() != 0) + { + return -1; + } + NSPOL_LOGINF(TCPIP_DEBUG, "stage end"); + + return 0; +} + +void create_netif(struct stackx_port_info *p_port_info) +{ + int ret; + struct spl_ip_addr ip, mask, gw; + struct netifExt *netifEx = NULL; + struct netif *netif = malloc(sizeof(struct netif)); + if (!netif) + { + NSPOL_LOGERR("malloc failed"); + return; + } + + if (memset_s(netif, sizeof(struct netif), 0, sizeof(struct netif)) < 0) + { + NSPOL_LOGERR("MEMSET_S failed"); + goto error; + } + + NSPOL_LOGINF(TCPIP_DEBUG, "I get netif]ip=%s,gw=%s,mask=%s,name=%c %c", + p_port_info->linux_ip.ip_addr_linux, + p_port_info->linux_ip.ip_addr_linux, + p_port_info->linux_ip.mask_linux, + netif->name[0], netif->name[1]); + + if (inet_aton(p_port_info->linux_ip.ip_addr_linux, &ip) + && inet_aton(p_port_info->linux_ip.ip_addr_linux, &gw) + && inet_aton(p_port_info->linux_ip.mask_linux, &mask)) + { + ret = + spl_netifapi_netif_add(netif, &ip, &mask, &gw, NULL, + ethernetif_init, spl_tcpip_input, + netif_set_up); + if (ERR_OK != ret) + { + NSPOL_LOGERR("netifapi_netif_add failed]ret=%d", ret); + goto error; + } +#if 1 + if (0 != netifExt_add(netif)) + return; + +#endif + netifEx = getNetifExt(netif->num); + if (NULL == netifEx) + return; + + netifEx->hdl = p_port_info->linux_ip.hdl; + ret = + strcpy_s(netifEx->if_name, sizeof(netifEx->if_name), + p_port_info->linux_ip.if_name); + if (EOK != ret) + { + NSPOL_LOGERR("STRCPY_S failed]ret=%d", ret); + goto error; + } + return; + } + + error: + free(netif); +} + +int +post_ip_module_msg(void *arg, ip_module_type Type, + ip_module_operate_type operate_type) +{ + data_com_msg *p_msg_entry; + msg_ip_module *imsg; + sys_mbox_t mbox = get_primary_box(); + + if (!mbox) + { + NSOPR_LOGERR("get_cur_mbox failed"); + return ERR_MEM; + } + + if (sys_mbox_valid(&mbox)) + { + if (spl_msg_malloc(&p_msg_entry) == -1) + { + NSOPR_LOGERR("ip_route_apimsg:spl_msg_malloc failed."); + return ERR_MEM; + } + + sys_sem_init(&p_msg_entry->param.op_completed); + p_msg_entry->param.module_type = MSG_MODULE_IP; + p_msg_entry->param.op_type = MSG_SYN_POST; + + imsg = (msg_ip_module *) (p_msg_entry->buffer); + imsg->arg = arg; + imsg->type = Type; + imsg->operate_type = operate_type; + + NSOPR_LOGINF("post ip_module msg to tcpip_thread]action=%d,type=%d", + operate_type, Type); + + if (msg_post(p_msg_entry, mbox->llring) != 0) + { + NSOPR_LOGERR + ("msg_post failed,this can not happen]action=%d,type=%d", + operate_type, Type); + } + + spl_msg_free(p_msg_entry); + + return ERR_OK; + } + + NSOPR_LOGERR("mbox is invalid"); + return ERR_VAL; +} + +int +process_ip_module_msg(void *arg, ip_module_type module_type, + ip_module_operate_type operate_type) +{ + int retval = process_configuration(arg, module_type, operate_type); + + NSOPR_LOGINF("tcpip_thread: ip_module cmd exec over, send SYNC_MSG_ACK"); + return retval; +} + +int init_new_network_configuration() +{ + if (spl_hal_port_init() < 0) + { + return -1; + } + + return 0; +} + +static int _process_ip_module_msg(data_com_msg * m) +{ + m->param.err = ERR_OK; + msg_ip_module *_m = (msg_ip_module *) m->buffer; + int ret = process_ip_module_msg(_m->arg, _m->type, _m->operate_type); + SYNC_MSG_ACK(m); + return ret; +} + +int +spl_post_msg(u16 mod, u16 maj, u16 min, u16 op, char *data, u16 data_len, + u32 src_pid) +{ + data_com_msg *p_msg_entry; + + sys_mbox_t mbox = get_primary_box(); + if (!sys_mbox_valid(&mbox)) + { + NSPOL_LOGERR + ("get mbox null!]mod=%u,maj=%u,min=%u,op=%u,data=%p,len=%u", mod, + maj, min, op, data, data_len); + return ERR_MEM; + } + + if (spl_msg_malloc(&p_msg_entry) == -1) + { + NSPOL_LOGERR + ("get msg null!]mod=%u,maj=%u,min=%u,op=%u,data=%p,len=%u", mod, + maj, min, op, data, data_len); + return ERR_MEM; + } + + sys_sem_init(&p_msg_entry->param.op_completed); + p_msg_entry->param.module_type = mod; + p_msg_entry->param.major_type = maj; + p_msg_entry->param.minor_type = min; + p_msg_entry->param.op_type = op; + p_msg_entry->param.src_pid = src_pid; + + int retVal; + if (NULL != data) + { + retVal = + memcpy_s((char *) p_msg_entry->buffer, + sizeof(p_msg_entry->buffer), data, data_len); + if (EOK != retVal) + { + NSPOL_LOGERR("MEMCPY_S failed %d.", retVal); + spl_msg_free(p_msg_entry); + return ERR_MEM; + } + } + + if (msg_post_with_lock_rel(p_msg_entry, mbox->llring) != 0) + { + NSPOL_LOGERR + ("post msg error!]mod=%u,maj=%u,min=%u,op=%u,data=%p,len=%u", mod, + maj, min, op, data, data_len); + spl_msg_free(p_msg_entry); + return ERR_MEM; + } + + if (MSG_SYN_POST == op) + { + spl_msg_free(p_msg_entry); + } + + NSOPR_LOGDBG("post msg suc!]mod=%u,maj=%u,min=%u,op=%u,data=%p,len=%u", + mod, maj, min, op, data, data_len); + return ERR_OK; +} + +/* +* Added by eliminate duplicated code degree, the function is moved to the public places +*adjust memory size for pal and eal mem size: this func do the following things: +*1. copy argv to gArgv and g_dpdk_argv +*2. remove OPT_EAL_MEM_SIZE option so that the rtp and rte options process won't reprt unrecognized option error. +*3. set eal mem size and pal_mem_size = mem - eal_mem_size +*/ +int adjust_mem_arg(int argc, char *argv[]) +{ + int i = 0; + int j = 0; + int retVal; + char *tmp = NULL; + char *tmp2 = NULL; + int arg_mem_index = -1; + char *saveptr1 = NULL; + int mem_size = 0; + int mem_size_parsed = 0; // if multi -m argument is set, then only deal with the first one + int eal_mem_size = DPDK_DEFAULT_EAL_MEM_SIZE; // Default + + if ((argc < NSTACK_MAIN_MIN_PARA) || (argc > NSTACK_MAIN_MAX_PARA)) + { + NSPOL_LOGERR("The number of parameters is incorrect"); + return -1; + } + + globalArgc = argc; + g_dpdk_argc = argc; + gArgv = (char **) malloc(sizeof(char *) * argc); + if (gArgv == NULL) + { + NSPOL_LOGERR("Failed to alloc memory for adjust mem args\n"); + goto ERROR_INIT; + } + + g_dpdk_argv = (char **) malloc(sizeof(char *) * argc); + if (g_dpdk_argv == NULL) + { + NSPOL_LOGERR("Failed to alloc memory for adjust mem args\n"); + goto ERROR_INIT; + } + + retVal = memset_s(gArgv, sizeof(char *) * argc, 0, sizeof(char *) * argc); + if (EOK != retVal) + { + NSPOL_LOGERR("MEMSET_S failed %d.", retVal); + goto ERROR_INIT; + } + retVal = + memset_s(g_dpdk_argv, sizeof(char *) * argc, 0, + sizeof(char *) * argc); + if (EOK != retVal) + { + NSPOL_LOGERR("MEMSET_S failed %d.", retVal); + goto ERROR_INIT; + } + + for (i = 0; i < argc; i++) + { + if (!strcmp("-m", argv[i]) && !mem_size_parsed && (i + 1 < argc)) + { + gArgv[j] = argv[i]; + g_dpdk_argv[j] = argv[i]; + i++; + j++; + gArgv[j] = (char *) malloc(32); + g_dpdk_argv[j] = (char *) malloc(32); + /* gArgv[j] is NULL and g_dpdk_argv[j] isnot NULL, need free g_dpdk_argv[j] */ + arg_mem_index = j; + if ((!gArgv[j]) || (!g_dpdk_argv[j])) + { + NSPOL_LOGERR("malloc failed."); + goto ERROR_PARSE_MALLOC; + } + mem_size = atoi(argv[i]); + /* add memory range check,avoid handle wrongly later begin */ + if (mem_size < 0) + { + goto ERROR_PARSE_MALLOC; + } + + j++; + mem_size_parsed = 1; + } + else if (!strncmp + (OPT_EAL_MEM_SIZE, argv[i], strlen(OPT_EAL_MEM_SIZE))) + { + tmp = strdup(argv[i]); + if (tmp == NULL) + { + goto ERROR_PARSE_MALLOC; + } + /* Always use re-entrant functions in multi-threaded environments */ + tmp2 = strtok_r(tmp, "=", &saveptr1); + tmp2 = strtok_r(NULL, "=", &saveptr1); + if (tmp2) + { + eal_mem_size = atoi(tmp2); + /* add memory range check,avoid handle wrongly later */ + if (eal_mem_size < 0) + { + free(tmp); + goto ERROR_PARSE_MALLOC; + } + } + free(tmp); + tmp = NULL; + /*remove this option since dpdk can't recognize it and may cause error. */ + /*so we should deduct the count by 1. */ + globalArgc -= 1; + g_dpdk_argc -= 1; + } + else + { + gArgv[j] = argv[i]; + g_dpdk_argv[j] = argv[i]; + j++; + } + } + + /* -m arg is set */ + if (arg_mem_index >= 0) + { + retVal = + sprintf_s(gArgv[arg_mem_index], 32, "%d", + mem_size - eal_mem_size); + if (-1 == retVal) + { + NSPOL_LOGERR("SPRINTF_S failed]ret=%d", retVal); + goto ERROR_PARSE_MALLOC; + } + retVal = + sprintf_s(g_dpdk_argv[arg_mem_index], 32, "%d", eal_mem_size); + if (-1 == retVal) + { + NSPOL_LOGERR("SPRINTF_S failed]ret=%d", retVal); + goto ERROR_PARSE_MALLOC; + } + } + else + { + // do nothing for no mem arg and leave it for default process of pal and eal. + } + + return 0; + ERROR_PARSE_MALLOC: + if (arg_mem_index >= 0 && gArgv[arg_mem_index]) + { + free(gArgv[arg_mem_index]); + gArgv[arg_mem_index] = NULL; + } + + if (arg_mem_index >= 0 && g_dpdk_argv[arg_mem_index]) + { + free(g_dpdk_argv[arg_mem_index]); + g_dpdk_argv[arg_mem_index] = NULL; + } + + ERROR_INIT: + if (gArgv) + { + free(gArgv); + gArgv = NULL; + globalArgc = 0; + } + + if (g_dpdk_argv) + { + free(g_dpdk_argv); + g_dpdk_argv = NULL; + g_dpdk_argc = 0; + } + + return -1; +} + +REGIST_MSG_MODULE_FUN(MSG_MODULE_IP, _process_ip_module_msg); + +REGIST_MSG_MODULE_MAJOR_FUN(MSG_MODULE_SPL, SPL_TCPIP_MSG_CALLBACK, + _do_spl_callback_msg); + +REGIST_MSG_MODULE_MAJOR_FUN(MSG_MODULE_TIMER, SPL_TCPIP_MSG_TIMER, + _do_spl_timer_msg); + +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_TIMER, SPL_TCPIP_MSG_TIMER, + TIMER_MSG_TIMEOUT, _do_timeout_handle); + +REGIST_MSG_MODULE_MAJOR_MINOR_FUN(MSG_MODULE_TIMER, SPL_TCPIP_MSG_TIMER, + TIMER_MSG_CLEAR, _do_clear_timer); -- cgit 1.2.3-korg