6a69f0e96f
Support SIOCDENYINETSOCK ioctl command to set usrsock status. If usock_enable is false, its means application wants to create a socket with other network stack.
1836 lines
41 KiB
C
1836 lines
41 KiB
C
/****************************************************************************
|
|
* apps/wireless/gs2200m/gs2200m_main.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you 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.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <debug.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <poll.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <net/if.h>
|
|
|
|
#include <nuttx/net/usrsock.h>
|
|
#include <nuttx/wireless/wireless.h>
|
|
#include <nuttx/wireless/gs2200m.h>
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
/* #define GS2200M_TRACE */
|
|
|
|
#ifdef GS2200M_TRACE
|
|
# define gs2200m_printf(v, ...) printf(v, ##__VA_ARGS__)
|
|
#else
|
|
# define gs2200m_printf(v, ...)
|
|
#endif
|
|
|
|
#define SOCKET_BASE 10000
|
|
#define SOCKET_COUNT 16
|
|
|
|
/****************************************************************************
|
|
* Private Data Types
|
|
****************************************************************************/
|
|
|
|
enum sock_state_e
|
|
{
|
|
CLOSED,
|
|
OPENED,
|
|
BOUND,
|
|
CONNECTED,
|
|
};
|
|
|
|
struct usock_s
|
|
{
|
|
int8_t type;
|
|
char cid;
|
|
enum sock_state_e state;
|
|
uint16_t lport; /* local port */
|
|
struct sockaddr_in raddr; /* remote addr */
|
|
};
|
|
|
|
struct gs2200m_s
|
|
{
|
|
char *ssid;
|
|
char *key;
|
|
uint8_t mode;
|
|
uint8_t ch;
|
|
int gsfd;
|
|
int usock_enable;
|
|
struct usock_s sockets[SOCKET_COUNT];
|
|
};
|
|
|
|
union usrsock_request_u
|
|
{
|
|
struct usrsock_request_socket_s socket;
|
|
struct usrsock_request_close_s close;
|
|
struct usrsock_request_connect_s connect;
|
|
struct usrsock_request_sendto_s sendto;
|
|
struct usrsock_request_recvfrom_s recvfrom;
|
|
struct usrsock_request_setsockopt_s setsockopt;
|
|
struct usrsock_request_getsockopt_s getsockopt;
|
|
struct usrsock_request_getsockname_s getsockname;
|
|
struct usrsock_request_getpeername_s getpeername;
|
|
struct usrsock_request_bind_s bind;
|
|
struct usrsock_request_listen_s listen;
|
|
struct usrsock_request_accept_s accept;
|
|
struct usrsock_request_ioctl_s ioctl;
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
static int socket_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
static int close_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
static int connect_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
static int sendto_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
static int recvfrom_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
static int setsockopt_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
static int getsockopt_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
static int getsockname_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
static int getpeername_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
static int ioctl_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
static int bind_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
static int listen_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
static int accept_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf);
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
static const struct usrsock_req_handler_s
|
|
{
|
|
uint32_t hdrlen;
|
|
int (CODE *fn)(int fd, FAR struct gs2200m_s *priv, FAR void *req);
|
|
}
|
|
handlers[USRSOCK_REQUEST__MAX] =
|
|
{
|
|
{
|
|
sizeof(struct usrsock_request_socket_s),
|
|
socket_request,
|
|
},
|
|
{
|
|
sizeof(struct usrsock_request_close_s),
|
|
close_request,
|
|
},
|
|
{
|
|
sizeof(struct usrsock_request_connect_s),
|
|
connect_request,
|
|
},
|
|
{
|
|
sizeof(struct usrsock_request_sendto_s),
|
|
sendto_request,
|
|
},
|
|
{
|
|
sizeof(struct usrsock_request_recvfrom_s),
|
|
recvfrom_request,
|
|
},
|
|
{
|
|
sizeof(struct usrsock_request_setsockopt_s),
|
|
setsockopt_request,
|
|
},
|
|
{
|
|
sizeof(struct usrsock_request_getsockopt_s),
|
|
getsockopt_request,
|
|
},
|
|
{
|
|
sizeof(struct usrsock_request_getsockname_s),
|
|
getsockname_request,
|
|
},
|
|
{
|
|
sizeof(struct usrsock_request_getpeername_s),
|
|
getpeername_request,
|
|
},
|
|
{
|
|
sizeof(struct usrsock_request_bind_s),
|
|
bind_request,
|
|
},
|
|
{
|
|
sizeof(struct usrsock_request_listen_s),
|
|
listen_request,
|
|
},
|
|
{
|
|
sizeof(struct usrsock_request_accept_s),
|
|
accept_request,
|
|
},
|
|
{
|
|
sizeof(struct usrsock_request_ioctl_s),
|
|
ioctl_request,
|
|
},
|
|
};
|
|
|
|
static struct gs2200m_s *_daemon;
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: _write_to_usock
|
|
****************************************************************************/
|
|
|
|
static int _write_to_usock(int fd, void *buf, size_t count)
|
|
{
|
|
ssize_t wlen;
|
|
|
|
wlen = write(fd, buf, count);
|
|
|
|
if (wlen < 0)
|
|
{
|
|
return -errno;
|
|
}
|
|
|
|
if (wlen != count)
|
|
{
|
|
return -ENOSPC;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: _send_ack_common
|
|
****************************************************************************/
|
|
|
|
static int _send_ack_common(int fd,
|
|
uint16_t events,
|
|
uint32_t xid,
|
|
FAR struct usrsock_message_req_ack_s *resp)
|
|
{
|
|
resp->head.msgid = USRSOCK_MESSAGE_RESPONSE_ACK;
|
|
resp->head.flags = 0;
|
|
resp->head.events = events;
|
|
resp->xid = xid;
|
|
|
|
/* Send ACK response. */
|
|
|
|
return _write_to_usock(fd, resp, sizeof(*resp));
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: gs2200m_socket_alloc
|
|
****************************************************************************/
|
|
|
|
static int16_t gs2200m_socket_alloc(FAR struct gs2200m_s *priv, int type)
|
|
{
|
|
FAR struct usock_s *usock;
|
|
int16_t i;
|
|
|
|
for (i = 0; i < SOCKET_COUNT; i++)
|
|
{
|
|
usock = &priv->sockets[i];
|
|
|
|
if (CLOSED == usock->state)
|
|
{
|
|
memset(usock, 0, sizeof(*usock));
|
|
usock->cid = 'z'; /* Invalidate cid */
|
|
usock->state = OPENED;
|
|
usock->type = type;
|
|
return i + SOCKET_BASE;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: gs2200m_socket_get
|
|
****************************************************************************/
|
|
|
|
static FAR struct usock_s *gs2200m_socket_get(FAR struct gs2200m_s *priv,
|
|
int sockid)
|
|
{
|
|
if (sockid < SOCKET_BASE)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
sockid -= SOCKET_BASE;
|
|
|
|
if (sockid >= SOCKET_COUNT)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return &priv->sockets[sockid];
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: gs2200m_find_socket_by_cid
|
|
****************************************************************************/
|
|
|
|
static FAR struct usock_s *
|
|
gs2200m_find_socket_by_cid(FAR struct gs2200m_s *priv,
|
|
char cid)
|
|
{
|
|
FAR struct usock_s *ret = NULL;
|
|
int i;
|
|
|
|
for (i = 0; i < SOCKET_COUNT; i++)
|
|
{
|
|
if (priv->sockets[i].cid == cid)
|
|
{
|
|
ret = &priv->sockets[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: gs2200m_socket_free
|
|
****************************************************************************/
|
|
|
|
static int gs2200m_socket_free(FAR struct gs2200m_s *priv, int sockid)
|
|
{
|
|
FAR struct usock_s *usock = gs2200m_socket_get(priv, sockid);
|
|
|
|
if (!usock)
|
|
{
|
|
return -EBADFD;
|
|
}
|
|
|
|
if (CLOSED == usock->state)
|
|
{
|
|
return -EFAULT;
|
|
}
|
|
|
|
usock->state = CLOSED;
|
|
usock->cid = 'z'; /* invalid */
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: read_req
|
|
****************************************************************************/
|
|
|
|
static ssize_t
|
|
read_req(int fd, FAR const struct usrsock_request_common_s *com_hdr,
|
|
FAR void *req, size_t reqsize)
|
|
{
|
|
ssize_t rlen;
|
|
|
|
rlen = read(fd, (uint8_t *)req + sizeof(*com_hdr),
|
|
reqsize - sizeof(*com_hdr));
|
|
|
|
if (rlen < 0)
|
|
{
|
|
return -errno;
|
|
}
|
|
|
|
if (rlen + sizeof(*com_hdr) != reqsize)
|
|
{
|
|
return -EMSGSIZE;
|
|
}
|
|
|
|
return rlen;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: usrsock_handle_request
|
|
****************************************************************************/
|
|
|
|
static int usrsock_handle_request(int fd, FAR struct gs2200m_s *priv)
|
|
{
|
|
FAR struct usrsock_request_common_s *com_hdr;
|
|
union usrsock_request_u req;
|
|
ssize_t rlen;
|
|
|
|
com_hdr = (FAR void *)&req;
|
|
rlen = read(fd, com_hdr, sizeof(*com_hdr));
|
|
|
|
if (rlen < 0)
|
|
{
|
|
return -errno;
|
|
}
|
|
|
|
if (rlen != sizeof(*com_hdr))
|
|
{
|
|
return -EMSGSIZE;
|
|
}
|
|
|
|
if (com_hdr->reqid >= USRSOCK_REQUEST__MAX ||
|
|
!handlers[com_hdr->reqid].fn)
|
|
{
|
|
ASSERT(false);
|
|
return -EIO;
|
|
}
|
|
|
|
assert(handlers[com_hdr->reqid].hdrlen <= sizeof(req));
|
|
|
|
rlen = read_req(fd, com_hdr, &req,
|
|
handlers[com_hdr->reqid].hdrlen);
|
|
|
|
if (rlen < 0)
|
|
{
|
|
return rlen;
|
|
}
|
|
|
|
return handlers[com_hdr->reqid].fn(fd, priv, &req);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: usock_send_event
|
|
****************************************************************************/
|
|
|
|
static int usock_send_event(int fd, FAR struct gs2200m_s *priv,
|
|
FAR struct usock_s *usock, int events)
|
|
{
|
|
FAR struct usrsock_message_socket_event_s event;
|
|
int i;
|
|
|
|
memset(&event, 0, sizeof(event));
|
|
event.head.flags = USRSOCK_MESSAGE_FLAG_EVENT;
|
|
event.head.msgid = USRSOCK_MESSAGE_SOCKET_EVENT;
|
|
|
|
for (i = 0; i < SOCKET_COUNT; i++)
|
|
{
|
|
if (usock == &priv->sockets[i])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == SOCKET_COUNT)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
event.usockid = i + SOCKET_BASE;
|
|
event.head.events = events;
|
|
|
|
return _write_to_usock(fd, &event, sizeof(event));
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: usock_sendevent_toall
|
|
****************************************************************************/
|
|
|
|
static void usock_sendevent_toall(FAR struct gs2200m_s *priv, int fd)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < SOCKET_COUNT; i++)
|
|
{
|
|
if (priv->sockets[i].state != CLOSED)
|
|
{
|
|
usock_send_event(fd, priv, &priv->sockets[i],
|
|
USRSOCK_EVENT_RECVFROM_AVAIL);
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: socket_request
|
|
****************************************************************************/
|
|
|
|
static int socket_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
FAR struct usrsock_request_socket_s *req = hdrbuf;
|
|
struct usrsock_message_req_ack_s resp;
|
|
uint16_t events = 0;
|
|
int16_t usockid;
|
|
int ret;
|
|
|
|
gs2200m_printf("%s: start type=%d\n",
|
|
__func__, req->type);
|
|
|
|
/* Check domain requested */
|
|
|
|
if (req->domain != AF_INET)
|
|
{
|
|
usockid = -EAFNOSUPPORT;
|
|
}
|
|
else if (!priv->usock_enable && req->domain == AF_INET &&
|
|
req->type != SOCK_CTRL)
|
|
{
|
|
/* If domain is AF_INET while usock_enable is false,
|
|
* set usockid to -ENOTSUP to fallback kernel
|
|
* network stack.
|
|
*/
|
|
|
|
usockid = -ENOTSUP;
|
|
}
|
|
else
|
|
{
|
|
/* Allocate socket. */
|
|
|
|
usockid = gs2200m_socket_alloc(priv, req->type);
|
|
ASSERT(0 < usockid);
|
|
}
|
|
|
|
/* Send ACK response */
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.result = usockid;
|
|
if (req->type == SOCK_DGRAM)
|
|
{
|
|
events = USRSOCK_EVENT_SENDTO_READY;
|
|
}
|
|
|
|
ret = _send_ack_common(fd, events, req->head.xid, &resp);
|
|
|
|
if (0 > ret)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
gs2200m_printf("%s: end\n", __func__);
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: close_request
|
|
****************************************************************************/
|
|
|
|
static int close_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
FAR struct usrsock_request_close_s *req = hdrbuf;
|
|
struct usrsock_message_req_ack_s resp;
|
|
struct gs2200m_close_msg clmsg;
|
|
FAR struct usock_s *usock;
|
|
char cid;
|
|
int ret = 0;
|
|
|
|
gs2200m_printf("%s: start\n", __func__);
|
|
|
|
/* Check if this socket exists. */
|
|
|
|
usock = gs2200m_socket_get(priv, req->usockid);
|
|
|
|
cid = usock->cid;
|
|
|
|
if ((BOUND != usock->state) && (CONNECTED != usock->state))
|
|
{
|
|
ret = -EBADFD;
|
|
goto errout;
|
|
}
|
|
|
|
memset(&clmsg, 0, sizeof(clmsg));
|
|
clmsg.cid = cid;
|
|
ioctl(priv->gsfd, GS2200M_IOC_CLOSE, (unsigned long)&clmsg);
|
|
|
|
errout:
|
|
|
|
/* Send ACK response */
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.result = ret;
|
|
ret = _send_ack_common(fd, 0, req->head.xid, &resp);
|
|
|
|
if (0 > ret)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* Free socket */
|
|
|
|
ret = gs2200m_socket_free(priv, req->usockid);
|
|
|
|
gs2200m_printf("%s: end\n", __func__);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: connect_request
|
|
****************************************************************************/
|
|
|
|
static int connect_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
FAR struct usrsock_request_connect_s *req = hdrbuf;
|
|
struct usrsock_message_req_ack_s resp;
|
|
struct gs2200m_connect_msg cmsg;
|
|
struct sockaddr_in addr;
|
|
FAR struct usock_s *usock;
|
|
int events;
|
|
ssize_t wlen;
|
|
ssize_t rlen;
|
|
int ret = 0;
|
|
|
|
DEBUGASSERT(priv);
|
|
DEBUGASSERT(req);
|
|
|
|
gs2200m_printf("%s: start\n", __func__);
|
|
|
|
/* Check if this socket exists. */
|
|
|
|
usock = gs2200m_socket_get(priv, req->usockid);
|
|
|
|
if (!usock)
|
|
{
|
|
ret = -EBADFD;
|
|
goto prepare;
|
|
}
|
|
|
|
/* Check if this socket is already connected. */
|
|
|
|
if (CONNECTED == usock->state)
|
|
{
|
|
ret = -EISCONN;
|
|
goto prepare;
|
|
}
|
|
|
|
memset(&cmsg, 0, sizeof(cmsg));
|
|
|
|
/* Check if this socket is already connected. */
|
|
|
|
if (BOUND == usock->state)
|
|
{
|
|
if (usock->type == SOCK_STREAM)
|
|
{
|
|
ret = -EISCONN;
|
|
goto prepare;
|
|
}
|
|
else
|
|
{
|
|
/* Firstly, close the socket */
|
|
|
|
struct gs2200m_close_msg clmsg;
|
|
memset(&clmsg, 0, sizeof(clmsg));
|
|
clmsg.cid = usock->cid;
|
|
|
|
ioctl(priv->gsfd, GS2200M_IOC_CLOSE, (unsigned long)&clmsg);
|
|
|
|
/* Copy the local port info */
|
|
|
|
cmsg.lport = usock->lport;
|
|
|
|
usock->state = OPENED;
|
|
}
|
|
}
|
|
|
|
/* Check if address size ok. */
|
|
|
|
if (req->addrlen > sizeof(addr))
|
|
{
|
|
ret = -EFAULT;
|
|
goto prepare;
|
|
}
|
|
|
|
/* Read address. */
|
|
|
|
rlen = read(fd, &addr, sizeof(addr));
|
|
|
|
if (rlen < 0 || rlen < req->addrlen)
|
|
{
|
|
ret = -EFAULT;
|
|
goto prepare;
|
|
}
|
|
|
|
/* Check address family. */
|
|
|
|
if (addr.sin_family != AF_INET)
|
|
{
|
|
ret = -EAFNOSUPPORT;
|
|
goto prepare;
|
|
}
|
|
|
|
snprintf(cmsg.addr, sizeof(cmsg.addr), "%s",
|
|
inet_ntoa(addr.sin_addr));
|
|
snprintf(cmsg.port, sizeof(cmsg.port), "%d",
|
|
ntohs(addr.sin_port));
|
|
|
|
cmsg.cid = 'z'; /* set to invalid */
|
|
cmsg.type = usock->type;
|
|
|
|
ret = ioctl(priv->gsfd, GS2200M_IOC_CONNECT,
|
|
(unsigned long)&cmsg);
|
|
|
|
if (0 == ret)
|
|
{
|
|
usock->cid = cmsg.cid;
|
|
usock->state = CONNECTED;
|
|
usock->raddr = addr;
|
|
}
|
|
else
|
|
{
|
|
ret = -errno;
|
|
}
|
|
|
|
prepare:
|
|
|
|
/* Send ACK response. */
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.result = ret;
|
|
ret = _send_ack_common(fd, 0, req->head.xid, &resp);
|
|
|
|
if (0 > ret)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
events = USRSOCK_EVENT_SENDTO_READY;
|
|
wlen = usock_send_event(fd, priv, usock, events);
|
|
|
|
if (wlen < 0)
|
|
{
|
|
return wlen;
|
|
}
|
|
|
|
gs2200m_printf("%s: end\n", __func__);
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: sendto_request
|
|
****************************************************************************/
|
|
|
|
static int sendto_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
FAR struct usrsock_request_sendto_s *req = hdrbuf;
|
|
struct usrsock_message_req_ack_s resp;
|
|
struct gs2200m_send_msg smsg;
|
|
FAR struct usock_s *usock;
|
|
uint8_t *sendbuf = NULL;
|
|
ssize_t wlen;
|
|
ssize_t rlen;
|
|
int nret;
|
|
int ret = 0;
|
|
|
|
DEBUGASSERT(priv);
|
|
DEBUGASSERT(req);
|
|
|
|
gs2200m_printf("%s: start (buflen=%d)\n",
|
|
__func__, req->buflen);
|
|
|
|
/* Check if this socket exists. */
|
|
|
|
usock = gs2200m_socket_get(priv, req->usockid);
|
|
|
|
if (!usock)
|
|
{
|
|
ret = -EBADFD;
|
|
goto prepare;
|
|
}
|
|
|
|
/* Check if this socket is connected. */
|
|
|
|
if (SOCK_STREAM == usock->type && CONNECTED != usock->state)
|
|
{
|
|
ret = -ENOTCONN;
|
|
goto prepare;
|
|
}
|
|
|
|
/* Check if the address size is non-zero.
|
|
* connection-mode socket does not accept address
|
|
*/
|
|
|
|
if (usock->type == SOCK_STREAM && req->addrlen > 0)
|
|
{
|
|
ret = -EISCONN;
|
|
goto prepare;
|
|
}
|
|
|
|
memset(&smsg, 0, sizeof(smsg));
|
|
|
|
smsg.is_tcp = (usock->type == SOCK_STREAM) ? true : false;
|
|
|
|
/* For UDP, addlen must be provided */
|
|
|
|
if (usock->type == SOCK_DGRAM)
|
|
{
|
|
if (CONNECTED != usock->state)
|
|
{
|
|
if (req->addrlen == 0)
|
|
{
|
|
ret = -EINVAL;
|
|
goto prepare;
|
|
}
|
|
|
|
/* In UDP case, read the address. */
|
|
|
|
rlen = read(fd, &smsg.addr, sizeof(smsg.addr));
|
|
|
|
if (rlen < 0 || rlen < req->addrlen)
|
|
{
|
|
ret = -EFAULT;
|
|
goto prepare;
|
|
}
|
|
}
|
|
else if (CONNECTED == usock->state)
|
|
{
|
|
/* Copy remote address */
|
|
|
|
smsg.addr = usock->raddr;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(false);
|
|
}
|
|
|
|
gs2200m_printf("%s: addr: %s:%d",
|
|
__func__,
|
|
inet_ntoa(smsg.addr.sin_addr),
|
|
ntohs(smsg.addr.sin_port));
|
|
}
|
|
|
|
/* Check if the request has data. */
|
|
|
|
if (req->buflen > 0)
|
|
{
|
|
sendbuf = calloc(1, req->buflen);
|
|
ASSERT(sendbuf);
|
|
|
|
/* Read data from usrsock. */
|
|
|
|
rlen = read(fd, sendbuf, req->buflen);
|
|
|
|
if (rlen < 0 || rlen < req->buflen)
|
|
{
|
|
ret = -EFAULT;
|
|
goto prepare;
|
|
}
|
|
|
|
smsg.cid = usock->cid;
|
|
smsg.buf = sendbuf;
|
|
smsg.len = req->buflen;
|
|
|
|
nret = ioctl(priv->gsfd, GS2200M_IOC_SEND,
|
|
(unsigned long)&smsg);
|
|
|
|
if (usock->cid != smsg.cid)
|
|
{
|
|
/* cid is newly assigned (bound) */
|
|
|
|
usock->cid = smsg.cid;
|
|
usock->state = BOUND;
|
|
}
|
|
|
|
if (0 != nret)
|
|
{
|
|
ret = -errno;
|
|
goto prepare;
|
|
}
|
|
|
|
/* return length which gs2200m sent */
|
|
|
|
ret = smsg.len;
|
|
}
|
|
|
|
prepare:
|
|
if (sendbuf)
|
|
{
|
|
free(sendbuf);
|
|
}
|
|
|
|
/* Send ACK response. */
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.result = ret;
|
|
ret = _send_ack_common(fd, 0, req->head.xid, &resp);
|
|
|
|
if (0 > ret)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* Let kernel-side know that there is space for more send data. */
|
|
|
|
wlen = usock_send_event(fd, priv, usock,
|
|
USRSOCK_EVENT_SENDTO_READY);
|
|
|
|
if (wlen < 0)
|
|
{
|
|
return wlen;
|
|
}
|
|
|
|
gs2200m_printf("%s: end\n", __func__);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: recvfrom_request
|
|
****************************************************************************/
|
|
|
|
static int recvfrom_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
FAR struct usrsock_request_recvfrom_s *req = hdrbuf;
|
|
struct usrsock_message_datareq_ack_s resp;
|
|
struct usrsock_message_req_ack_s resp1;
|
|
struct gs2200m_recv_msg rmsg;
|
|
FAR struct usock_s *usock;
|
|
int ret = 0;
|
|
|
|
DEBUGASSERT(priv);
|
|
DEBUGASSERT(req);
|
|
|
|
gs2200m_printf("%s: start (req->max_buflen=%d)\n",
|
|
__func__, req->max_buflen);
|
|
|
|
memset(&rmsg, 0, sizeof(rmsg));
|
|
|
|
/* Check if this socket exists. */
|
|
|
|
usock = gs2200m_socket_get(priv, req->usockid);
|
|
|
|
if (!usock)
|
|
{
|
|
ret = -EBADFD;
|
|
goto prepare;
|
|
}
|
|
|
|
/* Check if this socket is connected. */
|
|
|
|
if (SOCK_STREAM == usock->type && CONNECTED != usock->state)
|
|
{
|
|
ret = -ENOTCONN;
|
|
goto prepare;
|
|
}
|
|
|
|
rmsg.cid = usock->cid;
|
|
rmsg.reqlen = req->max_buflen;
|
|
rmsg.is_tcp = (usock->type == SOCK_STREAM) ? true : false;
|
|
rmsg.flags = req->flags;
|
|
|
|
if (0 < req->max_buflen)
|
|
{
|
|
rmsg.buf = calloc(1, req->max_buflen);
|
|
ASSERT(rmsg.buf);
|
|
|
|
ret = ioctl(priv->gsfd, GS2200M_IOC_RECV,
|
|
(unsigned long)&rmsg);
|
|
}
|
|
|
|
if (0 == ret)
|
|
{
|
|
ret = rmsg.len;
|
|
}
|
|
else
|
|
{
|
|
ret = -errno;
|
|
}
|
|
|
|
if (!rmsg.is_tcp)
|
|
{
|
|
gs2200m_printf("%s: from (%s:%d)\n",
|
|
__func__,
|
|
inet_ntoa(rmsg.addr.sin_addr),
|
|
ntohs(rmsg.addr.sin_port));
|
|
}
|
|
|
|
prepare:
|
|
|
|
/* Prepare response. */
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.reqack.result = ret;
|
|
resp.reqack.xid = req->head.xid;
|
|
resp.reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK;
|
|
resp.reqack.head.flags = 0;
|
|
resp.reqack.head.events = 0;
|
|
|
|
if (0 <= ret)
|
|
{
|
|
resp.valuelen_nontrunc = sizeof(rmsg.addr);
|
|
resp.valuelen = MIN(resp.valuelen_nontrunc,
|
|
req->max_addrlen);
|
|
|
|
if ((0 == rmsg.len) && (0 != rmsg.reqlen))
|
|
{
|
|
usock_send_event(fd, priv, usock,
|
|
USRSOCK_EVENT_REMOTE_CLOSED
|
|
);
|
|
|
|
/* Send ack only */
|
|
|
|
memset(&resp1, 0, sizeof(resp1));
|
|
resp1.result = ret;
|
|
ret = _send_ack_common(fd, 0, req->head.xid, &resp1);
|
|
|
|
goto err_out;
|
|
}
|
|
}
|
|
|
|
/* Send response. */
|
|
|
|
ret = _write_to_usock(fd, &resp, sizeof(resp));
|
|
|
|
if (0 > ret)
|
|
{
|
|
goto err_out;
|
|
}
|
|
|
|
if (0 < resp.valuelen)
|
|
{
|
|
/* Send address (value) */
|
|
|
|
ret = _write_to_usock(fd, &rmsg.addr, resp.valuelen);
|
|
|
|
if (0 > ret)
|
|
{
|
|
goto err_out;
|
|
}
|
|
}
|
|
|
|
if (resp.reqack.result > 0)
|
|
{
|
|
/* Send buffer */
|
|
|
|
ret = _write_to_usock(fd, rmsg.buf, resp.reqack.result);
|
|
|
|
if (0 > ret)
|
|
{
|
|
goto err_out;
|
|
}
|
|
}
|
|
|
|
err_out:
|
|
gs2200m_printf("%s: *** end ret=%d\n", __func__, ret);
|
|
|
|
if (rmsg.buf)
|
|
{
|
|
free(rmsg.buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bind_request
|
|
****************************************************************************/
|
|
|
|
static int bind_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
FAR struct usrsock_request_bind_s *req = hdrbuf;
|
|
struct usrsock_message_req_ack_s resp;
|
|
struct gs2200m_bind_msg bmsg;
|
|
FAR struct usock_s *usock;
|
|
struct sockaddr_in addr;
|
|
ssize_t rlen;
|
|
int ret = 0;
|
|
|
|
DEBUGASSERT(priv);
|
|
DEBUGASSERT(req);
|
|
|
|
gs2200m_printf("%s: called ****\n", __func__);
|
|
|
|
/* Check if this socket exists. */
|
|
|
|
usock = gs2200m_socket_get(priv, req->usockid);
|
|
if (!usock)
|
|
{
|
|
ret = -EBADFD;
|
|
goto prepare;
|
|
}
|
|
|
|
/* Check if address size ok. */
|
|
|
|
if (req->addrlen > sizeof(addr))
|
|
{
|
|
ret = -EFAULT;
|
|
goto prepare;
|
|
}
|
|
|
|
/* Read address. */
|
|
|
|
rlen = read(fd, &addr, sizeof(addr));
|
|
|
|
if (rlen < 0 || rlen < req->addrlen)
|
|
{
|
|
ret = -EFAULT;
|
|
goto prepare;
|
|
}
|
|
|
|
/* Check address family. */
|
|
|
|
if (addr.sin_family != AF_INET)
|
|
{
|
|
ret = -EAFNOSUPPORT;
|
|
goto prepare;
|
|
}
|
|
|
|
snprintf(bmsg.port, sizeof(bmsg.port), "%d", ntohs(addr.sin_port));
|
|
bmsg.cid = 'z'; /* set to invalid */
|
|
bmsg.is_tcp = (usock->type == SOCK_STREAM) ? true : false;
|
|
|
|
ret = ioctl(priv->gsfd, GS2200M_IOC_BIND, (unsigned long)&bmsg);
|
|
|
|
if (0 == ret)
|
|
{
|
|
usock->cid = bmsg.cid;
|
|
usock->lport = ntohs(addr.sin_port);
|
|
usock->state = BOUND;
|
|
}
|
|
|
|
prepare:
|
|
|
|
/* Send ACK response. */
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.result = ret;
|
|
ret = _send_ack_common(fd, 0, req->head.xid, &resp);
|
|
|
|
if (0 > ret)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
gs2200m_printf("%s: end\n", __func__);
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: listen_request
|
|
****************************************************************************/
|
|
|
|
static int listen_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
FAR struct usrsock_request_listen_s *req = hdrbuf;
|
|
struct usrsock_message_req_ack_s resp;
|
|
FAR struct usock_s *usock;
|
|
int ret = 0;
|
|
|
|
DEBUGASSERT(priv);
|
|
DEBUGASSERT(req);
|
|
|
|
gs2200m_printf("%s: called ****\n", __func__);
|
|
|
|
/* Check if this socket exists. */
|
|
|
|
usock = gs2200m_socket_get(priv, req->usockid);
|
|
|
|
if (!usock)
|
|
{
|
|
ret = -EBADFD;
|
|
}
|
|
|
|
/* Send ACK response. */
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.result = ret;
|
|
ret = _send_ack_common(fd, 0, req->head.xid, &resp);
|
|
|
|
if (0 > ret)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
gs2200m_printf("%s: end\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: accept_request
|
|
****************************************************************************/
|
|
|
|
static int accept_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
FAR struct usrsock_request_accept_s *req = hdrbuf;
|
|
struct usrsock_message_datareq_ack_s resp;
|
|
struct gs2200m_accept_msg amsg;
|
|
FAR struct usock_s *usock;
|
|
FAR struct usock_s *new_usock = NULL;
|
|
int ret = 0;
|
|
int16_t usockid; /* usockid for new client */
|
|
|
|
DEBUGASSERT(priv);
|
|
DEBUGASSERT(req);
|
|
|
|
gs2200m_printf("%s: called ****\n", __func__);
|
|
|
|
/* Check if this socket exists. */
|
|
|
|
usock = gs2200m_socket_get(priv, req->usockid);
|
|
|
|
if (!usock)
|
|
{
|
|
ret = -EBADFD;
|
|
goto prepare;
|
|
}
|
|
|
|
/* TODO: need to check if specified socket exists */
|
|
|
|
/* Call gs2200m driver to obtain new cid for client */
|
|
|
|
amsg.cid = usock->cid; /* Set server cid */
|
|
ret = ioctl(priv->gsfd, GS2200M_IOC_ACCEPT, (unsigned long)&amsg);
|
|
|
|
if (-1 == ret)
|
|
{
|
|
goto prepare;
|
|
}
|
|
|
|
/* allocate socket. */
|
|
|
|
usockid = gs2200m_socket_alloc(priv, SOCK_STREAM);
|
|
ASSERT(0 < usockid);
|
|
new_usock = gs2200m_socket_get(priv, usockid);
|
|
|
|
/* Set cid for the new_usock to be used in gs2200m driver */
|
|
|
|
new_usock->cid = amsg.cid;
|
|
new_usock->state = CONNECTED;
|
|
new_usock->raddr = amsg.addr;
|
|
|
|
prepare:
|
|
|
|
/* Prepare response. */
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.reqack.xid = req->head.xid;
|
|
resp.reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK;
|
|
resp.reqack.head.flags = 0;
|
|
resp.reqack.head.events = 0;
|
|
|
|
if (0 == ret)
|
|
{
|
|
resp.reqack.result = 2; /* new_usock->raddr + usock */
|
|
resp.valuelen_nontrunc = sizeof(new_usock->raddr);
|
|
resp.valuelen = resp.valuelen_nontrunc;
|
|
}
|
|
else
|
|
{
|
|
resp.reqack.result = ret;
|
|
resp.valuelen = 0;
|
|
}
|
|
|
|
/* Send response. */
|
|
|
|
ret = _write_to_usock(fd, &resp, sizeof(resp));
|
|
|
|
if (0 > ret)
|
|
{
|
|
goto err_out;
|
|
}
|
|
|
|
if (resp.valuelen > 0)
|
|
{
|
|
/* Send address (value) */
|
|
|
|
ret = _write_to_usock(fd, &new_usock->raddr, resp.valuelen);
|
|
|
|
if (0 > ret)
|
|
{
|
|
goto err_out;
|
|
}
|
|
|
|
/* Send new usockid info */
|
|
|
|
ret = _write_to_usock(fd, &usockid, sizeof(usockid));
|
|
|
|
if (0 > ret)
|
|
{
|
|
goto err_out;
|
|
}
|
|
|
|
/* Set events ofr new_usock */
|
|
|
|
usock_send_event(fd, priv, new_usock,
|
|
USRSOCK_EVENT_SENDTO_READY
|
|
);
|
|
}
|
|
|
|
err_out:
|
|
gs2200m_printf("%s: end\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: setsockopt_request
|
|
****************************************************************************/
|
|
|
|
static int setsockopt_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
FAR struct usrsock_request_setsockopt_s *req = hdrbuf;
|
|
struct usrsock_message_req_ack_s resp;
|
|
FAR struct usock_s *usock;
|
|
ssize_t rlen;
|
|
int ret = 0;
|
|
int value;
|
|
|
|
DEBUGASSERT(priv);
|
|
DEBUGASSERT(req);
|
|
|
|
gs2200m_printf("%s: called ****\n", __func__);
|
|
|
|
/* Check if this socket exists. */
|
|
|
|
usock = gs2200m_socket_get(priv, req->usockid);
|
|
|
|
if (!usock)
|
|
{
|
|
ret = -EBADFD;
|
|
goto prepare;
|
|
}
|
|
|
|
if (req->level != SOL_SOCKET)
|
|
{
|
|
gs2200m_printf("setsockopt: level=%d not supported\n",
|
|
__func__, req->level);
|
|
ret = -ENOPROTOOPT;
|
|
goto prepare;
|
|
}
|
|
|
|
if (req->option != SO_REUSEADDR)
|
|
{
|
|
gs2200m_printf("setsockopt: option=%d not supported\n",
|
|
__func__, req->option);
|
|
ret = -ENOPROTOOPT;
|
|
goto prepare;
|
|
}
|
|
|
|
if (req->valuelen < sizeof(value))
|
|
{
|
|
ret = -EINVAL;
|
|
goto prepare;
|
|
}
|
|
|
|
/* Read value. */
|
|
|
|
rlen = read(fd, &value, sizeof(value));
|
|
|
|
if (rlen < 0 || rlen < sizeof(value))
|
|
{
|
|
ret = -EFAULT;
|
|
goto prepare;
|
|
}
|
|
|
|
/* Debug print */
|
|
|
|
gs2200m_printf("setsockopt: option=%d value=%d\n",
|
|
__func__, req->option, value);
|
|
|
|
ret = OK;
|
|
|
|
prepare:
|
|
|
|
/* Send ACK response */
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.result = ret;
|
|
|
|
ret = _send_ack_common(fd, 0, req->head.xid, &resp);
|
|
|
|
gs2200m_printf("%s: end (ret=%d)\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: getsockopt_request
|
|
****************************************************************************/
|
|
|
|
static int getsockopt_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
DEBUGASSERT(false);
|
|
return -ENOSYS;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: getsockname_request
|
|
****************************************************************************/
|
|
|
|
static int getsockname_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
FAR struct usrsock_request_getsockname_s *req = hdrbuf;
|
|
struct usrsock_message_datareq_ack_s resp;
|
|
struct gs2200m_name_msg nmsg;
|
|
FAR struct usock_s *usock;
|
|
int ret = 0;
|
|
|
|
DEBUGASSERT(priv);
|
|
DEBUGASSERT(req);
|
|
|
|
gs2200m_printf("%s: called ****\n", __func__);
|
|
|
|
/* Check if this socket exists. */
|
|
|
|
usock = gs2200m_socket_get(priv, req->usockid);
|
|
|
|
if (!usock)
|
|
{
|
|
ret = -EBADFD;
|
|
goto prepare;
|
|
}
|
|
|
|
memset(&nmsg, 0, sizeof(nmsg));
|
|
nmsg.cid = usock->cid;
|
|
nmsg.local = true; /* Obtain local address & port */
|
|
|
|
ret = ioctl(priv->gsfd, GS2200M_IOC_NAME, (unsigned long)&nmsg);
|
|
|
|
prepare:
|
|
|
|
/* Prepare response. */
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.reqack.xid = req->head.xid;
|
|
resp.reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK;
|
|
resp.reqack.head.flags = 0;
|
|
resp.reqack.head.events = 0;
|
|
resp.reqack.result = ret;
|
|
|
|
if (0 == ret)
|
|
{
|
|
resp.valuelen_nontrunc = sizeof(nmsg.addr);
|
|
resp.valuelen = resp.valuelen_nontrunc;
|
|
|
|
if (resp.valuelen > req->max_addrlen)
|
|
{
|
|
resp.valuelen = req->max_addrlen;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
resp.valuelen_nontrunc = 0;
|
|
resp.valuelen = 0;
|
|
}
|
|
|
|
/* Send response. */
|
|
|
|
ret = _write_to_usock(fd, &resp, sizeof(resp));
|
|
|
|
if (0 > ret)
|
|
{
|
|
goto err_out;
|
|
}
|
|
|
|
if (resp.valuelen > 0)
|
|
{
|
|
/* Send address (value) */
|
|
|
|
ret = _write_to_usock(fd, &nmsg.addr, resp.valuelen);
|
|
|
|
if (0 > ret)
|
|
{
|
|
goto err_out;
|
|
}
|
|
}
|
|
|
|
err_out:
|
|
gs2200m_printf("%s: end\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: getpeername_request
|
|
****************************************************************************/
|
|
|
|
static int getpeername_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
FAR struct usrsock_request_getpeername_s *req = hdrbuf;
|
|
struct usrsock_message_datareq_ack_s resp;
|
|
FAR struct usock_s *usock;
|
|
int ret = 0;
|
|
|
|
DEBUGASSERT(priv);
|
|
DEBUGASSERT(req);
|
|
|
|
gs2200m_printf("%s: called ****\n", __func__);
|
|
|
|
/* Check if this socket exists. */
|
|
|
|
usock = gs2200m_socket_get(priv, req->usockid);
|
|
|
|
if (!usock)
|
|
{
|
|
ret = -EBADFD;
|
|
goto prepare;
|
|
}
|
|
|
|
if (CONNECTED != usock->state)
|
|
{
|
|
ret = -ENOTCONN;
|
|
}
|
|
|
|
prepare:
|
|
|
|
/* Prepare response. */
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.reqack.xid = req->head.xid;
|
|
resp.reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK;
|
|
resp.reqack.head.flags = 0;
|
|
resp.reqack.head.events = 0;
|
|
resp.reqack.result = ret;
|
|
|
|
if (0 == ret)
|
|
{
|
|
resp.valuelen_nontrunc = sizeof(usock->raddr);
|
|
resp.valuelen = resp.valuelen_nontrunc;
|
|
|
|
if (resp.valuelen > req->max_addrlen)
|
|
{
|
|
resp.valuelen = req->max_addrlen;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
resp.valuelen_nontrunc = 0;
|
|
resp.valuelen = 0;
|
|
}
|
|
|
|
/* Send response. */
|
|
|
|
ret = _write_to_usock(fd, &resp, sizeof(resp));
|
|
|
|
if (0 > ret)
|
|
{
|
|
goto err_out;
|
|
}
|
|
|
|
if (resp.valuelen > 0)
|
|
{
|
|
/* Send address (value) */
|
|
|
|
ret = _write_to_usock(fd, &usock->raddr, resp.valuelen);
|
|
|
|
if (0 > ret)
|
|
{
|
|
goto err_out;
|
|
}
|
|
}
|
|
|
|
err_out:
|
|
gs2200m_printf("%s: end\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: ioctl_request
|
|
****************************************************************************/
|
|
|
|
static int ioctl_request(int fd, FAR struct gs2200m_s *priv,
|
|
FAR void *hdrbuf)
|
|
{
|
|
FAR struct usrsock_request_ioctl_s *req = hdrbuf;
|
|
struct usrsock_message_req_ack_s resp;
|
|
struct usrsock_message_datareq_ack_s resp2;
|
|
struct gs2200m_ifreq_msg imsg;
|
|
uint8_t sock_type;
|
|
bool getreq = false;
|
|
int ret = -EINVAL;
|
|
|
|
memset(&imsg.ifr, 0, sizeof(imsg.ifr));
|
|
|
|
switch (req->cmd)
|
|
{
|
|
case SIOCGIFADDR:
|
|
case SIOCGIFFLAGS:
|
|
case SIOCGIFHWADDR:
|
|
case SIOCGIWNWID:
|
|
case SIOCGIWFREQ:
|
|
case SIOCGIWSENS:
|
|
getreq = true;
|
|
break;
|
|
|
|
case SIOCSIFADDR:
|
|
case SIOCSIFDSTADDR:
|
|
case SIOCSIFNETMASK:
|
|
|
|
read(fd, &imsg.ifr, sizeof(imsg.ifr));
|
|
break;
|
|
|
|
case SIOCDENYINETSOCK:
|
|
|
|
read(fd, &sock_type, sizeof(uint8_t));
|
|
|
|
if (sock_type == DENY_INET_SOCK_ENABLE)
|
|
{
|
|
/* Block to create INET socket */
|
|
|
|
priv->usock_enable = FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* Allow to create INET socket */
|
|
|
|
priv->usock_enable = TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
imsg.cmd = req->cmd;
|
|
ret = ioctl(priv->gsfd, GS2200M_IOC_IFREQ, (unsigned long)&imsg);
|
|
|
|
if (!getreq)
|
|
{
|
|
/* Send ACK response */
|
|
|
|
memset(&resp, 0, sizeof(resp));
|
|
resp.result = ret;
|
|
ret = _send_ack_common(fd, 0, req->head.xid, &resp);
|
|
|
|
if (0 > ret)
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if (getreq)
|
|
{
|
|
resp2.reqack.result = ret;
|
|
resp2.reqack.xid = req->head.xid;
|
|
resp2.reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK;
|
|
resp2.reqack.head.flags = 0;
|
|
resp2.reqack.head.events = 0;
|
|
resp2.valuelen_nontrunc = sizeof(imsg.ifr);
|
|
resp2.valuelen = sizeof(imsg.ifr);
|
|
|
|
_write_to_usock(fd, &resp2, sizeof(resp2));
|
|
|
|
/* Return struct ifreq address */
|
|
|
|
_write_to_usock(fd, &imsg.ifr, resp2.valuelen);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: gs2200m_loop
|
|
****************************************************************************/
|
|
|
|
static int gs2200m_loop(FAR struct gs2200m_s *priv)
|
|
{
|
|
struct gs2200m_assoc_msg amsg;
|
|
FAR struct usock_s *usock;
|
|
struct pollfd fds[2];
|
|
int fd[2];
|
|
char cid;
|
|
int ret;
|
|
|
|
fd[0] = open("/dev/usrsock", O_RDWR);
|
|
ASSERT(0 <= fd[0]);
|
|
|
|
fd[1] = open("/dev/gs2200m", O_RDWR);
|
|
ASSERT(0 <= fd[1]);
|
|
priv->gsfd = fd[1];
|
|
|
|
amsg.ssid = priv->ssid;
|
|
amsg.key = priv->key;
|
|
amsg.mode = priv->mode;
|
|
amsg.ch = priv->ch;
|
|
while (true)
|
|
{
|
|
ret = ioctl(priv->gsfd, GS2200M_IOC_ASSOC, (unsigned long)&amsg);
|
|
|
|
if (0 == ret)
|
|
{
|
|
break;
|
|
}
|
|
|
|
fprintf(stderr, "association failed : retrying\n");
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
memset(fds, 0, sizeof(fds));
|
|
|
|
/* Check events from usrsock and gs2200m */
|
|
|
|
fds[0].fd = fd[0];
|
|
fds[0].events = POLLIN;
|
|
fds[1].fd = fd[1];
|
|
fds[1].events = POLLIN;
|
|
|
|
ret = poll(fds, 2, -1);
|
|
ASSERT(0 < ret);
|
|
|
|
if (fds[0].revents & POLLIN)
|
|
{
|
|
ret = usrsock_handle_request(fd[0], priv);
|
|
ASSERT(0 == ret);
|
|
}
|
|
|
|
if (fds[1].revents & POLLIN)
|
|
{
|
|
gs2200m_printf("=== %s: event from /dev/gs2200m\n",
|
|
__func__);
|
|
|
|
/* retrieve cid from gs2200m driver */
|
|
|
|
cid = 'z';
|
|
ret = read(fd[1], &cid, sizeof(cid));
|
|
ASSERT(ret == sizeof(cid));
|
|
|
|
/* Check if all socket destroy or not */
|
|
|
|
if (cid == DISASSOCIATION_CID)
|
|
{
|
|
gs2200m_printf("=== %s: Disassocitaion event\n",
|
|
__func__);
|
|
|
|
/* To release sockets blocking in user-sock,
|
|
* send event to all opened sockets.
|
|
*/
|
|
|
|
usock_sendevent_toall(priv, fd[0]);
|
|
}
|
|
else
|
|
{
|
|
/* find usock by the cid */
|
|
|
|
usock = gs2200m_find_socket_by_cid(priv, cid);
|
|
|
|
if (NULL == usock)
|
|
{
|
|
gs2200m_printf("=== %s: cid=%c not found (ignored)\n",
|
|
__func__, cid);
|
|
}
|
|
else
|
|
{
|
|
/* send event to call xxxx_request() */
|
|
|
|
usock_send_event(fd[0], priv, usock,
|
|
USRSOCK_EVENT_RECVFROM_AVAIL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
close(fd[1]);
|
|
close(fd[0]);
|
|
|
|
gs2200m_printf("finished: ret=%d\n", __func__, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: _show_usage
|
|
****************************************************************************/
|
|
|
|
static void _show_usage(FAR char *cmd)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: %s [-a [ch]] ssid passphrase(key) \n\n", cmd);
|
|
fprintf(stderr,
|
|
"AP mode : specify -a option (optionally with channel) with ssid\n"
|
|
" and 8 to 63 ascii passphrase for WPA2-PSK\n"
|
|
" or 10 hex digits key for WEP\n");
|
|
fprintf(stderr,
|
|
"STA mode: specify ssid and passphrase for WPA/WPA2 PSK\n");
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
int main(int argc, FAR char *argv[])
|
|
{
|
|
int option;
|
|
int ret;
|
|
bool ap_mode = false;
|
|
|
|
if (_daemon)
|
|
{
|
|
fprintf(stderr, "%s is already running!\n", argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
_daemon = calloc(sizeof(struct gs2200m_s), 1);
|
|
ASSERT(_daemon);
|
|
|
|
_daemon->mode = 0; /* default mode = 0 (station) */
|
|
|
|
while ((option = getopt(argc, argv, "a:")) != ERROR)
|
|
{
|
|
switch (option)
|
|
{
|
|
case 'a':
|
|
_daemon->mode = 1; /* ap mode */
|
|
_daemon->ch = 1;
|
|
|
|
if (5 == argc)
|
|
{
|
|
_daemon->ch = (int)atoi(optarg);
|
|
}
|
|
|
|
ap_mode = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
_daemon->usock_enable = TRUE;
|
|
|
|
if ((ap_mode && (4 != argc) && (5 != argc))
|
|
|| (!ap_mode && 3 != argc))
|
|
{
|
|
_show_usage(argv[0]);
|
|
ret = ERROR;
|
|
goto errout;
|
|
}
|
|
|
|
_daemon->ssid = argv[argc - 2];
|
|
_daemon->key = argv[argc - 1];
|
|
|
|
ret = gs2200m_loop(_daemon);
|
|
|
|
errout:
|
|
if (_daemon)
|
|
{
|
|
free(_daemon);
|
|
_daemon = NULL;
|
|
}
|
|
|
|
return ret;
|
|
}
|