diff options
Diffstat (limited to 'stacks/lwip_stack/lwip_src/api')
-rw-r--r-- | stacks/lwip_stack/lwip_src/api/spl_api.c | 51 | ||||
-rw-r--r-- | stacks/lwip_stack/lwip_src/api/spl_api_msg.c | 3259 | ||||
-rw-r--r-- | stacks/lwip_stack/lwip_src/api/spl_netbuf.c | 58 | ||||
-rw-r--r-- | stacks/lwip_stack/lwip_src/api/spl_netifapi.c | 288 | ||||
-rw-r--r-- | stacks/lwip_stack/lwip_src/api/spl_sbr.c | 495 | ||||
-rw-r--r-- | stacks/lwip_stack/lwip_src/api/spl_tcpip.c | 1548 |
6 files changed, 5699 insertions, 0 deletions
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..5c8af7d --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/spl_api.c @@ -0,0 +1,51 @@ +/* +* +* 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.h" +//#include "sockets.h" +//#include <netinet/in.h> + +#include "stackx_spl_share.h" +#include "stackx/spl_api.h" +//#include "stackx/ip.h" +#include "sharedmemory.h" +#include "spl_hal.h" +#include "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 (NSTACK_DMM_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..9ba1e92 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/spl_api_msg.c @@ -0,0 +1,3259 @@ +/* +* +* 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 <netinet/in.h> +#include <errno.h> + +#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 + +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_event_callback (ADDR_SHTOL (conn->epInfo), EPOLLIN); + } + break; + case SPL_NETCONN_EVT_RCVMINUS: // This will never be reached + __sync_fetch_and_sub (&conn->rcvevent, 1); + if ((conn->epoll_flag) && (postFlag)) + { + nstack_event_callback (ADDR_SHTOL (conn->epInfo), EPOLLIN); + } + break; + case SPL_NETCONN_EVT_SENDPLUS: + conn->sendevent = 1; + if ((conn->epoll_flag) && (postFlag)) + { + nstack_event_callback (ADDR_SHTOL (conn->epInfo), EPOLLOUT); + } + break; + case SPL_NETCONN_EVT_SENDMINUS: + conn->sendevent = 0; + + if ((conn->epoll_flag) && (postFlag)) + { + nstack_event_callback (ADDR_SHTOL (conn->epInfo), EPOLLOUT); + } + break; + case SPL_NETCONN_EVT_ERROR: + conn->errevent |= EPOLLERR; + if ((conn->epoll_flag) && (postFlag)) + { + nstack_event_callback (ADDR_SHTOL (conn->epInfo), conn->errevent); + conn->errevent = 0; + } + break; +#if 1 + case SPL_NETCONN_EVT_ACCEPT: + __sync_fetch_and_add (&conn->rcvevent, 1); + if ((conn->epoll_flag) && (postFlag)) + { + nstack_event_callback (ADDR_SHTOL (conn->epInfo), EPOLLIN); + } + break; + + case SPL_NETCONN_EVT_HUP: + conn->errevent |= EPOLLHUP; + if ((conn->epoll_flag) && (postFlag)) + { + nstack_event_callback (ADDR_SHTOL (conn->epInfo), conn->errevent); + conn->errevent = 0; + } + break; + case SPL_NETCONN_EVT_RDHUP: + conn->errevent |= EPOLLRDHUP; + if ((conn->epoll_flag) && (postFlag)) + { + nstack_event_callback (ADDR_SHTOL (conn->epInfo), conn->errevent); + 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 *spb = 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); + + buf = (struct spl_netbuf *) ((char *) p + sizeof (struct spl_pbuf)); + buf->p = spb; + spl_ip_addr_set (&buf->addr, ipaddr); + buf->port = port; + + err_t ret = sp_enqueue (cpcb, (void *) p); + 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); + + 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 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); + spl_pbuf_free (p); + 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_ip_addr_t *destIP = &smsg->addr; + + //@TODO udp send need to update like TCP. copy pbuf here. Once testing done for TCP we'll update it here. + if (ip_addr_isany (&smsg->addr)) + { + //SET_MSG_ERR(m, udp_send(upcb, p)); + /* destIP.addr == IPADDR_ANY means it is from stackx_send + and the destination is stored in remote_ip and remote port */ + //destIP = &upcb->remote_ip; + } + else + { + //SET_MSG_ERR(m, udp_sendto(upcb, p, &smsg->addr, smsg->port)); + } + break; + } + + default: + SET_MSG_ERR (m, ERR_CONN); + break; + } + + 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; + + 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; + } + 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; + 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..9c682fc --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/spl_netbuf.c @@ -0,0 +1,58 @@ +/* +* +* 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 <adam@sics.se> + * + */ +//#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..ab1446a --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/spl_netifapi.c @@ -0,0 +1,288 @@ +/* +* +* 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 <sys/socket.h> +//#include <netinet/in.h> + +#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 <inet.h> + +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..4c510a5 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/spl_sbr.c @@ -0,0 +1,495 @@ +/* +* +* 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, STACKX, "NSPOL", 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, STACKX, "NSPOL", 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, STACKX, "NSPOL", 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..688c34b --- /dev/null +++ b/stacks/lwip_stack/lwip_src/api/spl_tcpip.c @@ -0,0 +1,1548 @@ +/* +* +* 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 <pthread.h> +#include <sched.h> +#include <signal.h> +#include "memp.h" +#include "mem.h" +#include "spl_pbuf.h" +//#include "sockets.h" +//#include <netinet/in.h> + +#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 19 +#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); + +/* 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 int nstack_rd_mng_int (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->length = 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_SEG_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 (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); |