/**************************************************************************** * apps/lte/alt1250/usock_handlers/alt1250_sockethdlr.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 #include #include "alt1250_dbg.h" #include "alt1250_container.h" #include "alt1250_socket.h" #include "alt1250_devif.h" #include "alt1250_usockevent.h" #include "alt1250_postproc.h" #include "alt1250_usrsock_hdlr.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define IS_SUPPORTED_INET_DOMAIN(d) (((d) == AF_INET) || ((d) == AF_INET6)) /**************************************************************************** * Private Functions Prototypes ****************************************************************************/ static int postproc_getfl(FAR struct alt1250_s *dev, FAR struct alt_container_s *reply, FAR struct usock_s *usock, FAR int32_t *usock_result, FAR uint32_t *usock_xid, FAR struct usock_ackinfo_s *ackinfo, unsigned long arg); static int postproc_setfl(FAR struct alt1250_s *dev, FAR struct alt_container_s *reply, FAR struct usock_s *usock, FAR int32_t *usock_result, FAR uint32_t *usock_xid, FAR struct usock_ackinfo_s *ackinfo, unsigned long arg); /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * name: send_fctl_command ****************************************************************************/ static int send_fctl_command(FAR struct alt1250_s *dev, FAR struct alt_container_s *container, FAR struct usock_s *usock, int32_t cmd, int32_t val, FAR int32_t *usock_result) { int idx = 0; FAR void *inparam[3]; /* These members are referenced only when sending a command and * not when receiving a response, so local variables are used. */ inparam[0] = &USOCKET_ALTSOCKID(usock); inparam[1] = &cmd; inparam[2] = &val; USOCKET_SET_RESPONSE(usock, idx++, USOCKET_REP_RESULT(usock)); USOCKET_SET_RESPONSE(usock, idx++, USOCKET_REP_ERRCODE(usock)); set_container_ids(container, USOCKET_USOCKID(usock), LTE_CMDID_FCNTL); set_container_argument(container, inparam, nitems(inparam)); set_container_response(container, USOCKET_REP_RESPONSE(usock), idx); set_container_postproc(container, cmd == ALTCOM_SETFL ? postproc_setfl : cmd == ALTCOM_GETFL ? postproc_getfl : NULL, 0); return altdevice_send_command(dev, dev->altfd, container, usock_result); } /**************************************************************************** * name: postproc_setfl ****************************************************************************/ static int postproc_setfl(FAR struct alt1250_s *dev, FAR struct alt_container_s *reply, FAR struct usock_s *usock, FAR int32_t *usock_result, FAR uint32_t *usock_xid, FAR struct usock_ackinfo_s *ackinfo, unsigned long arg) { int ret = REP_SEND_ACK; FAR void **resp = CONTAINER_RESPONSE(reply); /* resp[0]: command return code * resp[1]: alt1250 errno */ dbg_alt1250("%s start\n", __func__); *usock_xid = USOCKET_XID(usock); *usock_result = COMBINE_ERRCODE(*(FAR int *)resp[0], *(FAR int *)resp[1]); if (*usock_result >= 0) { USOCKET_SET_STATE(usock, SOCKET_STATE_OPENED); usocket_commitstate(dev); switch (USOCKET_REQID(usock)) { case USRSOCK_REQUEST_SOCKET: *usock_result = USOCKET_USOCKID(usock); dbg_alt1250("allocated usockid: %d\n", *usock_result); break; /* Below cases are for SOCK_STREAM type socket * SOCK_STREAM type socket can not be opend on alt1250 side, * because of LAPI command. It is also using SOCK_STREAM * type socket to send ioctl() to communicate with daemon. * So, on BSD-socket spec, aftre socket() API succeeded, * connect(), bind(), etc, can be called. And on the call, * socket on alt1250 side should be fixed, therefore, * open_altsocket() will be called on those cases. */ case USRSOCK_REQUEST_CONNECT: ret = nextstep_connect(dev, reply, usock, usock_result, usock_xid, ackinfo, arg); break; case USRSOCK_REQUEST_BIND: ret = nextstep_bind(dev, reply, usock, usock_result, usock_xid, ackinfo, arg); break; case USRSOCK_REQUEST_LISTEN: ret = nextstep_listen(dev, reply, usock, usock_result, usock_xid, ackinfo, arg); break; case USRSOCK_REQUEST_SETSOCKOPT: ret = nextstep_setsockopt(dev, reply, usock, usock_result, usock_xid, ackinfo, arg); break; case USRSOCK_REQUEST_GETSOCKOPT: ret = nextstep_getsockopt(dev, reply, usock, usock_result, usock_xid, ackinfo, arg); break; case USRSOCK_REQUEST_GETSOCKNAME: ret = nextstep_getsockname(dev, reply, usock, usock_result, usock_xid, ackinfo, arg); break; default: dbg_alt1250("unexpected sequence. reqid:0x%02x\n", USOCKET_REQID(usock)); *usock_result = -EFAULT; break; } } else { USOCKET_SET_STATE(usock, SOCKET_STATE_PREALLOC); if (USOCKET_TYPE(usock) == SOCK_DGRAM) { usocket_free(usock); } usocket_commitstate(dev); } return ret; } /**************************************************************************** * name: postproc_getfl ****************************************************************************/ static int postproc_getfl(FAR struct alt1250_s *dev, FAR struct alt_container_s *reply, FAR struct usock_s *usock, FAR int32_t *usock_result, FAR uint32_t *usock_xid, FAR struct usock_ackinfo_s *ackinfo, unsigned long arg) { int ret = REP_SEND_ACK; FAR void **resp = CONTAINER_RESPONSE(reply); /* resp[0]: command return code * resp[1]: alt1250 errno */ dbg_alt1250("%s start\n", __func__); *usock_xid = USOCKET_XID(usock); *usock_result = COMBINE_ERRCODE(*(FAR int *)resp[0], *(FAR int *)resp[1]); if (*usock_result >= 0) { /* Set non-blocking flag of socket fd */ *usock_result |= ALTCOM_O_NONBLOCK; ret = send_fctl_command(dev, reply, usock, ALTCOM_SETFL, *usock_result, usock_result); } if (*usock_result < 0) { USOCKET_SET_STATE(usock, SOCKET_STATE_PREALLOC); if (USOCKET_TYPE(usock) == SOCK_DGRAM) { /* In DGRAM case, it is a part of socket() API sequence. * The socket() API is not returned on application layer. * So, internal socket should be free here. */ usocket_free(usock); } usocket_commitstate(dev); } return ret; } /**************************************************************************** * name: postproc_socket ****************************************************************************/ static int postproc_socket(FAR struct alt1250_s *dev, FAR struct alt_container_s *reply, FAR struct usock_s *usock, FAR int32_t *usock_result, FAR uint32_t *usock_xid, FAR struct usock_ackinfo_s *ackinfo, unsigned long arg) { int ret = REP_SEND_ACK; FAR void **resp = CONTAINER_RESPONSE(reply); /* resp[0]: altcom_sockfd * resp[1]: alt1250 errno */ dbg_alt1250("%s start\n", __func__); *usock_xid = USOCKET_XID(usock); *usock_result = COMBINE_ERRCODE(*(FAR int *)resp[0], *(FAR int *)resp[1]); if (*usock_result >= 0) { /* In case of success socket allocation */ USOCKET_SET_ALTSOCKID(usock, *usock_result); ret = send_fctl_command(dev, reply, usock, ALTCOM_GETFL, 0, usock_result); } if (*usock_result < 0) { USOCKET_SET_STATE(usock, SOCKET_STATE_PREALLOC); if (USOCKET_TYPE(usock) == SOCK_DGRAM) { /* In DGRAM case, it is a part of socket() API sequence. * The socket() API is not returned on application layer. * So, internal socket should be free here. */ usocket_free(usock); } usocket_commitstate(dev); } return ret; } /**************************************************************************** * name: send_socket_command ****************************************************************************/ static int send_socket_command(FAR struct alt1250_s *dev, FAR struct alt_container_s *container, FAR struct usock_s *usock, int16_t domain, int16_t type, int16_t protocol, FAR int32_t *usock_result) { int idx = 0; FAR void *inparam[3]; /* These members are referenced only when sending a command and * not when receiving a response, so local variables are used. */ inparam[0] = &domain; inparam[1] = &type; inparam[2] = &protocol; USOCKET_SET_RESPONSE(usock, idx++, USOCKET_REP_RESULT(usock)); USOCKET_SET_RESPONSE(usock, idx++, USOCKET_REP_ERRCODE(usock)); set_container_ids(container, USOCKET_USOCKID(usock), LTE_CMDID_SOCKET); set_container_argument(container, inparam, nitems(inparam)); set_container_response(container, USOCKET_REP_RESPONSE(usock), idx); set_container_postproc(container, postproc_socket, 0); return altdevice_send_command(dev, dev->altfd, container, usock_result); } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * name: open_altsocket ****************************************************************************/ int open_altsocket(FAR struct alt1250_s *dev, FAR struct alt_container_s *container, FAR struct usock_s *usock, FAR int32_t *usock_result) { int ret; dbg_alt1250("%s start\n", __func__); ret = send_socket_command(dev, container, usock, USOCKET_DOMAIN(usock), USOCKET_TYPE(usock), USOCKET_PROTOCOL(usock), usock_result); if (*usock_result >= 0) { USOCKET_SET_STATE(usock, SOCKET_STATE_OPEN); usocket_commitstate(dev); } return ret; } /**************************************************************************** * name: usockreq_socket ****************************************************************************/ int usockreq_socket(FAR struct alt1250_s *dev, FAR struct usrsock_request_buff_s *req, FAR int32_t *usock_result, FAR uint32_t *usock_xid, FAR struct usock_ackinfo_s *ackinfo) { FAR struct usrsock_request_socket_s *request = &req->request.sock_req; FAR struct usock_s *usock; FAR struct alt_container_s *container; int ret = REP_SEND_ACK_WOFREE; dbg_alt1250("%s start type=%d\n", __func__, request->type); *usock_xid = request->head.xid; if (!IS_SUPPORTED_INET_DOMAIN(request->domain)) { dbg_alt1250("Not support this domain: %u\n", request->domain); *usock_result = -EAFNOSUPPORT; return REP_SEND_ACK_WOFREE; } else if (!dev->usock_enable && IS_SUPPORTED_INET_DOMAIN(request->domain) && request->type != SOCK_CTRL) { /* If domain is AF_INET while usock_enable is false, * set usockid to -ENOTSUP to fallback kernel * network stack. */ *usock_result = -ENOTSUP; return REP_SEND_ACK_WOFREE; } if (!dev->api_enable) { dbg_alt1250("Don't allow to call any API now.\n"); *usock_result = -EBUSY; return REP_SEND_ACK_WOFREE; } usock = usocket_alloc(dev, request->type); if (usock == NULL) { dbg_alt1250("socket alloc faild\n"); *usock_result = -EBUSY; return REP_SEND_ACK_WOFREE; } *usock_result = USOCKET_USOCKID(usock); USOCKET_SET_REQUEST(usock, request->head.reqid, request->head.xid); USOCKET_SET_SOCKTYPE(usock, request->domain, request->type, request->protocol); switch (request->type) { case SOCK_STREAM: case SOCK_CTRL: dbg_alt1250("allocated usockid: %d\n", *usock_result); break; case SOCK_SMS: ret = alt1250_sms_init(dev, usock, usock_result, ackinfo); if (*usock_result < 0) { usocket_free(usock); } break; case SOCK_DGRAM: case SOCK_RAW: dbg_alt1250("allocated usockid: %d\n", *usock_result); container = container_alloc(); if (container == NULL) { dbg_alt1250("no container\n"); usocket_free(usock); return REP_NO_CONTAINER; } ret = open_altsocket(dev, container, usock, usock_result); if (IS_NEED_CONTAINER_FREE(ret)) { container_free(container); } if (*usock_result < 0) { usocket_free(usock); } break; default: dbg_alt1250("Not support this type: %u\n", request->type); *usock_result = -EAFNOSUPPORT; usocket_free(usock); break; } return ret; }