diff --git a/include/netpacket/netlink.h b/include/netpacket/netlink.h index 8e52eeaa04..ec82df15f6 100644 --- a/include/netpacket/netlink.h +++ b/include/netpacket/netlink.h @@ -48,6 +48,7 @@ ****************************************************************************/ /* Netlink socket protocols *************************************************/ + /* The AF_NETLINK family offers multiple protocol subsets. Each interfaces * to a different kernel component and has a different messaging subset. The * subset is referenced by the protocol field in the socket call: @@ -55,25 +56,36 @@ * int socket(AF_NETLINK, SOCK_DGRAM or SOCK_RAW, protocol) * * Ref. Wikipedia.org + * + * Namespace is Linux compatible. */ -#define NETLINK_ROUTE 0 /* Routing/device hook for user-space - * routing daemons */ -#define NETLINK_FIREWALL 1 /* Interface to receive packets from - * the firewall */ -#define NETLINK_NFLOG 2 /* netfilter/iptables ULOG */ -#define NETLINK_ARPD 3 /* Interface to manage the ARP table */ -#define NETLINK_AUDIT 4 /* Interface to auditing sub-system */ -#define NETLINK_IP6_FW 5 /* Interface to transport packets from - * netfilter to user-space. */ -#define NETLINK_ROUTE6 6 -#define NETLINK_TAPBASE 7 -#define NETLINK_NETFILTER 8 -#define NETLINK_TCPDIAG 9 -#define NETLINK_XFRM 10 /* Interface to IPsec security databases - * for key-manager daemons using the Internet - * Key Exchange protocol. */ -#define NETLINK_USERSOCK 11 /* Reserved for user mode socket protocols */ +#define NETLINK_ROUTE 0 /* Routing/device hook for user-space + * routing daemons (default) */ +#define NETLINK_USERSOCK 1 /* Reserved for user mode socket protocols */ +#define NETLINK_FIREWALL 2 /* Interface to receive packets from + * the firewall */ +#define NETLINK_SOCK_DIAG 3 /* Socket monitoring */ +#define NETLINK_NFLOG 4 /* netfilter/iptables ULOG */ +#define NETLINK_XFRM 5 /* Interface to IPsec security databases + * for key-manager daemons using the Internet + * Key Exchange protocol. */ +#define NETLINK_ISCSI 6 /* Open-iSCSI */ +#define NETLINK_AUDIT 7 /* Interface to auditing sub-system */ +#define NETLINK_FIB_LOOKUP 8 +#define NETLINK_CONNECTOR 9 +#define NETLINK_NETFILTER 10 /* netfilter subsystem */ +#define NETLINK_IP6_FW 11 /* Interface to transport packets from + * netfilter to user-space. */ +#define NETLINK_DNRTMSG 12 /* DECnet routing messages */ +#define NETLINK_KOBJECT_UEVENT 13 /* Kernel messages to userspace */ +#define NETLINK_GENERIC 14 + /* NETLINK_DM (DM Events) */ +#define NETLINK_SCSITRANSPORT 16 /* SCSI Transports */ +#define NETLINK_ECRYPTFS 17 +#define NETLINK_RDMA 18 +#define NETLINK_CRYPTO 19 /* Crypto layer */ +#define NETLINK_SMC 20 /* SMC monitoring */ /* NETLINK_ROUTE protocol message types *************************************/ /* Link layer: @@ -218,6 +230,7 @@ #define NLM_F_ACK_TLVS 0x0200 /* extended ACK TVLs were included */ /* Definitions for struct rtattr ********************************************/ + /* Macros to handle rtattributes */ #define RTA_ALIGNTO 4 @@ -235,6 +248,7 @@ #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0)) /* Definitions for struct ifaddrmsg ****************************************/ + /* ifa_flags definitions: ifa_flags is a flag word of IFA_F_SECONDARY for * secondary address (old alias interface), IFA_F_PERMANENT for a permanent * address set by the user and other undocumented flags. @@ -243,6 +257,17 @@ #define IFA_F_SECONDARY 0x01 #define IFA_F_PERMANENT 0x02 +/* Common message helper macros ********************************************/ + +#define NLMSG_MASK (sizeof(uint32_t) - 1) +#define NLMSG_ALIGN(n) (((n) + NLMSG_MASK) & ~NLMSG_MASK) +#define NLMSG_HDRLEN sizeof(struct nlmsghdr) +#define NLMSG_LENGTH(n) (NLMSG_HDRLEN + (n)) +#define NLMSG_DATA(hdr) ((FAR void*)(((FAR char*)hdr) + NLMSG_HDRLEN) +#define NLMSG_NEXT(hdr,n) \ + ((n) -= NLMSG_ALIGN((hdr)->nlmsg_len), \ + (FAR struct nlmsghdr*)(((FAR cha r*)(hdr)) + NLMSG_ALIGN((hdr)->nlmsg_len))) + /**************************************************************************** * Public Type Definitions ****************************************************************************/ @@ -316,6 +341,22 @@ struct ifaddrmsg int16_t ifa_index; /* Unique interface index */ }; +/* RTM_NEWNEIGH, RTM_DELNEIGH, RTM_GETNEIGH + * Add, remove or receive information about a neighbor table entry (e.g., + * an ARP entry). The message contains an ndmsg structure. + */ + +struct ndmsg +{ + uint8_t ndm_family; + uint8_t ndm_pad1; + uint16_t ndm_pad2; + int32_t ndm_ifindex; + uint16_t ndm_state; + uint8_t ndm_flags; + uint8_t ndm_type; +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ diff --git a/net/arp/arp.h b/net/arp/arp.h index 307c498931..5eee6864c0 100644 --- a/net/arp/arp.h +++ b/net/arp/arp.h @@ -416,6 +416,31 @@ int arp_update(in_addr_t ipaddr, FAR uint8_t *ethaddr); void arp_hdr_update(FAR uint16_t *pipaddr, FAR uint8_t *ethaddr); +/**************************************************************************** + * Name: arp_snapshot + * + * Description: + * Take a snapshot of the current state of the ARP table. + * + * Input Parameters: + * snapshot - Location to return the ARP table copy + * nentries - The size of the user provided 'dest' in entries, each of + * size sizeof(struct arp_entry_s) + * + * Returned Value: + * On success, the number of entries actually copied is returned. Unused + * entries are not returned. + * + * Assumptions + * The network is locked to assure exclusive access to the ARP table + * + ****************************************************************************/ + +#ifdef CONFIG_NETLINK_ROUTE +unsigned int arp_snapshot(FAR struct arp_entry_s *snapshot, + unsigned int nentries); +#endif + /**************************************************************************** * Name: arp_dump * diff --git a/net/arp/arp_table.c b/net/arp/arp_table.c index 9ab9c58bbe..030b686264 100644 --- a/net/arp/arp_table.c +++ b/net/arp/arp_table.c @@ -393,6 +393,56 @@ void arp_delete(in_addr_t ipaddr) } } +/**************************************************************************** + * Name: arp_snapshot + * + * Description: + * Take a snapshot of the current state of the ARP table. + * + * Input Parameters: + * snapshot - Location to return the ARP table copy + * nentries - The size of the user provided 'dest' in entries, each of + * size sizeof(struct arp_entry_s) + * + * Returned Value: + * On success, the number of entries actually copied is returned. Unused + * entries are not returned. + * + * Assumptions + * The network is locked to assure exclusive access to the ARP table + * + ****************************************************************************/ + +#ifdef CONFIG_NETLINK_ROUTE +unsigned int arp_snapshot(FAR struct arp_entry_s *snapshot, + unsigned int nentries) +{ + FAR struct arp_entry_s *tabptr; + clock_t now; + unsigned int ncopied; + int i; + + /* Copy all non-empty, non-expired entries in the ARP table. */ + + for (i = 0, now = clock_systimer(), ncopied = 0; + nentries > ncopied && i < CONFIG_NET_ARPTAB_SIZE; + i++) + { + tabptr = &g_arptable[i]; + if (tabptr->at_ipaddr == 0 && + now - tabptr->at_time <= ARP_MAXAGE_TICK) + { + memcpy(&snapshot[ncopied], tabptr, sizeof(struct arp_entry_s)); + ncopied++; + } + } + + /* Not found */ + + return ncopied; +} +#endif + #endif /* CONFIG_NET_ARP */ #endif /* CONFIG_NET */ diff --git a/net/netlink/Kconfig b/net/netlink/Kconfig index 816384397c..bbaa065013 100644 --- a/net/netlink/Kconfig +++ b/net/netlink/Kconfig @@ -17,10 +17,19 @@ config NET_NETLINK if NET_NETLINK -config NET_NETLINK_CONNS +config NETLINK_CONNS int "Number of netlink connections" default 4 ---help--- Maximum number of netlink connections (all tasks). +menu "Netlink Protocols" + +config NETLINK_ROUTE + bool "Netlink Route protocol" + default n + ---help--- + Support the NETLINK_ROUTE protocol option. + +endmenu # Netlink Protocols endif # NET_NETLINK diff --git a/net/netlink/Make.defs b/net/netlink/Make.defs index 7b3f7e7ce6..b80690aadd 100644 --- a/net/netlink/Make.defs +++ b/net/netlink/Make.defs @@ -37,7 +37,12 @@ ifeq ($(CONFIG_NET_NETLINK),y) -SOCK_CSRCS += netlink_sockif.c netlink_conn.c +SOCK_CSRCS += netlink_sockif.c +NET_CSRCS += netlink_conn.c + +ifeq ($(CONFIG_NETLINK_ROUTE),y) +NET_CSRCS += netlink_route.c +endif # Include netlink build support diff --git a/net/netlink/netlink.h b/net/netlink/netlink.h index fdf2d6de56..967c0f173d 100644 --- a/net/netlink/netlink.h +++ b/net/netlink/netlink.h @@ -46,6 +46,8 @@ #include #include +#include + #include "devif/devif.h" #include "socket/socket.h" @@ -59,6 +61,25 @@ * Public Type Definitions ****************************************************************************/ +/* Netlink uses a two step, request-get, referenced by a user managed + * sequence number. This means that the requested data must be buffered + * until it is gotten by the client. This structure holds that buffered + * data. + * + * REVISIT: There really should be a timestamp on this so that we can + * someday weed out un-claimed responses. + */ + +struct netlink_response_s +{ + FAR struct netlink_response_s *flink; + FAR struct nlmsghdr msg; +}; + +#define SIZEOF_NETLINK_RESPONSE_S(n) (sizeof(struct netlink_response_s) + (n) - 1) + +/* This "connection" structure describes the underlying state of the socket. */ + struct netlink_conn_s { /* Common prologue of all connection structures. */ @@ -74,7 +95,14 @@ struct netlink_conn_s /* Netlink-specific content follows */ + uint32_t pid; /* Port ID (if bound) */ + uint32_t groups; /* Multicast groups mask (if bound) */ uint8_t crefs; /* Reference counts on this instance */ + uint8_t protocol; /* See NETLINK_* definitions */ + + /* Buffered response data */ + + FAR struct netlink_response_s *resplist; }; /**************************************************************************** @@ -95,6 +123,8 @@ EXTERN const struct sock_intf_s g_netlink_sockif; * Public Function Prototypes ****************************************************************************/ +struct sockaddr_nl; /* Forward reference */ + /**************************************************************************** * Name: netlink_initialize() * @@ -148,12 +178,71 @@ FAR struct netlink_conn_s *netlink_nextconn(FAR struct netlink_conn_s *conn); * Find a connection structure that is the appropriate connection for the * provided netlink address * + ****************************************************************************/ + +FAR struct netlink_conn_s *netlink_active(FAR struct sockaddr_nl *addr); + +/**************************************************************************** + * Name: netlink_add_response + * + * Description: + * Add response data at the head of the pending response list. + * * Assumptions: + * The caller has the network locked to prevent concurrent access to the + * socket. * ****************************************************************************/ -struct sockaddr_nl; /* Forward reference */ -FAR struct netlink_conn_s *netlink_active(FAR struct sockaddr_nl *addr); +void netlink_add_response(FAR struct socket *psock, + FAR struct netlink_response_s *resp); + +/**************************************************************************** + * Name: netlink_get_response + * + * Description: + * Find the response matching the request. Remove it from the list of + * pending responses and return the response data. + * + * Assumptions: + * The caller has the network locked to prevent concurrent access to the + * socket. + * + ****************************************************************************/ + +FAR struct netlink_response_s * + netlink_get_response(FAR struct socket *psock, FAR struct nlmsghdr *nlmsg); + +/**************************************************************************** + * Name: netlink_route_sendto() + * + * Description: + * Perform the sendto() operation for the NETLINK_ROUTE protocol. + * + ****************************************************************************/ + +#ifdef CONFIG_NETLINK_ROUTE +ssize_t netlink_route_sendto(FAR struct socket *psock, + FAR const struct nlmsghdr *nlmsg, + size_t len, int flags, + FAR const struct sockaddr_nl *to, + socklen_t tolen); +#endif + +/**************************************************************************** + * Name: netlink_route_recvfrom() + * + * Description: + * Perform the recvfrom() operation for the NETLINK_ROUTE protocol. + * + ****************************************************************************/ + +#ifdef CONFIG_NETLINK_ROUTE +ssize_t netlink_route_recvfrom(FAR struct socket *psock, + FAR struct nlmsghdr *nlmsg, + size_t len, int flags, + FAR struct sockaddr_nl *from); +#endif #undef EXTERN #ifdef __cplusplus diff --git a/net/netlink/netlink_conn.c b/net/netlink/netlink_conn.c index 46b873d674..3d4eee67d0 100644 --- a/net/netlink/netlink_conn.c +++ b/net/netlink/netlink_conn.c @@ -61,7 +61,7 @@ /* The array containing all netlink connections. */ -static struct netlink_conn_s g_netlink_connections[CONFIG_NET_NETLINK_CONNS]; +static struct netlink_conn_s g_netlink_connections[CONFIG_NETLINK_CONNS]; /* A list of all free netlink connections */ @@ -128,7 +128,7 @@ void netlink_initialize(void) dq_init(&g_active_netlink_connections); nxsem_init(&g_free_sem, 0, 1); - for (i = 0; i < CONFIG_NET_NETLINK_CONNS; i++) + for (i = 0; i < CONFIG_NETLINK_CONNS; i++) { FAR struct netlink_conn_s *conn = &g_netlink_connections[i]; @@ -226,7 +226,7 @@ FAR struct netlink_conn_s *netlink_nextconn(FAR struct netlink_conn_s *conn) } /**************************************************************************** - * Name: netlink_active() + * Name: netlink_active * * Description: * Find a connection structure that is the appropriate connection for the @@ -243,4 +243,89 @@ FAR struct netlink_conn_s *netlink_active(FAR struct sockaddr_nl *addr) return NULL; } +/**************************************************************************** + * Name: netlink_add_response + * + * Description: + * Add response data at the head of the pending response list. + * + * Assumptions: + * The caller has the network locked to prevent concurrent access to the + * socket. + * + ****************************************************************************/ + +void netlink_add_response(FAR struct socket *psock, + FAR struct netlink_response_s *resp) +{ + FAR struct netlink_conn_s *conn; + + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && resp != NULL); + + conn = (FAR struct netlink_conn_s *)psock->s_conn; + resp->flink = conn->resplist; + conn->resplist = resp; +} + +/**************************************************************************** + * Name: netlink_get_response + * + * Description: + * Find the response matching the request. Remove it from the list of + * pending responses and return the response data. + * + * Assumptions: + * The caller has the network locked to prevent concurrent access to the + * socket. + * + ****************************************************************************/ + +FAR struct netlink_response_s * + netlink_get_response(FAR struct socket *psock, FAR struct nlmsghdr *nlmsg) +{ + FAR struct netlink_conn_s *conn; + FAR struct netlink_response_s *curr; + FAR struct netlink_response_s *prev; + + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && nlmsg != NULL); + + conn = (FAR struct netlink_conn_s *)psock->s_conn; + + /* Search the pending response data for this socket and find the entry + * with the matching sequence. Here is is assumed that the sequence + * number is unique and, hence, it is not necessary to verify other + * information. + */ + + for (prev = NULL, curr = conn->resplist; + curr != NULL; + prev = curr, curr = curr->flink) + { + /* Check for a matching sequence number */ + + if (curr->msg.nlmsg_seq == nlmsg->nlmsg_seq) + { + /* We have a match */ + + DEBUGASSERT(curr->msg.nlmsg_type == nlmsg->nlmsg_type); + + /* Remove the entry from the list and return it */ + + if (prev != NULL) + { + prev->flink = curr->flink; + } + else + { + conn->resplist = curr->flink; + } + + curr->flink = NULL; + return curr; + } + } + + return NULL; +} + #endif /* CONFIG_NET_NETLINK */ diff --git a/net/netlink/netlink_route.c b/net/netlink/netlink_route.c new file mode 100644 index 0000000000..aff21504b6 --- /dev/null +++ b/net/netlink/netlink_route.c @@ -0,0 +1,262 @@ +/**************************************************************************** + * net/netlink/netlink_route.c + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "arp/arp.h" +#include "netlink/netlink.h" + +#ifdef CONFIG_NETLINK_ROUTE + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +#define IFA_RTA(r) \ + ((FAR struct rtattr *)(((FAR char *)(r)) + \ + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) +#define IFA_PAYLOAD(n) \ + NLMSG_PAYLOAD(n, sizeof(struct ifaddrmsg)) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* RTM_NEWNEIGH, RTM_DELNEIGH, RTM_GETNEIGH + * Add, remove or receive information about a neighbor table entry (e.g., + * an ARP entry). The message contains an ndmsg structure. + */ + +struct nlroute_sendto_request_s +{ + struct nlmsghdr hdr; + struct ndmsg msg; + uint8_t data[1]; +}; + +#define SIZEOF_NLROUTE_SENDTO_REQUEST_S(n) \ + (sizeof(struct nlroute_sendto_request_s) + (n) - 1) + +struct nlroute_recvfrom_response_s +{ + FAR struct netlink_reqdata_s *flink; + struct nlmsghdr hdr; + struct ndmsg msg; + struct rtattr attr; + uint8_t data[1]; +}; + +#define SIZEOF_NLROUTE_RECVFROM_RESPONSE_S(n) \ + (sizeof(struct nlroute_recvfrom_response_s) + (n) - 1) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: netlink_route_sendto() + * + * Description: + * Perform the sendto() operation for the NETLINK_ROUTE protocol. + * + ****************************************************************************/ + +ssize_t netlink_route_sendto(FAR struct socket *psock, + FAR const struct nlmsghdr *nlmsg, + size_t len, int flags, + FAR const struct sockaddr_nl *to, + socklen_t tolen) +{ + FAR const struct nlroute_sendto_request_s *req; + + DEBUGASSERT(psock != NULL && nlmsg != NULL && + nlmsg->nlmsg_len >= sizeof(struct nlmsghdr) && + len >= sizeof(struct nlmsghdr) && + len >= nlmsg->nlmsg_len && to != NULL && + tolen >= sizeof(struct sockaddr_nl)); + + req = (FAR const struct nlroute_sendto_request_s *)nlmsg; + +#ifdef CONFIG_NET_ARP + /* REVISIT: Currently, the only operation supported is retrieving the + * ARP table in its entirety. + */ + + if (req->hdr.nlmsg_type == RTM_GETNEIGH && req->msg.ndm_family == AF_INET) + { + FAR struct nlroute_recvfrom_response_s *entry; + unsigned int ncopied; + size_t tabsize; + size_t paysize; + size_t entsize; + + /* Preallocate memory to hold the maximum sized ARP table + * REVISIT: This is probably excessively large and could cause false + * memory out conditions. A better approach would be to actually count + * the number of valid entries in the ARP table. + */ + + tabsize = CONFIG_NET_ARPTAB_SIZE * sizeof( struct arp_entry_s); + paysize = SIZEOF_NLROUTE_RECVFROM_RESPONSE_S(tabsize); + entsize = SIZEOF_NETLINK_RESPONSE_S(paysize); + + entry = (FAR struct nlroute_recvfrom_response_s *)kmm_malloc(entsize); + if (entry == NULL) + { + return -ENOMEM; + } + + /* Populate the entry */ + + memcpy(&entry->hdr, &req->hdr, sizeof(struct nlmsghdr)); + entry->hdr.nlmsg_len = paysize; + memcpy(&entry->msg, &req->msg, sizeof(struct ndmsg)); + entry->attr.rta_len = tabsize; + entry->attr.rta_type = 0; + + /* Lock the network so that the ARP table will be stable, then copy + * the ARP table into the allocated memory. + */ + + net_lock(); + ncopied = arp_snapshot((FAR struct arp_entry_s *)entry->data, + CONFIG_NET_ARPTAB_SIZE); + net_unlock(); + + /* Now we have the real number of valid entries in the ARP table and + * we can trim the allocation. + */ + + if (ncopied < CONFIG_NET_ARPTAB_SIZE) + { + FAR struct nlroute_recvfrom_response_s *newentry; + + tabsize = ncopied * sizeof( struct arp_entry_s); + paysize = SIZEOF_NLROUTE_RECVFROM_RESPONSE_S(tabsize); + entsize = SIZEOF_NETLINK_RESPONSE_S(paysize); + + newentry = (FAR struct nlroute_recvfrom_response_s *) + kmm_realloc(entry, entsize); + + if (newentry != NULL) + { + entry = newentry; + } + + entry->hdr.nlmsg_len = paysize; + entry->attr.rta_len = tabsize; + } + + /* Finally, add the data to the list of pending responses */ + + netlink_add_response(psock, (FAR struct netlink_response_s *)entry); + return OK; + } + +#else + UNUSED(req); +#endif + + /* REVISIT: Not implemented */ + + return -ENOSYS; +} + +/**************************************************************************** + * Name: netlink_route_recvfrom() + * + * Description: + * Perform the recvfrom() operation for the NETLINK_ROUTE protocol. + * + ****************************************************************************/ + +ssize_t netlink_route_recvfrom(FAR struct socket *psock, + FAR struct nlmsghdr *nlmsg, + size_t len, int flags, + FAR struct sockaddr_nl *from) +{ + FAR struct nlroute_recvfrom_response_s *resp; + + DEBUGASSERT(psock != NULL && nlmsg != NULL && + nlmsg->nlmsg_len >= sizeof(struct nlmsghdr) && + len >= sizeof(struct nlmsghdr) && + from != NULL); + + /* Find the response to this message */ + + net_lock(); + resp = (FAR struct nlroute_recvfrom_response_s *) + netlink_get_response(psock, nlmsg); + net_unlock(); + + if (resp == NULL) + { + return -ENOENT; + } + + if (len < resp->hdr.nlmsg_len) + { + kmm_free(resp); + return -EMSGSIZE; + } + + memcpy(nlmsg, resp, resp->hdr.nlmsg_len); + + /* Return address. REVISIT... this is just a guess. */ + + from->nl_family = resp->msg.ndm_family; + from->nl_pad = 0; + from->nl_pid = resp->hdr.nlmsg_pid; + from->nl_groups = resp->hdr.nlmsg_type; + + return resp->hdr.nlmsg_len; +} + +#endif /* CONFIG_NETLINK_ROUTE */ diff --git a/net/netlink/netlink_sockif.c b/net/netlink/netlink_sockif.c index 286d3517f2..e060123894 100644 --- a/net/netlink/netlink_sockif.c +++ b/net/netlink/netlink_sockif.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -120,8 +121,9 @@ const struct sock_intf_s g_netlink_sockif = * specific socket fields. * * Input Parameters: - * psock A pointer to a user allocated socket structure to be initialized. - * protocol (see sys/socket.h) + * psock - A pointer to a user allocated socket structure to be + * initialized. + * protocol - Netlink socket protocol (see sys/socket.h) * * Returned Value: * Zero (OK) is returned on success. Otherwise, a negated errno value is @@ -133,19 +135,56 @@ static int netlink_setup(FAR struct socket *psock, int protocol) { int domain = psock->s_domain; int type = psock->s_type; - int ret; + + /* Verify that the protocol is supported */ + + DEBUGASSERT((unsigned int)protocol <= UINT8_MAX); + + switch (protocol) + { +#ifdef CONFIG_NETLINK_ROUTE + case NETLINK_ROUTE: + break; +#endif + + default: + return -EPROTONOSUPPORT; + } + + /* Verify the socket type (domain should always be PF_NETLINK here) */ if (domain == PF_NETLINK && (type == SOCK_RAW || type == SOCK_DGRAM)) { - ret = OK; - } - else - { - return -ENETDOWN; + /* Allocate the netlink socket connection structure and save it in the + * new socket instance. + */ + + FAR struct netlink_conn_s *conn = netlink_alloc(); + if (conn == NULL) + { + /* Failed to reserve a connection structure */ + + return -ENOMEM; + } + + /* Initialize the connection instance */ + + conn->protocol = (uint8_t)protocol; + + /* Set the reference count on the connection structure. This + * reference count will be incremented only if the socket is + * dup'ed + */ + + conn->crefs = 1; + + /* Attach the connection instance to the socket */ + + psock->s_conn = conn; + return OK; } - psock->s_conn = NULL; - return ret; + return -EPROTONOSUPPORT; } /**************************************************************************** @@ -227,8 +266,22 @@ static void netlink_addref(FAR struct socket *psock) static int netlink_bind(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen) { -#warning Missing logic for NETLINK bind - return -EOPNOTSUPP; + FAR struct sockaddr_nl *nladdr; + FAR struct netlink_conn_s *conn; + + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && addr != NULL && + addrlen >= sizeof(struct sockaddr_nl)); + + /* Save the address information in the connection structure */ + + nladdr = (FAR struct sockaddr_nl *)addr; + conn = (FAR struct netlink_conn_s *)psock->s_conn; + + conn->pid = nladdr->nl_pid; + conn->groups = nladdr->nl_groups; + + psock->s_flags |= _SF_BOUND; + return OK; } /**************************************************************************** @@ -257,8 +310,29 @@ static int netlink_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen) { -#warning Missing logic for NETLINK getsockname - return -EOPNOTSUPP; + FAR struct sockaddr_nl *nladdr; + + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && addr != NULL && + addrlen != NULL && *addrlen >= sizeof(struct sockaddr_nl)); + + /* Return the address information in the address structure */ + + nladdr = (FAR struct sockaddr_nl *)addr; + memset(nladdr, 0, sizeof(struct sockaddr_nl)); + + nladdr->nl_family = AF_NETLINK; + + if (_SS_ISBOUND(psock->s_flags)) + { + FAR struct netlink_conn_s *conn; + + conn = (FAR struct netlink_conn_s *)psock->s_conn; + nladdr->nl_pid = conn->pid; + nladdr->nl_groups = conn->groups; + } + + *addrlen = sizeof(struct sockaddr_nl); + return OK; } /**************************************************************************** @@ -449,12 +523,41 @@ static int netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds, * ****************************************************************************/ -static ssize_t netlink_send(FAR struct socket *psock, - FAR const void *buf, - size_t len, int flags) +static ssize_t netlink_send(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags) { -#warning Missing logic for NETLINK send - return -EOPNOTSUPP; + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL); + + /* The socket must be connected in order to use send */ + + if (_SS_ISBOUND(psock->s_flags)) + { + FAR struct netlink_conn_s *conn; + struct sockaddr_nl nladdr; + + /* Get the underlying connection structure */ + + conn = (FAR struct netlink_conn_s *)psock->s_conn; + + /* Format the address */ + + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pad = 0; + nladdr.nl_pid = conn->pid; + nladdr.nl_groups = conn->groups; + + /* Then let sendto() perform the actual send operation */ + + return netlink_sendto(psock, buf, len, flags, + (FAR const struct sockaddr *)&nladdr, + sizeof(struct sockaddr_nl)); + } + + /* EDESTADDRREQ. Signifies that the socket is not connection-mode and no + * peer address is set. + */ + + return -EDESTADDRREQ; } /**************************************************************************** @@ -482,11 +585,40 @@ static ssize_t netlink_send(FAR struct socket *psock, ****************************************************************************/ static ssize_t netlink_sendto(FAR struct socket *psock, FAR const void *buf, - size_t len, int flags, - FAR const struct sockaddr *to, socklen_t tolen) + size_t len, int flags, + FAR const struct sockaddr *to, socklen_t tolen) { -#warning Missing logic for NETLINK sendto - return -EOPNOTSUPP; + FAR struct netlink_conn_s *conn; + FAR struct nlmsghdr *nlmsg; + int ret; + + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL && + to != NULL && tolen >= sizeof(struct nlmsghdr)); + + conn = (FAR struct netlink_conn_s *)psock->s_conn; + + /* Get a reference to the netlink message */ + + nlmsg = (FAR struct nlmsghdr *)buf; + DEBUGASSERT(nlmsg->nlmsg_len >= sizeof(struct nlmsghdr) && + tolen >= nlmsg->nlmsg_len); + + switch (conn->protocol) + { +#ifdef CONFIG_NETLINK_ROUTE + case NETLINK_ROUTE: + ret = netlink_route_sendto(psock, nlmsg, len, flags, + (FAR struct sockaddr_nl *)to, + tolen); + break; +#endif + + default: + ret= -EOPNOTSUPP; + break; + } + + return ret; } /**************************************************************************** @@ -516,8 +648,35 @@ static ssize_t netlink_recvfrom(FAR struct socket *psock, FAR void *buf, FAR struct sockaddr *from, FAR socklen_t *fromlen) { -#warning Missing logic for NETLINK recvfrom - return -EOPNOTSUPP; + FAR struct netlink_conn_s *conn; + FAR struct nlmsghdr *nlmsg; + int ret; + + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL && + from != NULL && *fromlen >= sizeof(struct nlmsghdr)); + + conn = (FAR struct netlink_conn_s *)psock->s_conn; + + /* Get a reference to the netlink message */ + + nlmsg = (FAR struct nlmsghdr *)buf; + + switch (conn->protocol) + { +#ifdef CONFIG_NETLINK_ROUTE + case NETLINK_ROUTE: + ret = netlink_route_recvfrom(psock, nlmsg, len, flags, + (FAR struct sockaddr_nl *)from); + *fromlen = sizeof(struct sockaddr_nl); + break; +#endif + + default: + ret= -EOPNOTSUPP; + break; + } + + return ret; } /**************************************************************************** @@ -539,7 +698,7 @@ static ssize_t netlink_recvfrom(FAR struct socket *psock, FAR void *buf, static int netlink_close(FAR struct socket *psock) { FAR struct netlink_conn_s *conn = psock->s_conn; - int ret; + int ret = OK; /* Perform some pre-close operations for the NETLINK socket type. */ @@ -573,7 +732,7 @@ static int netlink_close(FAR struct socket *psock) conn->crefs--; } - return OK; + return ret; } #endif /* CONFIG_NET_NETLINK */ diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c index 46ac4dd2ca..def5bc4410 100644 --- a/net/pkt/pkt_sockif.c +++ b/net/pkt/pkt_sockif.c @@ -198,7 +198,7 @@ static int pkt_setup(FAR struct socket *psock, int protocol) * queried. * * Returned Value: - * The set of socket cababilities is returned. + * The set of socket capabilities is returned. * ****************************************************************************/ @@ -261,7 +261,7 @@ static void pkt_addref(FAR struct socket *psock) * addrlen Length of actual 'addr' * * Returned Value: - * 0 on success; a negated errno value on failue. See connect() for the + * 0 on success; a negated errno value on failure. See connect() for the * list of appropriate errno values to be returned. * ****************************************************************************/ diff --git a/net/udp/udp_psock_sendto_unbuffered.c b/net/udp/udp_psock_sendto_unbuffered.c index 218dbe0607..d19e9d577b 100644 --- a/net/udp/udp_psock_sendto_unbuffered.c +++ b/net/udp/udp_psock_sendto_unbuffered.c @@ -208,7 +208,7 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev, { FAR struct sendto_s *pstate = (FAR struct sendto_s *)pvpriv; - DEBUGASSERT(pstate != NULL && pstate->dev != NULL); + DEBUGASSERT(pstate != NULL && pstate->st_dev != NULL); if (pstate != NULL) { /* The TCP socket should be bound to a device. Make sure that the