/**************************************************************************** * drivers/modem/alt1250/altcom_hdlr_socket.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 #include #include #include #include #include #include #include #include "altcom_cmd_sock.h" #include "altcom_errno.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define READSET_BIT (1 << 0) #define WRITESET_BIT (1 << 1) #define EXCEPTSET_BIT (1 << 2) #define ALTCOM_SO_SETMODE_8BIT (1) #define ALTCOM_SO_SETMODE_32BIT (2) #define ALTCOM_SO_SETMODE_LINGER (3) #define ALTCOM_SO_SETMODE_INADDR (4) #define ALTCOM_SO_SETMODE_IPMREQ (5) /**************************************************************************** * Private Functions ****************************************************************************/ static void sockaddr2altstorage(FAR const struct sockaddr *from, FAR struct altcom_sockaddr_storage *to) { FAR struct sockaddr_in *inaddr_from; FAR struct sockaddr_in6 *in6addr_from; FAR struct altcom_sockaddr_in *inaddr_to; FAR struct altcom_sockaddr_in6 *in6addr_to; if (from->sa_family == AF_INET) { inaddr_from = (FAR struct sockaddr_in *)from; inaddr_to = (FAR struct altcom_sockaddr_in *)to; inaddr_to->sin_len = sizeof(struct altcom_sockaddr_in); inaddr_to->sin_family = ALTCOM_AF_INET; inaddr_to->sin_port = inaddr_from->sin_port; memcpy(&inaddr_to->sin_addr, &inaddr_from->sin_addr, sizeof(struct altcom_in_addr)); } else if (from->sa_family == AF_INET6) { in6addr_from = (FAR struct sockaddr_in6 *)from; in6addr_to = (FAR struct altcom_sockaddr_in6 *)to; in6addr_to->sin6_len = sizeof(struct altcom_sockaddr_in6); in6addr_to->sin6_family = ALTCOM_AF_INET6; in6addr_to->sin6_port = in6addr_from->sin6_port; memcpy(&in6addr_to->sin6_addr, &in6addr_from->sin6_addr, sizeof(struct altcom_in6_addr)); } } static void altstorage2sockaddr( FAR const struct altcom_sockaddr_storage *from, FAR struct sockaddr *to) { FAR struct altcom_sockaddr_in *inaddr_from; FAR struct altcom_sockaddr_in6 *in6addr_from; FAR struct sockaddr_in *inaddr_to; FAR struct sockaddr_in6 *in6addr_to; if (from->ss_family == ALTCOM_AF_INET) { inaddr_from = (FAR struct altcom_sockaddr_in *)from; inaddr_to = (FAR struct sockaddr_in *)to; inaddr_to->sin_family = AF_INET; inaddr_to->sin_port = inaddr_from->sin_port; memcpy(&inaddr_to->sin_addr, &inaddr_from->sin_addr, sizeof(struct in_addr)); /* LwIP does not use this member, so it should be set to 0 */ memset(inaddr_to->sin_zero, 0, sizeof(inaddr_to->sin_zero)); } else if (from->ss_family == ALTCOM_AF_INET6) { in6addr_from = (FAR struct altcom_sockaddr_in6 *)from; in6addr_to = (FAR struct sockaddr_in6 *)to; in6addr_to->sin6_family = AF_INET6; in6addr_to->sin6_port = in6addr_from->sin6_port; memcpy(&in6addr_to->sin6_addr, &in6addr_from->sin6_addr, sizeof(struct in6_addr)); /* LwIP does not use thease members, so it should be set to 0 */ in6addr_to->sin6_flowinfo = 0; in6addr_to->sin6_scope_id = 0; } } static int flags2altflags(int32_t flags, FAR int32_t *altflags) { if (flags & (MSG_DONTROUTE | MSG_CTRUNC | MSG_PROXY | MSG_TRUNC | MSG_EOR | MSG_FIN | MSG_SYN | MSG_CONFIRM | MSG_RST | MSG_ERRQUEUE | MSG_NOSIGNAL)) { return -ENOPROTOOPT; } *altflags = 0; if (flags & MSG_PEEK) { *altflags |= ALTCOM_MSG_PEEK; } if (flags & MSG_WAITALL) { *altflags |= ALTCOM_MSG_WAITALL; } if (flags & MSG_OOB) { *altflags |= ALTCOM_MSG_OOB; } if (flags & MSG_DONTWAIT) { *altflags |= ALTCOM_MSG_DONTWAIT; } if (flags & MSG_MORE) { *altflags |= ALTCOM_MSG_MORE; } return 0; } static int get_so_setmode(uint16_t level, uint16_t option) { int setmode = 0; switch (level) { case SOL_SOCKET: switch (option) { case SO_ACCEPTCONN: case SO_ERROR: case SO_BROADCAST: case SO_KEEPALIVE: case SO_REUSEADDR: case SO_TYPE: case SO_RCVBUF: setmode = ALTCOM_SO_SETMODE_32BIT; break; #ifdef CONFIG_NET_SOLINGER case SO_LINGER: setmode = ALTCOM_SO_SETMODE_LINGER; break; #endif default: m_err("Not support option: %u\n", option); setmode = -EILSEQ; break; } break; case IPPROTO_IP: switch (option) { case IP_TOS: case IP_TTL: setmode = ALTCOM_SO_SETMODE_32BIT; break; case IP_MULTICAST_TTL: case IP_MULTICAST_LOOP: setmode = ALTCOM_SO_SETMODE_8BIT; break; case IP_MULTICAST_IF: setmode = ALTCOM_SO_SETMODE_INADDR; break; case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: setmode = ALTCOM_SO_SETMODE_IPMREQ; break; default: m_err("Not support option: %u\n", option); setmode = -EILSEQ; break; } break; case IPPROTO_TCP: switch (option) { case TCP_NODELAY: case TCP_KEEPIDLE: case TCP_KEEPINTVL: setmode = ALTCOM_SO_SETMODE_32BIT; break; default: m_err("Not support option: %u\n", option); setmode = -EILSEQ; break; } break; case IPPROTO_IPV6: switch (option) { case IPV6_V6ONLY: setmode = ALTCOM_SO_SETMODE_32BIT; break; default: m_err("Not support option: %u\n", option); setmode = -EILSEQ; break; } break; default: m_err("Not support level: %u\n", level); setmode = -EILSEQ; break; } return setmode; } static int32_t sockaddrlen_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz) { int32_t size = 0; FAR int16_t *usockid = (FAR int16_t *)arg[0]; FAR int16_t *addrlen = (FAR int16_t *)arg[1]; FAR struct altmdmpkt_sockaddrlen_s *out = (FAR struct altmdmpkt_sockaddrlen_s *)pktbuf; out->sockfd = htonl(*usockid); if (*addrlen == sizeof(struct sockaddr_in)) { out->addrlen = htonl(sizeof(struct altcom_sockaddr_in)); } else if (*addrlen == sizeof(struct sockaddr_in6)) { out->addrlen = htonl(sizeof(struct altcom_sockaddr_in6)); } else { size = -EINVAL; } if (size == 0) { size = sizeof(struct altmdmpkt_sockaddrlen_s); } return size; } static int32_t sockaddr_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz) { int32_t size = 0; FAR int16_t *usockid = (FAR int16_t *)arg[0]; FAR int16_t *addrlen = (FAR int16_t *)arg[1]; FAR struct sockaddr_storage *sa = (FAR struct sockaddr_storage *)arg[2]; FAR struct altmdmpkt_sockaddr_s *out = (FAR struct altmdmpkt_sockaddr_s *)pktbuf; struct altcom_sockaddr_storage altsa; out->sockfd = htonl(*usockid); if (*addrlen == sizeof(struct sockaddr_in)) { out->namelen = htonl(sizeof(struct altcom_sockaddr_in)); } else if (*addrlen == sizeof(struct sockaddr_in6)) { out->namelen = htonl(sizeof(struct altcom_sockaddr_in6)); } else { size = -EINVAL; } sockaddr2altstorage((struct sockaddr *)sa, &altsa); memcpy(&out->name, &altsa, sizeof(struct altcom_sockaddr_storage)); if (size == 0) { size = sizeof(struct altmdmpkt_sockaddr_s); } return size; } /**************************************************************************** * Public Functions ****************************************************************************/ int32_t altcom_socket_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; FAR int16_t *domain = (FAR int16_t *)arg[0]; FAR int16_t *type = (FAR int16_t *)arg[1]; FAR int16_t *protocol = (FAR int16_t *)arg[2]; FAR struct apicmd_socket_s *out = (FAR struct apicmd_socket_s *)pktbuf; /* convert domain */ if (*domain == PF_UNSPEC) { out->domain = htonl(ALTCOM_PF_UNSPEC); } else if (*domain == PF_INET) { out->domain = htonl(ALTCOM_PF_INET); } else if (*domain == PF_INET6) { out->domain = htonl(ALTCOM_PF_INET6); } else { size = -EAFNOSUPPORT; } /* convert type */ if (*type == SOCK_STREAM) { out->type = htonl(ALTCOM_SOCK_STREAM); } else if (*type == SOCK_DGRAM) { out->type = htonl(ALTCOM_SOCK_DGRAM); } else if (*type == SOCK_RAW) { out->type = htonl(ALTCOM_SOCK_RAW); } else { size = -EAFNOSUPPORT; } /* convert protocol */ if (*protocol == IPPROTO_IP) { out->protocol = htonl(ALTCOM_IPPROTO_IP); } else if (*protocol == IPPROTO_ICMP) { out->protocol = htonl(ALTCOM_IPPROTO_ICMP); } else if (*protocol == IPPROTO_TCP) { out->protocol = htonl(ALTCOM_IPPROTO_TCP); } else if (*protocol == IPPROTO_UDP) { out->protocol = htonl(ALTCOM_IPPROTO_UDP); } else if (*protocol == IPPROTO_IPV6) { out->protocol = htonl(ALTCOM_IPPROTO_IPV6); } else if (*protocol == IPPROTO_ICMP6) { out->protocol = htonl(ALTCOM_IPPROTO_ICMPV6); } else if (*protocol == IPPROTO_UDPLITE) { out->protocol = htonl(ALTCOM_IPPROTO_UDPLITE); } else if (*protocol == IPPROTO_RAW) { out->protocol = htonl(ALTCOM_IPPROTO_RAW); } else { size = -EAFNOSUPPORT; } if (size == 0) { size = sizeof(struct apicmd_socket_s); } *altcid = APICMDID_SOCK_SOCKET; return size; } int32_t altcom_close_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; FAR int16_t *usockid = (FAR int16_t *)arg[0]; FAR struct apicmd_close_s *out = (FAR struct apicmd_close_s *)pktbuf; out->sockfd = htonl(*usockid); size = sizeof(struct apicmd_close_s); *altcid = APICMDID_SOCK_CLOSE; return size; } int32_t altcom_accept_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; size = sockaddrlen_pkt_compose(arg, arglen, altver, pktbuf, pktsz); *altcid = APICMDID_SOCK_ACCEPT; return size; } int32_t altcom_bind_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; size = sockaddr_pkt_compose(arg, arglen, altver, pktbuf, pktsz); *altcid = APICMDID_SOCK_BIND; return size; } int32_t altcom_connect_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; size = sockaddr_pkt_compose(arg, arglen, altver, pktbuf, pktsz); *altcid = APICMDID_SOCK_CONNECT; return size; } int32_t altcom_fcntl_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; FAR int32_t *sockfd = (FAR int32_t *)arg[0]; FAR int32_t *cmd = (FAR int32_t *)arg[1]; FAR int32_t *val = (FAR int32_t *)arg[2]; FAR struct apicmd_fcntl_s *out = (FAR struct apicmd_fcntl_s *)pktbuf; out->sockfd = htonl(*sockfd); out->cmd = htonl(*cmd); out->val = htonl(*val); if (size == 0) { size = sizeof(struct apicmd_fcntl_s); } *altcid = APICMDID_SOCK_FCNTL; return size; } int32_t altcom_getsockname_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; size = sockaddrlen_pkt_compose(arg, arglen, altver, pktbuf, pktsz); *altcid = APICMDID_SOCK_GETSOCKNAME; return size; } int32_t altcom_getsockopt_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; FAR int32_t *sockfd = (FAR int32_t *)arg[0]; FAR int16_t *level = (FAR int16_t *)arg[1]; FAR int16_t *option = (FAR int16_t *)arg[2]; FAR uint16_t *max_valuelen = (FAR uint16_t *)arg[3]; FAR struct apicmd_getsockopt_s *out = (FAR struct apicmd_getsockopt_s *)pktbuf; out->sockfd = htonl(*sockfd); if (*level == SOL_SOCKET) { out->level = htonl(ALTCOM_SOL_SOCKET); out->optlen = htonl(*max_valuelen); if (*option == SO_ACCEPTCONN) { out->optname = htonl(ALTCOM_SO_ACCEPTCONN); } else if (*option == SO_ERROR) { out->optname = htonl(ALTCOM_SO_ERROR); } else if (*option == SO_BROADCAST) { out->optname = htonl(ALTCOM_SO_BROADCAST); } else if (*option == SO_KEEPALIVE) { out->optname = htonl(ALTCOM_SO_KEEPALIVE); } else if (*option == SO_REUSEADDR) { out->optname = htonl(ALTCOM_SO_REUSEADDR); } else if (*option == SO_TYPE) { out->optname = htonl(ALTCOM_SO_TYPE); } else if (*option == SO_RCVBUF) { out->optname = htonl(ALTCOM_SO_RCVBUF); } #ifdef CONFIG_NET_SOLINGER else if (*option == SO_LINGER) { out->optname = htonl(ALTCOM_SO_LINGER); } #endif else { size = -ENOPROTOOPT; } } else if (*level == IPPROTO_IP) { out->level = htonl(ALTCOM_IPPROTO_IP); out->optlen = htonl(*max_valuelen); if (*option == IP_TOS) { out->optname = htonl(ALTCOM_IP_TOS); } else if (*option == IP_TTL) { out->optname = htonl(ALTCOM_IP_TTL); } else if (*option == IP_MULTICAST_TTL) { out->optname = htonl(ALTCOM_IP_MULTICAST_TTL); } else if (*option == IP_MULTICAST_LOOP) { out->optname = htonl(ALTCOM_IP_MULTICAST_LOOP); } else if (*option == IP_MULTICAST_IF) { out->optname = htonl(ALTCOM_IP_MULTICAST_IF); } else { size = -ENOPROTOOPT; } } else if (*level == IPPROTO_TCP) { out->level = htonl(ALTCOM_IPPROTO_TCP); out->optlen = htonl(*max_valuelen); if (*option == TCP_NODELAY) { out->optname = htonl(ALTCOM_TCP_NODELAY); } else if (*option == TCP_KEEPIDLE) { out->optname = htonl(ALTCOM_TCP_KEEPIDLE); } else if (*option == TCP_KEEPINTVL) { out->optname = htonl(ALTCOM_TCP_KEEPINTVL); } else { size = -ENOPROTOOPT; } } else if (*level == IPPROTO_IPV6) { out->level = htonl(ALTCOM_IPPROTO_IPV6); out->optlen = htonl(*max_valuelen); if (*option == IPV6_V6ONLY) { out->optname = htonl(ALTCOM_IPV6_V6ONLY); } else { size = -ENOPROTOOPT; } } else { size = -ENOPROTOOPT; } if (size == 0) { size = sizeof(struct apicmd_getsockopt_s); } *altcid = APICMDID_SOCK_GETSOCKOPT; return size; } int32_t altcom_listen_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; FAR int32_t *sockfd = (FAR int32_t *)arg[0]; FAR uint16_t *backlog = (FAR uint16_t *)arg[1]; FAR struct apicmd_listen_s *out = (FAR struct apicmd_listen_s *)pktbuf; out->sockfd = htonl(*sockfd); out->backlog = htonl(*backlog); size = sizeof(struct apicmd_listen_s); *altcid = APICMDID_SOCK_LISTEN; return size; } int32_t altcom_recvfrom_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; FAR int32_t *sockfd = (FAR int32_t *)arg[0]; FAR int32_t *flags = (FAR int32_t *)arg[1]; FAR uint16_t *max_buflen = (FAR uint16_t *)arg[2]; FAR uint16_t *max_addrlen = (FAR uint16_t *)arg[3]; FAR struct apicmd_recvfrom_s *out = (FAR struct apicmd_recvfrom_s *)pktbuf; int32_t flg; out->sockfd = htonl(*sockfd); if (*max_buflen > APICMD_DATA_LENGTH) { /* Truncate the length to the maximum transfer size */ *max_buflen = APICMD_DATA_LENGTH; } out->recvlen = htonl(*max_buflen); size = flags2altflags(*flags, &flg); out->flags = htonl(flg); if (*max_addrlen == sizeof(struct sockaddr_in)) { out->fromlen = htonl(sizeof(struct altcom_sockaddr_in)); } else if (*max_addrlen == sizeof(struct sockaddr_in6)) { out->fromlen = htonl(sizeof(struct altcom_sockaddr_in6)); } else if (*max_addrlen == 0) { out->fromlen = htonl(0); } else { size = -EINVAL; } if (size == 0) { size = sizeof(struct apicmd_recvfrom_s); } *altcid = APICMDID_SOCK_RECVFROM; return size; } int32_t altcom_sendto_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; FAR int32_t *sockfd = (FAR int32_t *)arg[0]; FAR int32_t *flags = (FAR int32_t *)arg[1]; FAR uint16_t *addrlen = (FAR uint16_t *)arg[2]; FAR uint16_t *buflen = (FAR uint16_t *)arg[3]; FAR struct sockaddr_storage *sa = (FAR struct sockaddr_storage *)arg[4]; FAR uint8_t *buf = (FAR uint8_t *)arg[5]; FAR struct apicmd_sendto_s *out = (FAR struct apicmd_sendto_s *)pktbuf; int32_t flg; struct altcom_sockaddr_storage altsa; if (*buflen > APICMD_DATA_LENGTH) { /* Truncate the length to the maximum transfer size */ *buflen = APICMD_DATA_LENGTH; } else if (*buflen < 0) { size = -EINVAL; goto err_out; } if (*buflen > 0 && !buf) { size = -EINVAL; goto err_out; } if (sa && !(*addrlen)) { size = -EINVAL; goto err_out; } out->sockfd = htonl(*sockfd); size = flags2altflags(*flags, &flg); if (size != 0) { goto err_out; } out->flags = htonl(flg); out->datalen = htonl(*buflen); if (*addrlen == sizeof(struct sockaddr_in)) { out->tolen = htonl(sizeof(struct altcom_sockaddr_in)); } else if (*addrlen == sizeof(struct sockaddr_in6)) { out->tolen = htonl(sizeof(struct altcom_sockaddr_in6)); } else if (*addrlen == 0) { out->tolen = htonl(0); } else { size = -EINVAL; } if (size == 0) { memset(&altsa, 0, sizeof(struct altcom_sockaddr_storage)); sockaddr2altstorage((struct sockaddr *)sa, &altsa); memcpy(&out->to, &altsa, *addrlen); memcpy(out->senddata, buf, *buflen); size = sizeof(struct apicmd_sendto_s) - sizeof(out->senddata) + *buflen; } err_out: *altcid = APICMDID_SOCK_SENDTO; return size; } int32_t altcom_setsockopt_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; FAR int32_t *sockfd = (FAR int32_t *)arg[0]; FAR int16_t *level = (FAR int16_t *)arg[1]; FAR int16_t *option = (FAR int16_t *)arg[2]; FAR uint16_t *valuelen = (FAR uint16_t *)arg[3]; FAR uint8_t *value = (FAR uint8_t *)arg[4]; FAR struct apicmd_setsockopt_s *out = (FAR struct apicmd_setsockopt_s *)pktbuf; int setmode = 0; out->sockfd = htonl(*sockfd); if (*level == SOL_SOCKET) { out->level = htonl(ALTCOM_SOL_SOCKET); out->optlen = htonl(*valuelen); if (*option == SO_BROADCAST) { out->optname = htonl(ALTCOM_SO_BROADCAST); } else if (*option == SO_REUSEADDR) { out->optname = htonl(ALTCOM_SO_REUSEADDR); } else if (*option == SO_KEEPALIVE) { out->optname = htonl(ALTCOM_SO_KEEPALIVE); } else if (*option == SO_RCVBUF) { out->optname = htonl(ALTCOM_SO_RCVBUF); } #ifdef CONFIG_NET_SOLINGER else if (*option == SO_LINGER) { out->optname = htonl(ALTCOM_SO_LINGER); } #endif else { size = -ENOPROTOOPT; } } else if (*level == IPPROTO_IP) { out->level = htonl(ALTCOM_IPPROTO_IP); out->optlen = htonl(*valuelen); if (*option == IP_TOS) { out->optname = htonl(ALTCOM_IP_TOS); } else if (*option == IP_TTL) { out->optname = htonl(ALTCOM_IP_TTL); } else if (*option == IP_MULTICAST_TTL) { out->optname = htonl(ALTCOM_IP_MULTICAST_TTL); } else if (*option == IP_MULTICAST_LOOP) { out->optname = htonl(ALTCOM_IP_MULTICAST_LOOP); } else if (*option == IP_MULTICAST_IF) { out->optname = htonl(ALTCOM_IP_MULTICAST_IF); } else if (*option == IP_ADD_MEMBERSHIP) { out->optname = htonl(ALTCOM_IP_ADD_MEMBERSHIP); } else if (*option == IP_DROP_MEMBERSHIP) { out->optname = htonl(ALTCOM_IP_DROP_MEMBERSHIP); } else { size = -ENOPROTOOPT; } } else if (*level == IPPROTO_TCP) { out->level = htonl(ALTCOM_IPPROTO_TCP); out->optlen = htonl(*valuelen); if (*option == TCP_NODELAY) { out->optname = htonl(ALTCOM_TCP_NODELAY); } else if (*option == TCP_KEEPIDLE) { out->optname = htonl(ALTCOM_TCP_KEEPIDLE); } else if (*option == TCP_KEEPINTVL) { out->optname = htonl(ALTCOM_TCP_KEEPINTVL); } else if (*option == TCP_KEEPCNT) { out->optname = htonl(ALTCOM_TCP_KEEPCNT); } else { size = -ENOPROTOOPT; } } else if (*level == IPPROTO_IPV6) { out->level = htonl(ALTCOM_IPPROTO_IPV6); out->optlen = htonl(*valuelen); if (*option == IPV6_V6ONLY) { out->optname = htonl(ALTCOM_IPV6_V6ONLY); } else { size = -ENOPROTOOPT; } } else { size = -ENOPROTOOPT; } if (size < 0) { goto exit; } setmode = get_so_setmode(*level, *option); switch (setmode) { case ALTCOM_SO_SETMODE_8BIT: if (*valuelen < sizeof(int8_t)) { m_err("Unexpected valuelen: actual=%lu expect=%lu\n", *valuelen, sizeof(int8_t)); size = -EINVAL; break; } *out->optval = value[0]; break; case ALTCOM_SO_SETMODE_32BIT: if (*valuelen < sizeof(int32_t)) { m_err("Unexpected valuelen: actual=%lu expect=%lu\n", *valuelen, sizeof(int32_t)); size = -EINVAL; break; } *((FAR int32_t *)out->optval) = htonl(*((FAR int32_t *)value)); break; case ALTCOM_SO_SETMODE_LINGER: if (*valuelen < sizeof(struct linger)) { m_err("Unexpected valuelen: actual=%lu expect=%lu\n", *valuelen, sizeof(struct linger)); size = -EINVAL; break; } ((FAR struct altcom_linger *)out->optval)->l_onoff = htonl(((FAR struct linger *)value)->l_onoff); ((FAR struct altcom_linger *)out->optval)->l_linger = htonl(((FAR struct linger *)value)->l_linger); break; case ALTCOM_SO_SETMODE_INADDR: if (*valuelen < sizeof(struct in_addr)) { m_err("Unexpected valuelen: actual=%lu expect=%lu\n", *valuelen, sizeof(struct in_addr)); size = -EINVAL; break; } ((FAR struct altcom_in_addr *)out->optval)->s_addr = htonl(((FAR struct in_addr *)value)->s_addr); break; case ALTCOM_SO_SETMODE_IPMREQ: if (*valuelen < sizeof(struct ip_mreq)) { m_err("Unexpected valuelen: actual=%lu expect=%lu\n", *valuelen, sizeof(struct ip_mreq)); size = -EINVAL; break; } ((FAR struct altcom_ip_mreq *)out->optval)->imr_multiaddr.s_addr = htonl(((FAR struct ip_mreq *)value)->imr_multiaddr.s_addr); ((FAR struct altcom_ip_mreq *)out->optval)->imr_interface.s_addr = htonl(((FAR struct ip_mreq *)value)->imr_interface.s_addr); break; default: size = -EINVAL; break; } exit: if (size == 0) { size = sizeof(struct apicmd_setsockopt_s); } *altcid = APICMDID_SOCK_SETSOCKOPT; return size; } int32_t altcom_select_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { int32_t size = 0; FAR int32_t *request = (FAR int32_t *)arg[0]; FAR int32_t *id = (FAR int32_t *)arg[1]; FAR int32_t *maxfds = (FAR int32_t *)arg[2]; FAR uint16_t *used_setbit = (FAR uint16_t *)arg[3]; FAR altcom_fd_set *readset = (FAR altcom_fd_set *)arg[4]; FAR altcom_fd_set *writeset = (FAR altcom_fd_set *)arg[5]; FAR altcom_fd_set *exceptset = (FAR altcom_fd_set *)arg[6]; FAR struct apicmd_select_s *out = (FAR struct apicmd_select_s *)pktbuf; out->request = htonl(*request); out->id = htonl(*id); out->maxfds = htonl(*maxfds); out->used_setbit = htons(*used_setbit); memcpy(&out->readset, readset, sizeof(altcom_fd_set)); memcpy(&out->writeset, writeset, sizeof(altcom_fd_set)); memcpy(&out->exceptset, exceptset, sizeof(altcom_fd_set)); size = sizeof(struct apicmd_select_s); *altcid = APICMDID_SOCK_SELECT; return size; } int32_t altcom_shutdown_pkt_compose(FAR void **arg, size_t arglen, uint8_t altver, FAR uint8_t *pktbuf, const size_t pktsz, FAR uint16_t *altcid) { FAR int32_t sockfd = *((FAR int32_t *)arg[0]); FAR int32_t how = *((FAR int32_t *)arg[1]); FAR struct apicmd_shutdown_s *out = (FAR struct apicmd_shutdown_s *)pktbuf; switch (how) { case SHUT_RD: how = ALTCOM_SHUT_RD; break; case SHUT_WR: how = ALTCOM_SHUT_WR; break; case SHUT_RDWR: how = ALTCOM_SHUT_RDWR; break; default: return -EINVAL; } out->sockfd = htonl(sockfd); out->how = htonl(how); *altcid = APICMDID_SOCK_SHUTDOWN; return sizeof(struct apicmd_shutdown_s); } int32_t altcom_sockcomm_pkt_parse(FAR struct alt1250_dev_s *dev, FAR uint8_t *pktbuf, size_t pktsz, uint8_t altver, FAR void **arg, size_t arglen, FAR uint64_t *bitmap) { FAR int32_t *ret = (FAR int32_t *)arg[0]; FAR int32_t *errcode = (FAR int32_t *)arg[1]; FAR struct altmdmpktr_sockcomm_s *in = (FAR struct altmdmpktr_sockcomm_s *)pktbuf; *ret = ntohl(in->ret_code); *errcode = altcom_errno2nuttx(ntohl(in->err_code)); return 0; } int32_t altcom_scokaddr_pkt_parse(FAR struct alt1250_dev_s *dev, FAR uint8_t *pktbuf, size_t pktsz, uint8_t altver, FAR void **arg, size_t arglen, FAR uint64_t *bitmap) { int32_t rc = OK; FAR int32_t *ret = (FAR int32_t *)arg[0]; FAR int32_t *errcode = (FAR int32_t *)arg[1]; FAR uint32_t *addrlen = (FAR uint32_t *)arg[2]; FAR struct sockaddr_storage *sa = (FAR struct sockaddr_storage *)arg[3]; FAR struct altmdmpktr_sockaddr_s *in = (FAR struct altmdmpktr_sockaddr_s *)pktbuf; struct altcom_sockaddr_storage altsa; *ret = ntohl(in->ret_code); *errcode = altcom_errno2nuttx(ntohl(in->err_code)); if (*ret >= 0) { *addrlen = ntohl(in->addrlen); if (*addrlen == sizeof(struct altcom_sockaddr_in)) { *addrlen = sizeof(struct sockaddr_in); } else if (*addrlen == sizeof(struct altcom_sockaddr_in6)) { *addrlen = sizeof(struct sockaddr_in6); } else { rc = -EILSEQ; } memcpy(&altsa, &in->address, sizeof(struct altcom_sockaddr_storage)); altstorage2sockaddr(&altsa, (FAR struct sockaddr *)sa); } return rc; } int32_t altcom_getsockopt_pkt_parse(FAR struct alt1250_dev_s *dev, FAR uint8_t *pktbuf, size_t pktsz, uint8_t altver, FAR void **arg, size_t arglen, FAR uint64_t *bitmap) { int32_t rc = OK; FAR int32_t *ret = (FAR int32_t *)arg[0]; FAR int32_t *errcode = (FAR int32_t *)arg[1]; FAR uint32_t *optlen = (FAR uint32_t *)arg[2]; FAR int8_t *optval = (FAR int8_t *)arg[3]; FAR uint16_t *level = (FAR uint16_t *)arg[4]; FAR uint16_t *option = (FAR uint16_t *)arg[5]; FAR struct apicmd_getsockoptres_s *in = (FAR struct apicmd_getsockoptres_s *)pktbuf; int setmode = 0; *ret = ntohl(in->ret_code); *errcode = altcom_errno2nuttx(ntohl(in->err_code)); if (*ret >= 0) { *optlen = ntohl(in->optlen); if (*optlen > APICMD_OPTVAL_LENGTH) { rc = -EILSEQ; } else { setmode = get_so_setmode(*level, *option); switch (setmode) { case ALTCOM_SO_SETMODE_8BIT: if (*optlen < sizeof(int8_t)) { m_err("Unexpected optlen: actual=%lu expect=%lu\n", *optlen, sizeof(int8_t)); rc = -EILSEQ; break; } *optval = in->optval[0]; break; case ALTCOM_SO_SETMODE_32BIT: if (*optlen < sizeof(int32_t)) { m_err("Unexpected optlen: actual=%lu expect=%lu\n", *optlen, sizeof(int32_t)); rc = -EILSEQ; break; } *((FAR int32_t *)optval) = ntohl(*((FAR int32_t *)in->optval)); break; case ALTCOM_SO_SETMODE_LINGER: if (*optlen < sizeof(struct linger)) { m_err("Unexpected optlen: actual=%lu expect=%lu\n", *optlen, sizeof(struct linger)); rc = -EILSEQ; break; } FAR struct altcom_linger *plinger; plinger = (FAR struct altcom_linger *)&in->optval[0]; ((FAR struct linger *)optval)->l_onoff = ntohl(plinger->l_onoff); ((FAR struct linger *)optval)->l_linger = ntohl(plinger->l_linger); break; case ALTCOM_SO_SETMODE_INADDR: if (*optlen < sizeof(struct in_addr)) { m_err("Unexpected optlen: actual=%lu expect=%lu\n", *optlen, sizeof(struct in_addr)); rc = -EILSEQ; break; } FAR struct altcom_in_addr *pinaddr; pinaddr = (FAR struct altcom_in_addr *)&in->optval[0]; ((FAR struct in_addr *)optval)->s_addr = ntohl(pinaddr->s_addr); break; default: break; } } } return rc; } int32_t altcom_recvfrom_pkt_parse(FAR struct alt1250_dev_s *dev, FAR uint8_t *pktbuf, size_t pktsz, uint8_t altver, FAR void **arg, size_t arglen, FAR uint64_t *bitmap) { int32_t rc = OK; FAR int32_t *ret = (FAR int32_t *)arg[0]; FAR int32_t *errcode = (FAR int32_t *)arg[1]; FAR uint32_t *fromlen = (FAR uint32_t *)arg[2]; FAR struct sockaddr_storage *sa = (FAR struct sockaddr_storage *)arg[3]; FAR int8_t *buf = (FAR int8_t *)arg[4]; FAR struct apicmd_recvfromres_s *in = (FAR struct apicmd_recvfromres_s *)pktbuf; struct altcom_sockaddr_storage altsa; *ret = ntohl(in->ret_code); *errcode = altcom_errno2nuttx(ntohl(in->err_code)); if (*ret >= 0) { *fromlen = ntohl(in->fromlen); if (*fromlen == sizeof(struct altcom_sockaddr_in)) { *fromlen = sizeof(struct sockaddr_in); } else if (*fromlen == sizeof(struct altcom_sockaddr_in6)) { *fromlen = sizeof(struct sockaddr_in6); } else if (*fromlen != 0) { rc = -EILSEQ; } if ((rc == OK) && (*fromlen != 0)) { memcpy(&altsa, &in->from, *fromlen); altstorage2sockaddr(&altsa, (FAR struct sockaddr *)sa); } if (*ret > APICMD_DATA_LENGTH) { rc = -EILSEQ; } else { memcpy(buf, in->recvdata, *ret); } } return rc; } int32_t altcom_select_pkt_parse(FAR struct alt1250_dev_s *dev, FAR uint8_t *pktbuf, size_t pktsz, uint8_t altver, FAR void **arg, size_t arglen, FAR uint64_t *bitmap) { FAR int32_t *ret = (FAR int32_t *)arg[0]; FAR int32_t *errcode = (FAR int32_t *)arg[1]; FAR int32_t *id = (FAR int32_t *)arg[2]; FAR altcom_fd_set *readset = (FAR altcom_fd_set *)arg[3]; FAR altcom_fd_set *writeset = (FAR altcom_fd_set *)arg[4]; FAR altcom_fd_set *exceptset = (FAR altcom_fd_set *)arg[5]; FAR struct apicmd_selectres_s *in = (FAR struct apicmd_selectres_s *)pktbuf; uint16_t used_setbit; *ret = ntohl(in->ret_code); *errcode = altcom_errno2nuttx(ntohl(in->err_code)); if (*ret >= 0) { *id = ntohl(in->id); used_setbit = ntohs(in->used_setbit); memset(readset, 0, sizeof(altcom_fd_set)); memset(writeset, 0, sizeof(altcom_fd_set)); memset(exceptset, 0, sizeof(altcom_fd_set)); if (used_setbit & READSET_BIT) { memcpy(readset, &in->readset, sizeof(altcom_fd_set)); } if (used_setbit & WRITESET_BIT) { memcpy(writeset, &in->writeset, sizeof(altcom_fd_set)); } if (used_setbit & EXCEPTSET_BIT) { memcpy(exceptset, &in->exceptset, sizeof(altcom_fd_set)); } } return 0; }