7de8d0603f
When running a dual stack (usrsock daemon and kernel stack), ioctl requests that should be handled by the kernel stack are being processed by the usrsock daemon. This causes ifconfig and ifup to fail. The usrsock daemon that receives an ioctl request that should be handled by the kernel stack should reply with ENOTTY. Replying with ENOTTY means that the ioctl request can fall back to the kernel stack.
1860 lines
42 KiB
C
1860 lines
42 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;
|
|
bool drvreq = true;
|
|
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:
|
|
if (priv->usock_enable)
|
|
{
|
|
getreq = true;
|
|
}
|
|
else
|
|
{
|
|
ret = -ENOTTY;
|
|
drvreq = false;
|
|
}
|
|
break;
|
|
|
|
case SIOCSIFADDR:
|
|
case SIOCSIFDSTADDR:
|
|
case SIOCSIFNETMASK:
|
|
if (priv->usock_enable)
|
|
{
|
|
read(fd, &imsg.ifr, sizeof(imsg.ifr));
|
|
}
|
|
else
|
|
{
|
|
ret = -ENOTTY;
|
|
drvreq = false;
|
|
}
|
|
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:
|
|
if (!priv->usock_enable)
|
|
{
|
|
ret = -ENOTTY;
|
|
drvreq = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (drvreq)
|
|
{
|
|
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;
|
|
}
|