net/netlink/netlink_route.c (mostly): This completes a minimal netlink implementation that will retrieve the ARP table.

net/netlink:  Add basic hooks (only) to support the NETLINK_ROUTE protocol.
This commit is contained in:
Gregory Nutt 2019-11-03 13:59:42 -06:00
parent d0c164274d
commit 2991987018
11 changed files with 779 additions and 54 deletions

View File

@ -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
* 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_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
#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_USERSOCK 11 /* Reserved for user mode socket protocols */
#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
****************************************************************************/

View File

@ -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
*

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -46,6 +46,8 @@
#include <queue.h>
#include <semaphore.h>
#include <netpacket/netlink.h>
#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

View File

@ -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 */

262
net/netlink/netlink_route.c Normal file
View File

@ -0,0 +1,262 @@
/****************************************************************************
* net/netlink/netlink_route.c
*
* Copyright (C) 2019 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <sys/types.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <netpacket/netlink.h>
#include <nuttx/kmalloc.h>
#include <nuttx/net/net.h>
#include <nuttx/net/arp.h>
#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 */

View File

@ -42,6 +42,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
@ -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
/* 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)
{
return -ENETDOWN;
/* Failed to reserve a connection structure */
return -ENOMEM;
}
psock->s_conn = NULL;
return ret;
/* 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;
}
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,
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;
}
/****************************************************************************
@ -485,8 +588,37 @@ 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)
{
#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 */

View File

@ -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.
*
****************************************************************************/

View File

@ -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