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:
parent
d0c164274d
commit
2991987018
@ -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
|
||||
****************************************************************************/
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
262
net/netlink/netlink_route.c
Normal 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 */
|
@ -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 */
|
||||
|
@ -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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user