|  | /** | 
|  | * Copyright (c) 2017 IpTronix | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #define LOG_MODULE_NAME wifi_winc1500 | 
|  | #define LOG_LEVEL CONFIG_WIFI_LOG_LEVEL | 
|  |  | 
|  | #include <zephyr/logging/log.h> | 
|  | LOG_MODULE_REGISTER(LOG_MODULE_NAME); | 
|  |  | 
|  | #include <zephyr/kernel.h> | 
|  | #include <zephyr/debug/stack.h> | 
|  | #include <zephyr/device.h> | 
|  | #include <string.h> | 
|  | #include <errno.h> | 
|  | #include <zephyr/net/net_pkt.h> | 
|  | #include <zephyr/net/net_if.h> | 
|  | #include <zephyr/net/net_l2.h> | 
|  | #include <zephyr/net/net_context.h> | 
|  | #include <zephyr/net/net_offload.h> | 
|  | #include <zephyr/net/wifi_mgmt.h> | 
|  | #include <zephyr/net/conn_mgr/connectivity_wifi_mgmt.h> | 
|  |  | 
|  | #include <zephyr/sys/printk.h> | 
|  |  | 
|  | /* We do not need <socket/include/socket.h> | 
|  | * It seems there is a bug in ASF side: if OS is already defining sockaddr | 
|  | * and all, ASF will not need to define it. Unfortunately its socket.h does | 
|  | * but also defines some NM API functions there (??), so we need to redefine | 
|  | * those here. | 
|  | */ | 
|  | #define __SOCKET_H__ | 
|  | #define HOSTNAME_MAX_SIZE	(64) | 
|  |  | 
|  | #include <driver/include/m2m_wifi.h> | 
|  | #include <socket/include/m2m_socket_host_if.h> | 
|  |  | 
|  | NMI_API void socketInit(void); | 
|  | typedef void (*tpfAppSocketCb) (SOCKET sock, uint8 u8Msg, void *pvMsg); | 
|  | typedef void (*tpfAppResolveCb) (uint8 *pu8DomainName, uint32 u32ServerIP); | 
|  | NMI_API void registerSocketCallback(tpfAppSocketCb socket_cb, | 
|  | tpfAppResolveCb resolve_cb); | 
|  | NMI_API SOCKET winc1500_socket(uint16 u16Domain, uint8 u8Type, uint8 u8Flags); | 
|  | NMI_API sint8 winc1500_socket_bind(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen); | 
|  | NMI_API sint8 winc1500_socket_listen(SOCKET sock, uint8 backlog); | 
|  | NMI_API sint8 winc1500_socket_accept(SOCKET sock, struct sockaddr *addr, uint8 *addrlen); | 
|  | NMI_API sint8 winc1500_socket_connect(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen); | 
|  | NMI_API sint16 winc1500_socket_recv(SOCKET sock, void *pvRecvBuf, | 
|  | uint16 u16BufLen, uint32 u32Timeoutmsec); | 
|  | NMI_API sint16 winc1500_socket_send(SOCKET sock, void *pvSendBuffer, | 
|  | uint16 u16SendLength, uint16 u16Flags); | 
|  | NMI_API sint16 winc1500_socket_sendto(SOCKET sock, void *pvSendBuffer, | 
|  | uint16 u16SendLength, uint16 flags, | 
|  | struct sockaddr *pstrDestAddr, uint8 u8AddrLen); | 
|  | NMI_API sint8 winc1500_close(SOCKET sock); | 
|  |  | 
|  | enum socket_errors { | 
|  | SOCK_ERR_NO_ERROR = 0, | 
|  | SOCK_ERR_INVALID_ADDRESS = -1, | 
|  | SOCK_ERR_ADDR_ALREADY_IN_USE = -2, | 
|  | SOCK_ERR_MAX_TCP_SOCK = -3, | 
|  | SOCK_ERR_MAX_UDP_SOCK = -4, | 
|  | SOCK_ERR_INVALID_ARG = -6, | 
|  | SOCK_ERR_MAX_LISTEN_SOCK = -7, | 
|  | SOCK_ERR_INVALID = -9, | 
|  | SOCK_ERR_ADDR_IS_REQUIRED = -11, | 
|  | SOCK_ERR_CONN_ABORTED = -12, | 
|  | SOCK_ERR_TIMEOUT = -13, | 
|  | SOCK_ERR_BUFFER_FULL = -14, | 
|  | }; | 
|  |  | 
|  | enum socket_messages { | 
|  | SOCKET_MSG_BIND	= 1, | 
|  | SOCKET_MSG_LISTEN, | 
|  | SOCKET_MSG_DNS_RESOLVE, | 
|  | SOCKET_MSG_ACCEPT, | 
|  | SOCKET_MSG_CONNECT, | 
|  | SOCKET_MSG_RECV, | 
|  | SOCKET_MSG_SEND, | 
|  | SOCKET_MSG_SENDTO, | 
|  | SOCKET_MSG_RECVFROM, | 
|  | }; | 
|  |  | 
|  | typedef struct { | 
|  | sint8	status; | 
|  | } tstrSocketBindMsg; | 
|  |  | 
|  | typedef struct { | 
|  | sint8	status; | 
|  | } tstrSocketListenMsg; | 
|  |  | 
|  | typedef struct { | 
|  | SOCKET			sock; | 
|  | struct sockaddr_in	strAddr; | 
|  | } tstrSocketAcceptMsg; | 
|  |  | 
|  | typedef struct { | 
|  | SOCKET	sock; | 
|  | sint8	s8Error; | 
|  | } tstrSocketConnectMsg; | 
|  |  | 
|  | typedef struct { | 
|  | uint8			*pu8Buffer; | 
|  | sint16			s16BufferSize; | 
|  | uint16			u16RemainingSize; | 
|  | struct sockaddr_in	strRemoteAddr; | 
|  | } tstrSocketRecvMsg; | 
|  |  | 
|  | #include <driver/include/m2m_wifi.h> | 
|  | #include <socket/include/m2m_socket_host_if.h> | 
|  |  | 
|  | #if defined(CONFIG_WIFI_WINC1500_REGION_NORTH_AMERICA) | 
|  | #define WINC1500_REGION		NORTH_AMERICA | 
|  | #elif defined(CONFIG_WIFI_WINC1500_REGION_EUROPE) | 
|  | #define WINC1500_REGION		EUROPE | 
|  | #elif defined(CONFIG_WIFI_WINC1500_REGION_ASIA) | 
|  | #define WINC1500_REGION		ASIA | 
|  | #endif | 
|  |  | 
|  | #define WINC1500_BIND_TIMEOUT K_MSEC(500) | 
|  | #define WINC1500_LISTEN_TIMEOUT K_MSEC(500) | 
|  | #define WINC1500_BUF_TIMEOUT K_MSEC(100) | 
|  |  | 
|  | NET_BUF_POOL_DEFINE(winc1500_tx_pool, CONFIG_WIFI_WINC1500_BUF_CTR, | 
|  | CONFIG_WIFI_WINC1500_MAX_PACKET_SIZE, 0, NULL); | 
|  | NET_BUF_POOL_DEFINE(winc1500_rx_pool, CONFIG_WIFI_WINC1500_BUF_CTR, | 
|  | CONFIG_WIFI_WINC1500_MAX_PACKET_SIZE, 0, NULL); | 
|  |  | 
|  | K_KERNEL_STACK_MEMBER(winc1500_stack, CONFIG_WIFI_WINC1500_THREAD_STACK_SIZE); | 
|  | struct k_thread winc1500_thread_data; | 
|  |  | 
|  | struct socket_data { | 
|  | struct net_context		*context; | 
|  | net_context_connect_cb_t	connect_cb; | 
|  | net_tcp_accept_cb_t		accept_cb; | 
|  | net_context_recv_cb_t		recv_cb; | 
|  | void				*connect_user_data; | 
|  | void				*recv_user_data; | 
|  | void				*accept_user_data; | 
|  | struct net_pkt			*rx_pkt; | 
|  | struct net_buf			*pkt_buf; | 
|  | int				ret_code; | 
|  | struct k_sem			wait_sem; | 
|  | }; | 
|  |  | 
|  | struct winc1500_data { | 
|  | struct socket_data socket_data[ | 
|  | CONFIG_WIFI_WINC1500_OFFLOAD_MAX_SOCKETS]; | 
|  | struct net_if *iface; | 
|  | unsigned char mac[6]; | 
|  | scan_result_cb_t scan_cb; | 
|  | uint8_t scan_result; | 
|  | bool connecting; | 
|  | bool connected; | 
|  | }; | 
|  |  | 
|  | static struct winc1500_data w1500_data; | 
|  |  | 
|  | #if LOG_LEVEL > LOG_LEVEL_OFF | 
|  | static void stack_stats(void) | 
|  | { | 
|  | log_stack_usage(&winc1500_thread_data); | 
|  | } | 
|  | #endif /* LOG_LEVEL > LOG_LEVEL_OFF */ | 
|  |  | 
|  | static char *socket_error_string(int8_t err) | 
|  | { | 
|  | switch (err) { | 
|  | case SOCK_ERR_NO_ERROR: | 
|  | return "Successful socket operation"; | 
|  | case SOCK_ERR_INVALID_ADDRESS: | 
|  | return "Socket address is invalid." | 
|  | "The socket operation cannot be completed successfully" | 
|  | " without specifying a specific address. " | 
|  | "For example: bind is called without specifying" | 
|  | " a port number"; | 
|  | case SOCK_ERR_ADDR_ALREADY_IN_USE: | 
|  | return "Socket operation cannot bind on the given address." | 
|  | " With socket operations, only one IP address per " | 
|  | "socket is permitted. Any attempt for a new socket " | 
|  | "to bind with an IP address already bound to another " | 
|  | "open socket, will return the following error code. " | 
|  | "States that bind operation failed."; | 
|  | case SOCK_ERR_MAX_TCP_SOCK: | 
|  | return "Exceeded the maximum number of TCP sockets." | 
|  | "A maximum number of TCP sockets opened simultaneously" | 
|  | " is defined through TCP_SOCK_MAX. It is not permitted" | 
|  | " to exceed that number at socket creation." | 
|  | " Identifies that @ref socket operation failed."; | 
|  | case SOCK_ERR_MAX_UDP_SOCK: | 
|  | return "Exceeded the maximum number of UDP sockets." | 
|  | "A maximum number of UDP sockets opened simultaneously" | 
|  | " is defined through UDP_SOCK_MAX. It is not permitted" | 
|  | " to exceed that number at socket creation." | 
|  | " Identifies that socket operation failed"; | 
|  | case SOCK_ERR_INVALID_ARG: | 
|  | return "An invalid argument is passed to a function."; | 
|  | case SOCK_ERR_MAX_LISTEN_SOCK: | 
|  | return "Exceeded the maximum number of TCP passive listening " | 
|  | "sockets. Identifies Identifies that listen operation" | 
|  | " failed."; | 
|  | case SOCK_ERR_INVALID: | 
|  | return "The requested socket operation is not valid in the " | 
|  | "current socket state. For example: @ref accept is " | 
|  | "called on a TCP socket before bind or listen."; | 
|  | case SOCK_ERR_ADDR_IS_REQUIRED: | 
|  | return "Destination address is required. Failure to provide " | 
|  | "the socket address required for the socket operation " | 
|  | "to be completed. It is generated as an error to the " | 
|  | "sendto function when the address required to send the" | 
|  | " data to is not known."; | 
|  | case SOCK_ERR_CONN_ABORTED: | 
|  | return "The socket is closed by the peer. The local socket is " | 
|  | "also closed."; | 
|  | case SOCK_ERR_TIMEOUT: | 
|  | return "The socket pending operation has  timedout."; | 
|  | case SOCK_ERR_BUFFER_FULL: | 
|  | return "No buffer space available to be used for the requested" | 
|  | " socket operation."; | 
|  | default: | 
|  | return "Unknown"; | 
|  | } | 
|  | } | 
|  |  | 
|  | static char *wifi_cb_msg_2_str(uint8_t message_type) | 
|  | { | 
|  | switch (message_type) { | 
|  | case M2M_WIFI_RESP_CURRENT_RSSI: | 
|  | return "M2M_WIFI_RESP_CURRENT_RSSI"; | 
|  | case M2M_WIFI_REQ_WPS: | 
|  | return "M2M_WIFI_REQ_WPS"; | 
|  | case M2M_WIFI_RESP_IP_CONFIGURED: | 
|  | return "M2M_WIFI_RESP_IP_CONFIGURED"; | 
|  | case M2M_WIFI_RESP_IP_CONFLICT: | 
|  | return "M2M_WIFI_RESP_IP_CONFLICT"; | 
|  | case M2M_WIFI_RESP_CLIENT_INFO: | 
|  | return "M2M_WIFI_RESP_CLIENT_INFO"; | 
|  |  | 
|  | case M2M_WIFI_RESP_GET_SYS_TIME: | 
|  | return "M2M_WIFI_RESP_GET_SYS_TIME"; | 
|  | case M2M_WIFI_REQ_SEND_ETHERNET_PACKET: | 
|  | return "M2M_WIFI_REQ_SEND_ETHERNET_PACKET"; | 
|  | case M2M_WIFI_RESP_ETHERNET_RX_PACKET: | 
|  | return "M2M_WIFI_RESP_ETHERNET_RX_PACKET"; | 
|  |  | 
|  | case M2M_WIFI_RESP_CON_STATE_CHANGED: | 
|  | return "M2M_WIFI_RESP_CON_STATE_CHANGED"; | 
|  | case M2M_WIFI_REQ_DHCP_CONF: | 
|  | return "Response indicating that IP address was obtained."; | 
|  | case M2M_WIFI_RESP_SCAN_DONE: | 
|  | return "M2M_WIFI_RESP_SCAN_DONE"; | 
|  | case M2M_WIFI_RESP_SCAN_RESULT: | 
|  | return "M2M_WIFI_RESP_SCAN_RESULT"; | 
|  | case M2M_WIFI_RESP_PROVISION_INFO: | 
|  | return "M2M_WIFI_RESP_PROVISION_INFO"; | 
|  | default: | 
|  | return "UNKNOWN"; | 
|  | } | 
|  | } | 
|  |  | 
|  | static char *socket_message_to_string(uint8_t message) | 
|  | { | 
|  | switch (message) { | 
|  | case SOCKET_MSG_BIND: | 
|  | return "Bind socket event."; | 
|  | case SOCKET_MSG_LISTEN: | 
|  | return "Listen socket event."; | 
|  | case SOCKET_MSG_DNS_RESOLVE: | 
|  | return "DNS Resolution event."; | 
|  | case SOCKET_MSG_ACCEPT: | 
|  | return "Accept socket event."; | 
|  | case SOCKET_MSG_CONNECT: | 
|  | return "Connect socket event."; | 
|  | case SOCKET_MSG_RECV: | 
|  | return "Receive socket event."; | 
|  | case SOCKET_MSG_SEND: | 
|  | return "Send socket event."; | 
|  | case SOCKET_MSG_SENDTO: | 
|  | return "Sendto socket event."; | 
|  | case SOCKET_MSG_RECVFROM: | 
|  | return "Recvfrom socket event."; | 
|  | default: | 
|  | return "UNKNOWN."; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This function is called when the socket is to be opened. | 
|  | */ | 
|  | static int winc1500_get(sa_family_t family, | 
|  | enum net_sock_type type, | 
|  | enum net_ip_protocol ip_proto, | 
|  | struct net_context **context) | 
|  | { | 
|  | struct socket_data *sd; | 
|  | SOCKET sock; | 
|  |  | 
|  | if (family != AF_INET) { | 
|  | LOG_ERR("Only AF_INET is supported!"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* winc1500 atmel uses AF_INET 2 instead of zephyrs AF_INET 1 | 
|  | * we have checked if family is AF_INET so we can hardcode this | 
|  | * for now. | 
|  | */ | 
|  | sock = winc1500_socket(2, type, 0); | 
|  | if (sock < 0) { | 
|  | LOG_ERR("socket error!"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | (*context)->offload_context = (void *)(intptr_t)sock; | 
|  | sd = &w1500_data.socket_data[sock]; | 
|  |  | 
|  | k_sem_init(&sd->wait_sem, 0, 1); | 
|  |  | 
|  | sd->context = *context; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This function is called when user wants to bind to local IP address. | 
|  | */ | 
|  | static int winc1500_bind(struct net_context *context, | 
|  | const struct sockaddr *addr, | 
|  | socklen_t addrlen) | 
|  | { | 
|  | SOCKET socket = (intptr_t)context->offload_context; | 
|  | int ret; | 
|  |  | 
|  | /* FIXME atmel winc1500 don't support bind on null port */ | 
|  | if (net_sin(addr)->sin_port == 0U) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | ret = winc1500_socket_bind((intptr_t)context->offload_context, (struct sockaddr *)addr, | 
|  | addrlen); | 
|  | if (ret) { | 
|  | LOG_ERR("bind error %d %s!", | 
|  | ret, socket_message_to_string(ret)); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | if (k_sem_take(&w1500_data.socket_data[socket].wait_sem, | 
|  | WINC1500_BIND_TIMEOUT)) { | 
|  | LOG_ERR("bind error timeout expired"); | 
|  | return -ETIMEDOUT; | 
|  | } | 
|  |  | 
|  | return w1500_data.socket_data[socket].ret_code; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This function is called when user wants to mark the socket | 
|  | * to be a listening one. | 
|  | */ | 
|  | static int winc1500_listen(struct net_context *context, int backlog) | 
|  | { | 
|  | SOCKET socket = (intptr_t)context->offload_context; | 
|  | int ret; | 
|  |  | 
|  | ret = winc1500_socket_listen((intptr_t)context->offload_context, backlog); | 
|  | if (ret) { | 
|  | LOG_ERR("listen error %d %s!", | 
|  | ret, socket_error_string(ret)); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | if (k_sem_take(&w1500_data.socket_data[socket].wait_sem, | 
|  | WINC1500_LISTEN_TIMEOUT)) { | 
|  | return -ETIMEDOUT; | 
|  | } | 
|  |  | 
|  | return w1500_data.socket_data[socket].ret_code; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This function is called when user wants to create a connection | 
|  | * to a peer host. | 
|  | */ | 
|  | static int winc1500_connect(struct net_context *context, | 
|  | const struct sockaddr *addr, | 
|  | socklen_t addrlen, | 
|  | net_context_connect_cb_t cb, | 
|  | int32_t timeout, | 
|  | void *user_data) | 
|  | { | 
|  | SOCKET socket = (intptr_t)context->offload_context; | 
|  | int ret; | 
|  |  | 
|  | w1500_data.socket_data[socket].connect_cb = cb; | 
|  | w1500_data.socket_data[socket].connect_user_data = user_data; | 
|  | w1500_data.socket_data[socket].ret_code = 0; | 
|  |  | 
|  | ret = winc1500_socket_connect(socket, (struct sockaddr *)addr, addrlen); | 
|  | if (ret) { | 
|  | LOG_ERR("connect error %d %s!", | 
|  | ret, socket_error_string(ret)); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | if (timeout != 0 && | 
|  | k_sem_take(&w1500_data.socket_data[socket].wait_sem, K_MSEC(timeout))) { | 
|  | return -ETIMEDOUT; | 
|  | } | 
|  |  | 
|  | return w1500_data.socket_data[socket].ret_code; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This function is called when user wants to accept a connection | 
|  | * being established. | 
|  | */ | 
|  | static int winc1500_accept(struct net_context *context, | 
|  | net_tcp_accept_cb_t cb, | 
|  | int32_t timeout, | 
|  | void *user_data) | 
|  | { | 
|  | SOCKET socket = (intptr_t)context->offload_context; | 
|  | int ret; | 
|  |  | 
|  | w1500_data.socket_data[socket].accept_cb = cb; | 
|  | w1500_data.socket_data[socket].accept_user_data = user_data; | 
|  |  | 
|  | ret = winc1500_socket_accept(socket, NULL, 0); | 
|  | if (ret) { | 
|  | LOG_ERR("accept error %d %s!", | 
|  | ret, socket_error_string(ret)); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | if (timeout) { | 
|  | if (k_sem_take(&w1500_data.socket_data[socket].wait_sem, | 
|  | K_MSEC(timeout))) { | 
|  | return -ETIMEDOUT; | 
|  | } | 
|  | } | 
|  |  | 
|  | return w1500_data.socket_data[socket].ret_code; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This function is called when user wants to send data to peer host. | 
|  | */ | 
|  | static int winc1500_send(struct net_pkt *pkt, | 
|  | net_context_send_cb_t cb, | 
|  | int32_t timeout, | 
|  | void *user_data) | 
|  | { | 
|  | struct net_context *context = pkt->context; | 
|  | SOCKET socket = (intptr_t)context->offload_context; | 
|  | int ret = 0; | 
|  | struct net_buf *buf; | 
|  |  | 
|  | buf = net_buf_alloc(&winc1500_tx_pool, WINC1500_BUF_TIMEOUT); | 
|  | if (!buf) { | 
|  | return -ENOBUFS; | 
|  | } | 
|  |  | 
|  | if (net_pkt_read(pkt, buf->data, net_pkt_get_len(pkt))) { | 
|  | ret = -ENOBUFS; | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | net_buf_add(buf, net_pkt_get_len(pkt)); | 
|  |  | 
|  | ret = winc1500_socket_send(socket, buf->data, buf->len, 0); | 
|  | if (ret) { | 
|  | LOG_ERR("send error %d %s!", ret, socket_error_string(ret)); | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | net_pkt_unref(pkt); | 
|  | out: | 
|  | net_buf_unref(buf); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This function is called when user wants to send data to peer host. | 
|  | */ | 
|  | static int winc1500_sendto(struct net_pkt *pkt, | 
|  | const struct sockaddr *dst_addr, | 
|  | socklen_t addrlen, | 
|  | net_context_send_cb_t cb, | 
|  | int32_t timeout, | 
|  | void *user_data) | 
|  | { | 
|  | struct net_context *context = pkt->context; | 
|  | SOCKET socket = (intptr_t)context->offload_context; | 
|  | int ret = 0; | 
|  | struct net_buf *buf; | 
|  |  | 
|  | buf = net_buf_alloc(&winc1500_tx_pool, WINC1500_BUF_TIMEOUT); | 
|  | if (!buf) { | 
|  | return -ENOBUFS; | 
|  | } | 
|  |  | 
|  | if (net_pkt_read(pkt, buf->data, net_pkt_get_len(pkt))) { | 
|  | ret = -ENOBUFS; | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | net_buf_add(buf, net_pkt_get_len(pkt)); | 
|  |  | 
|  | ret = winc1500_socket_sendto(socket, buf->data, buf->len, 0, | 
|  | (struct sockaddr *)dst_addr, addrlen); | 
|  | if (ret) { | 
|  | LOG_ERR("sendto error %d %s!", ret, socket_error_string(ret)); | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | net_pkt_unref(pkt); | 
|  | out: | 
|  | net_buf_unref(buf); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /** | 
|  | */ | 
|  | static int prepare_pkt(struct socket_data *sock_data) | 
|  | { | 
|  | /* Get the frame from the buffer */ | 
|  | sock_data->rx_pkt = net_pkt_rx_alloc_on_iface(w1500_data.iface, | 
|  | K_NO_WAIT); | 
|  | if (!sock_data->rx_pkt) { | 
|  | LOG_ERR("Could not allocate rx packet"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Reserve a data buffer to receive the frame */ | 
|  | sock_data->pkt_buf = net_buf_alloc(&winc1500_rx_pool, K_NO_WAIT); | 
|  | if (!sock_data->pkt_buf) { | 
|  | LOG_ERR("Could not allocate data buffer"); | 
|  | net_pkt_unref(sock_data->rx_pkt); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | net_pkt_append_buffer(sock_data->rx_pkt, sock_data->pkt_buf); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This function is called when user wants to receive data from peer | 
|  | * host. | 
|  | */ | 
|  | static int winc1500_recv(struct net_context *context, | 
|  | net_context_recv_cb_t cb, | 
|  | int32_t timeout, | 
|  | void *user_data) | 
|  | { | 
|  | SOCKET socket = (intptr_t)context->offload_context; | 
|  | int ret; | 
|  |  | 
|  | w1500_data.socket_data[socket].recv_cb = cb; | 
|  | w1500_data.socket_data[socket].recv_user_data = user_data; | 
|  | if (!cb) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | ret = prepare_pkt(&w1500_data.socket_data[socket]); | 
|  | if (ret) { | 
|  | LOG_ERR("Could not reserve packet buffer"); | 
|  | return -ENOMEM; | 
|  | } | 
|  |  | 
|  |  | 
|  | ret = winc1500_socket_recv(socket, w1500_data.socket_data[socket].pkt_buf->data, | 
|  | CONFIG_WIFI_WINC1500_MAX_PACKET_SIZE, timeout); | 
|  | if (ret) { | 
|  | LOG_ERR("recv error %d %s!", | 
|  | ret, socket_error_string(ret)); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * This function is called when user wants to close the socket. | 
|  | */ | 
|  | static int winc1500_put(struct net_context *context) | 
|  | { | 
|  | SOCKET sock = (intptr_t)context->offload_context; | 
|  | struct socket_data *sd = &w1500_data.socket_data[sock]; | 
|  | int ret; | 
|  |  | 
|  | memset(&(context->remote), 0, sizeof(struct sockaddr_in)); | 
|  | context->flags &= ~NET_CONTEXT_REMOTE_ADDR_SET; | 
|  | ret = winc1500_close(sock); | 
|  |  | 
|  | net_pkt_unref(sd->rx_pkt); | 
|  |  | 
|  | memset(sd, 0, sizeof(struct socket_data)); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static struct net_offload winc1500_offload = { | 
|  | .get		= winc1500_get, | 
|  | .bind		= winc1500_bind, | 
|  | .listen		= winc1500_listen, | 
|  | .connect	= winc1500_connect, | 
|  | .accept		= winc1500_accept, | 
|  | .send		= winc1500_send, | 
|  | .sendto		= winc1500_sendto, | 
|  | .recv		= winc1500_recv, | 
|  | .put		= winc1500_put, | 
|  | }; | 
|  |  | 
|  | static void handle_wifi_con_state_changed(void *pvMsg) | 
|  | { | 
|  | tstrM2mWifiStateChanged *pstrWifiState = | 
|  | (tstrM2mWifiStateChanged *)pvMsg; | 
|  |  | 
|  | switch (pstrWifiState->u8CurrState) { | 
|  | case M2M_WIFI_DISCONNECTED: | 
|  | LOG_DBG("Disconnected (%u)", pstrWifiState->u8ErrCode); | 
|  |  | 
|  | if (w1500_data.connecting) { | 
|  | wifi_mgmt_raise_connect_result_event(w1500_data.iface, | 
|  | pstrWifiState->u8ErrCode ? -EIO : 0); | 
|  | w1500_data.connecting = false; | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | w1500_data.connected = false; | 
|  | wifi_mgmt_raise_disconnect_result_event(w1500_data.iface, 0); | 
|  |  | 
|  | break; | 
|  | case M2M_WIFI_CONNECTED: | 
|  | LOG_DBG("Connected (%u)", pstrWifiState->u8ErrCode); | 
|  |  | 
|  | w1500_data.connected = true; | 
|  | w1500_data.connecting = false; | 
|  | wifi_mgmt_raise_connect_result_event(w1500_data.iface, 0); | 
|  |  | 
|  | break; | 
|  | case M2M_WIFI_UNDEF: | 
|  | /* TODO status undefined*/ | 
|  | LOG_DBG("Undefined?"); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void handle_wifi_dhcp_conf(void *pvMsg) | 
|  | { | 
|  | uint8_t *pu8IPAddress = (uint8_t *)pvMsg; | 
|  | struct in_addr addr; | 
|  | uint8_t i; | 
|  |  | 
|  | /* Connected and got IP address*/ | 
|  | LOG_DBG("Wi-Fi connected, IP is %u.%u.%u.%u", | 
|  | pu8IPAddress[0], pu8IPAddress[1], | 
|  | pu8IPAddress[2], pu8IPAddress[3]); | 
|  |  | 
|  | /* TODO at this point the standby mode should be enable | 
|  | * status = WiFi connected IP assigned | 
|  | */ | 
|  | for (i = 0U; i < 4; i++) { | 
|  | addr.s4_addr[i] = pu8IPAddress[i]; | 
|  | } | 
|  |  | 
|  | /* TODO fill in net mask, gateway and lease time */ | 
|  |  | 
|  | net_if_ipv4_addr_add(w1500_data.iface, &addr, NET_ADDR_DHCP, 0); | 
|  | } | 
|  |  | 
|  | static void reset_scan_data(void) | 
|  | { | 
|  | w1500_data.scan_cb = NULL; | 
|  | w1500_data.scan_result = 0U; | 
|  | } | 
|  |  | 
|  | static void handle_scan_result(void *pvMsg) | 
|  | { | 
|  | tstrM2mWifiscanResult *pstrScanResult = (tstrM2mWifiscanResult *)pvMsg; | 
|  | struct wifi_scan_result result = { 0 }; | 
|  |  | 
|  | if (!w1500_data.scan_cb) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (pstrScanResult->u8AuthType == M2M_WIFI_SEC_OPEN) { | 
|  | result.security = WIFI_SECURITY_TYPE_NONE; | 
|  | } else if (pstrScanResult->u8AuthType == M2M_WIFI_SEC_WPA_PSK) { | 
|  | result.security = WIFI_SECURITY_TYPE_PSK; | 
|  | } else { | 
|  | LOG_DBG("Security %u not supported", | 
|  | pstrScanResult->u8AuthType); | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | memcpy(result.ssid, pstrScanResult->au8SSID, WIFI_SSID_MAX_LEN); | 
|  | result.ssid_length = strlen(result.ssid); | 
|  |  | 
|  | result.channel = pstrScanResult->u8ch; | 
|  | result.rssi = pstrScanResult->s8rssi; | 
|  |  | 
|  | w1500_data.scan_cb(w1500_data.iface, 0, &result); | 
|  |  | 
|  | k_yield(); | 
|  |  | 
|  | out: | 
|  | if (w1500_data.scan_result < m2m_wifi_get_num_ap_found()) { | 
|  | m2m_wifi_req_scan_result(w1500_data.scan_result); | 
|  | w1500_data.scan_result++; | 
|  | } else { | 
|  | w1500_data.scan_cb(w1500_data.iface, 0, NULL); | 
|  | reset_scan_data(); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void handle_scan_done(void *pvMsg) | 
|  | { | 
|  | tstrM2mScanDone	*pstrInfo = (tstrM2mScanDone *)pvMsg; | 
|  |  | 
|  | if (!w1500_data.scan_cb) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (pstrInfo->s8ScanState != M2M_SUCCESS) { | 
|  | w1500_data.scan_cb(w1500_data.iface, -EIO, NULL); | 
|  | reset_scan_data(); | 
|  |  | 
|  | LOG_ERR("Scan failed."); | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | w1500_data.scan_result = 0U; | 
|  |  | 
|  | if (pstrInfo->u8NumofCh >= 1) { | 
|  | LOG_DBG("Requesting results (%u)", | 
|  | m2m_wifi_get_num_ap_found()); | 
|  |  | 
|  | m2m_wifi_req_scan_result(w1500_data.scan_result); | 
|  | w1500_data.scan_result++; | 
|  | } else { | 
|  | LOG_DBG("No AP found"); | 
|  |  | 
|  | w1500_data.scan_cb(w1500_data.iface, 0, NULL); | 
|  | reset_scan_data(); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void winc1500_wifi_cb(uint8_t message_type, void *pvMsg) | 
|  | { | 
|  | LOG_DBG("Msg Type %d %s", | 
|  | message_type, wifi_cb_msg_2_str(message_type)); | 
|  |  | 
|  | switch (message_type) { | 
|  | case M2M_WIFI_RESP_CON_STATE_CHANGED: | 
|  | handle_wifi_con_state_changed(pvMsg); | 
|  | break; | 
|  | case M2M_WIFI_REQ_DHCP_CONF: | 
|  | handle_wifi_dhcp_conf(pvMsg); | 
|  | break; | 
|  | case M2M_WIFI_RESP_SCAN_RESULT: | 
|  | handle_scan_result(pvMsg); | 
|  | break; | 
|  | case M2M_WIFI_RESP_SCAN_DONE: | 
|  | handle_scan_done(pvMsg); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | #if LOG_LEVEL > LOG_LEVEL_OFF | 
|  | stack_stats(); | 
|  | #endif /* LOG_LEVEL > LOG_LEVEL_OFF */ | 
|  | } | 
|  |  | 
|  | static void handle_socket_msg_connect(struct socket_data *sd, void *pvMsg) | 
|  | { | 
|  | tstrSocketConnectMsg *strConnMsg = (tstrSocketConnectMsg *)pvMsg; | 
|  |  | 
|  | LOG_ERR("CONNECT: socket %d error %d", | 
|  | strConnMsg->sock, strConnMsg->s8Error); | 
|  |  | 
|  | if (!strConnMsg->s8Error) { | 
|  | net_context_set_state(sd->context, NET_CONTEXT_CONNECTED); | 
|  | } | 
|  |  | 
|  | if (sd->connect_cb) { | 
|  | sd->connect_cb(sd->context, | 
|  | strConnMsg->s8Error, | 
|  | sd->connect_user_data); | 
|  | } | 
|  |  | 
|  | sd->ret_code = strConnMsg->s8Error; | 
|  | } | 
|  |  | 
|  |  | 
|  | static bool handle_socket_msg_recv(SOCKET sock, | 
|  | struct socket_data *sd, void *pvMsg) | 
|  | { | 
|  | tstrSocketRecvMsg *pstrRx = (tstrSocketRecvMsg *)pvMsg; | 
|  |  | 
|  | if ((pstrRx->pu8Buffer != NULL) && (pstrRx->s16BufferSize > 0)) { | 
|  | net_buf_add(sd->pkt_buf, pstrRx->s16BufferSize); | 
|  | net_pkt_cursor_init(sd->rx_pkt); | 
|  |  | 
|  | if (sd->recv_cb) { | 
|  | sd->recv_cb(sd->context, | 
|  | sd->rx_pkt, | 
|  | NULL, NULL, | 
|  | 0, | 
|  | sd->recv_user_data); | 
|  | } | 
|  | } else if (pstrRx->pu8Buffer == NULL) { | 
|  | if (pstrRx->s16BufferSize == SOCK_ERR_CONN_ABORTED) { | 
|  | winc1500_close(sock); | 
|  |  | 
|  | net_pkt_unref(sd->rx_pkt); | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static void handle_socket_msg_bind(struct socket_data *sd, void *pvMsg) | 
|  | { | 
|  | tstrSocketBindMsg *bind_msg = (tstrSocketBindMsg *)pvMsg; | 
|  |  | 
|  | /* Holding a value of ZERO for a successful bind or otherwise | 
|  | * a negative error code corresponding to the type of error. | 
|  | */ | 
|  |  | 
|  | if (bind_msg->status) { | 
|  | LOG_ERR("BIND: error %d %s", | 
|  | bind_msg->status, | 
|  | socket_message_to_string(bind_msg->status)); | 
|  | sd->ret_code = bind_msg->status; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void handle_socket_msg_listen(struct socket_data *sd, void *pvMsg) | 
|  | { | 
|  | tstrSocketListenMsg *listen_msg = (tstrSocketListenMsg *)pvMsg; | 
|  |  | 
|  | /* Holding a value of ZERO for a successful listen or otherwise | 
|  | * a negative error code corresponding to the type of error. | 
|  | */ | 
|  |  | 
|  | if (listen_msg->status) { | 
|  | LOG_ERR("winc1500_socket_cb:LISTEN: error %d %s", | 
|  | listen_msg->status, | 
|  | socket_message_to_string(listen_msg->status)); | 
|  | sd->ret_code = listen_msg->status; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void handle_socket_msg_accept(struct socket_data *sd, void *pvMsg) | 
|  | { | 
|  | tstrSocketAcceptMsg *accept_msg = (tstrSocketAcceptMsg *)pvMsg; | 
|  |  | 
|  | /* On a successful accept operation, the return information is | 
|  | * the socket ID for the accepted connection with the remote peer. | 
|  | * Otherwise a negative error code is returned to indicate failure | 
|  | * of the accept operation. | 
|  | */ | 
|  |  | 
|  | LOG_DBG("ACCEPT: from %d.%d.%d.%d:%d, new socket is %d", | 
|  | accept_msg->strAddr.sin_addr.s4_addr[0], | 
|  | accept_msg->strAddr.sin_addr.s4_addr[1], | 
|  | accept_msg->strAddr.sin_addr.s4_addr[2], | 
|  | accept_msg->strAddr.sin_addr.s4_addr[3], | 
|  | ntohs(accept_msg->strAddr.sin_port), | 
|  | accept_msg->sock); | 
|  |  | 
|  | if (accept_msg->sock < 0) { | 
|  | LOG_ERR("ACCEPT: error %d %s", | 
|  | accept_msg->sock, | 
|  | socket_message_to_string(accept_msg->sock)); | 
|  | sd->ret_code = accept_msg->sock; | 
|  | } | 
|  |  | 
|  | if (sd->accept_cb) { | 
|  | struct socket_data *a_sd; | 
|  | int ret; | 
|  |  | 
|  | a_sd = &w1500_data.socket_data[accept_msg->sock]; | 
|  |  | 
|  | memcpy(a_sd, sd, sizeof(struct socket_data)); | 
|  |  | 
|  | ret = net_context_get(AF_INET, SOCK_STREAM, | 
|  | IPPROTO_TCP, &a_sd->context); | 
|  | if (ret < 0) { | 
|  | LOG_ERR("Cannot get new net context for ACCEPT"); | 
|  | return; | 
|  | } | 
|  | /* We get a new socket from accept_msg but we need a new | 
|  | * context as well. The new context gives us another socket | 
|  | * so we have to close that one first. | 
|  | */ | 
|  | winc1500_close((intptr_t)a_sd->context->offload_context); | 
|  |  | 
|  | a_sd->context->offload_context = (void *)((intptr_t)accept_msg->sock); | 
|  | /** The iface is reset when getting a new context. */ | 
|  | a_sd->context->iface = sd->context->iface; | 
|  |  | 
|  | net_context_set_state(a_sd->context, NET_CONTEXT_CONNECTED); | 
|  |  | 
|  | /** Setup remote */ | 
|  | a_sd->context->remote.sa_family = AF_INET; | 
|  | net_sin(&a_sd->context->remote)->sin_port = | 
|  | accept_msg->strAddr.sin_port; | 
|  | net_sin(&a_sd->context->remote)->sin_addr.s_addr = | 
|  | accept_msg->strAddr.sin_addr.s_addr; | 
|  | a_sd->context->flags |= NET_CONTEXT_REMOTE_ADDR_SET; | 
|  |  | 
|  | sd->accept_cb(a_sd->context, | 
|  | (struct sockaddr *)&accept_msg->strAddr, | 
|  | sizeof(struct sockaddr_in), | 
|  | (accept_msg->sock > 0) ? | 
|  | 0 : accept_msg->sock, | 
|  | sd->accept_user_data); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void winc1500_socket_cb(SOCKET sock, uint8 message, void *pvMsg) | 
|  | { | 
|  | struct socket_data *sd = &w1500_data.socket_data[sock]; | 
|  |  | 
|  | if (message != 6) { | 
|  | LOG_DBG("sock %d Msg %d %s", | 
|  | sock, message, socket_message_to_string(message)); | 
|  | } | 
|  |  | 
|  | sd->ret_code = 0; | 
|  |  | 
|  | switch (message) { | 
|  | case SOCKET_MSG_CONNECT: | 
|  | handle_socket_msg_connect(sd, pvMsg); | 
|  | k_sem_give(&sd->wait_sem); | 
|  |  | 
|  | break; | 
|  | case SOCKET_MSG_SEND: | 
|  | break; | 
|  | case SOCKET_MSG_RECV: | 
|  | if (!handle_socket_msg_recv(sock, sd, pvMsg)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | break; | 
|  | case SOCKET_MSG_BIND: | 
|  | handle_socket_msg_bind(sd, pvMsg); | 
|  | k_sem_give(&sd->wait_sem); | 
|  |  | 
|  | break; | 
|  | case SOCKET_MSG_LISTEN: | 
|  | handle_socket_msg_listen(sd, pvMsg); | 
|  | k_sem_give(&sd->wait_sem); | 
|  |  | 
|  | break; | 
|  | case SOCKET_MSG_ACCEPT: | 
|  | handle_socket_msg_accept(sd, pvMsg); | 
|  |  | 
|  | break; | 
|  | } | 
|  | #if LOG_LEVEL > LOG_LEVEL_OFF | 
|  | stack_stats(); | 
|  | #endif /* LOG_LEVEL > LOG_LEVEL_OFF */ | 
|  | } | 
|  |  | 
|  | static void winc1500_thread(void *p1, void *p2, void *p3) | 
|  | { | 
|  | ARG_UNUSED(p1); | 
|  | ARG_UNUSED(p2); | 
|  | ARG_UNUSED(p3); | 
|  |  | 
|  | while (1) { | 
|  | while (m2m_wifi_handle_events(NULL) != 0) { | 
|  | } | 
|  |  | 
|  | k_sleep(K_MSEC(1)); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int winc1500_mgmt_scan(const struct device *dev, | 
|  | struct wifi_scan_params *params, | 
|  | scan_result_cb_t cb) | 
|  | { | 
|  | ARG_UNUSED(params); | 
|  |  | 
|  | if (w1500_data.scan_cb) { | 
|  | return -EALREADY; | 
|  | } | 
|  |  | 
|  | w1500_data.scan_cb = cb; | 
|  |  | 
|  | if (m2m_wifi_request_scan(M2M_WIFI_CH_ALL)) { | 
|  | w1500_data.scan_cb = NULL; | 
|  | LOG_ERR("Failed to request scan"); | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int winc1500_mgmt_connect(const struct device *dev, | 
|  | struct wifi_connect_req_params *params) | 
|  | { | 
|  | uint8_t ssid[M2M_MAX_SSID_LEN]; | 
|  | tuniM2MWifiAuth psk; | 
|  | uint8_t security; | 
|  | uint16_t channel; | 
|  | void *auth; | 
|  |  | 
|  | memcpy(ssid, params->ssid, params->ssid_length); | 
|  | ssid[params->ssid_length] = '\0'; | 
|  |  | 
|  | if (params->security == WIFI_SECURITY_TYPE_PSK) { | 
|  | memcpy(psk.au8PSK, params->psk, params->psk_length); | 
|  | psk.au8PSK[params->psk_length] = '\0'; | 
|  | auth = &psk; | 
|  |  | 
|  | security = M2M_WIFI_SEC_WPA_PSK; | 
|  | } else { | 
|  | auth = NULL; | 
|  | security = M2M_WIFI_SEC_OPEN; | 
|  | } | 
|  |  | 
|  | if (params->channel == WIFI_CHANNEL_ANY) { | 
|  | channel = M2M_WIFI_CH_ALL; | 
|  | } else { | 
|  | channel = params->channel; | 
|  | } | 
|  |  | 
|  | LOG_DBG("Connecting to %s (%u) on %s %u %s security (%s)", | 
|  | ssid, params->ssid_length, | 
|  | channel == M2M_WIFI_CH_ALL ? "channel unknown" : "channel", | 
|  | channel, | 
|  | security == M2M_WIFI_SEC_OPEN ? "without" : "with", | 
|  | params->psk ? (char *)psk.au8PSK : ""); | 
|  |  | 
|  | if (m2m_wifi_connect((char *)ssid, params->ssid_length, | 
|  | security, auth, channel)) { | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | w1500_data.connecting = true; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int winc1500_mgmt_disconnect(const struct device *dev) | 
|  | { | 
|  | if (!w1500_data.connected) { | 
|  | return -EALREADY; | 
|  | } | 
|  |  | 
|  | if (m2m_wifi_disconnect()) { | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int winc1500_mgmt_ap_enable(const struct device *dev, | 
|  | struct wifi_connect_req_params *params) | 
|  | { | 
|  | tstrM2MAPConfig strM2MAPConfig; | 
|  |  | 
|  | memset(&strM2MAPConfig, 0x00, sizeof(tstrM2MAPConfig)); | 
|  | strncpy((char *)&strM2MAPConfig.au8SSID, params->ssid, | 
|  | params->ssid_length); | 
|  | strM2MAPConfig.u8ListenChannel = params->channel; | 
|  | /** security is hardcoded as open for now */ | 
|  | strM2MAPConfig.u8SecType = M2M_WIFI_SEC_OPEN; | 
|  | /** DHCP: 192.168.1.1 */ | 
|  | strM2MAPConfig.au8DHCPServerIP[0] = 0xC0; | 
|  | strM2MAPConfig.au8DHCPServerIP[1] = 0xA8; | 
|  | strM2MAPConfig.au8DHCPServerIP[2] = 0x01; | 
|  | strM2MAPConfig.au8DHCPServerIP[3] = 0x01; | 
|  |  | 
|  | if (m2m_wifi_enable_ap(&strM2MAPConfig) != M2M_SUCCESS) { | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int winc1500_mgmt_ap_disable(const struct device *dev) | 
|  | { | 
|  | if (m2m_wifi_disable_ap() != M2M_SUCCESS) { | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void winc1500_iface_init(struct net_if *iface) | 
|  | { | 
|  | LOG_DBG("eth_init:net_if_set_link_addr:" | 
|  | "MAC Address %02X:%02X:%02X:%02X:%02X:%02X", | 
|  | w1500_data.mac[0], w1500_data.mac[1], w1500_data.mac[2], | 
|  | w1500_data.mac[3], w1500_data.mac[4], w1500_data.mac[5]); | 
|  |  | 
|  | net_if_set_link_addr(iface, w1500_data.mac, sizeof(w1500_data.mac), | 
|  | NET_LINK_ETHERNET); | 
|  |  | 
|  | iface->if_dev->offload = &winc1500_offload; | 
|  |  | 
|  | w1500_data.iface = iface; | 
|  | } | 
|  |  | 
|  | static enum offloaded_net_if_types winc1500_get_wifi_type(void) | 
|  | { | 
|  | return L2_OFFLOADED_NET_IF_TYPE_WIFI; | 
|  | } | 
|  |  | 
|  | static const struct wifi_mgmt_ops winc1500_mgmt_ops = { | 
|  | .scan		= winc1500_mgmt_scan, | 
|  | .connect	= winc1500_mgmt_connect, | 
|  | .disconnect	= winc1500_mgmt_disconnect, | 
|  | .ap_enable	= winc1500_mgmt_ap_enable, | 
|  | .ap_disable	= winc1500_mgmt_ap_disable, | 
|  | }; | 
|  | static const struct net_wifi_mgmt_offload winc1500_api = { | 
|  | .wifi_iface.iface_api.init = winc1500_iface_init, | 
|  | .wifi_iface.get_type = winc1500_get_wifi_type, | 
|  | .wifi_mgmt_api = &winc1500_mgmt_ops, | 
|  | }; | 
|  |  | 
|  | static int winc1500_init(const struct device *dev) | 
|  | { | 
|  | tstrWifiInitParam param = { | 
|  | .pfAppWifiCb = winc1500_wifi_cb, | 
|  | }; | 
|  | unsigned char is_valid; | 
|  | int ret; | 
|  |  | 
|  | ARG_UNUSED(dev); | 
|  |  | 
|  | w1500_data.connecting = false; | 
|  | w1500_data.connected = false; | 
|  |  | 
|  | ret = m2m_wifi_init(¶m); | 
|  | if (ret != M2M_SUCCESS) { | 
|  | LOG_ERR("m2m_wifi_init return error!(%d)", ret); | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | socketInit(); | 
|  | registerSocketCallback(winc1500_socket_cb, NULL); | 
|  |  | 
|  | if (m2m_wifi_get_otp_mac_address(w1500_data.mac, &is_valid) != M2M_SUCCESS) { | 
|  | LOG_ERR("Failed to get MAC address"); | 
|  | } | 
|  |  | 
|  | LOG_DBG("WINC1500 MAC Address from OTP (%d) " | 
|  | "%02X:%02X:%02X:%02X:%02X:%02X", | 
|  | is_valid, | 
|  | w1500_data.mac[0], w1500_data.mac[1], w1500_data.mac[2], | 
|  | w1500_data.mac[3], w1500_data.mac[4], w1500_data.mac[5]); | 
|  |  | 
|  | if (m2m_wifi_set_scan_region(WINC1500_REGION) != M2M_SUCCESS) { | 
|  | LOG_ERR("Failed set scan region"); | 
|  | } | 
|  |  | 
|  | if (m2m_wifi_set_power_profile(PWR_LOW1) != M2M_SUCCESS) { | 
|  | LOG_ERR("Failed set power profile"); | 
|  | } | 
|  |  | 
|  | if (m2m_wifi_set_tx_power(TX_PWR_LOW) != M2M_SUCCESS) { | 
|  | LOG_ERR("Failed set tx power"); | 
|  | } | 
|  |  | 
|  | /* monitoring thread for winc wifi callbacks */ | 
|  | k_thread_create(&winc1500_thread_data, winc1500_stack, | 
|  | CONFIG_WIFI_WINC1500_THREAD_STACK_SIZE, | 
|  | winc1500_thread, NULL, NULL, NULL, | 
|  | K_PRIO_COOP(CONFIG_WIFI_WINC1500_THREAD_PRIO), | 
|  | 0, K_NO_WAIT); | 
|  | k_thread_name_set(&winc1500_thread_data, "WINC1500"); | 
|  |  | 
|  | LOG_DBG("WINC1500 driver Initialized"); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | NET_DEVICE_OFFLOAD_INIT(winc1500, CONFIG_WIFI_WINC1500_NAME, | 
|  | winc1500_init, NULL, &w1500_data, NULL, | 
|  | CONFIG_WIFI_INIT_PRIORITY, &winc1500_api, | 
|  | CONFIG_WIFI_WINC1500_MAX_PACKET_SIZE); | 
|  |  | 
|  | CONNECTIVITY_WIFI_MGMT_BIND(winc1500); |