9a23ebdbc0
We're using the `sll_ifindex` inside `struct sockaddr_ll` to bind device, so we don't need to translate it into mac address, we can just match the index, which also let us bind to different type of devices other than Ethernet. Ref: Linux also uses `ifindex` to find related device and note it down without mac addresses. https://man7.org/linux/man-pages/man7/packet.7.html https://github.com/torvalds/linux/blob/v6.7/net/packet/af_packet.c#L3328 https://github.com/torvalds/linux/blob/v6.7/net/packet/af_packet.c#L3264-L3265 Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
327 lines
9.3 KiB
C
327 lines
9.3 KiB
C
/****************************************************************************
|
|
* net/pkt/pkt_sockif.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <debug.h>
|
|
|
|
#include <netpacket/packet.h>
|
|
|
|
#include <nuttx/net/net.h>
|
|
#include <nuttx/net/netdev.h>
|
|
|
|
#include "netdev/netdev.h"
|
|
#include <socket/socket.h>
|
|
#include "pkt/pkt.h"
|
|
|
|
#ifdef CONFIG_NET_PKT
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
static int pkt_setup(FAR struct socket *psock);
|
|
static sockcaps_t pkt_sockcaps(FAR struct socket *psock);
|
|
static void pkt_addref(FAR struct socket *psock);
|
|
static int pkt_bind(FAR struct socket *psock,
|
|
FAR const struct sockaddr *addr, socklen_t addrlen);
|
|
static int pkt_close(FAR struct socket *psock);
|
|
|
|
/****************************************************************************
|
|
* Public Data
|
|
****************************************************************************/
|
|
|
|
const struct sock_intf_s g_pkt_sockif =
|
|
{
|
|
pkt_setup, /* si_setup */
|
|
pkt_sockcaps, /* si_sockcaps */
|
|
pkt_addref, /* si_addref */
|
|
pkt_bind, /* si_bind */
|
|
NULL, /* si_getsockname */
|
|
NULL, /* si_getpeername */
|
|
NULL, /* si_listen */
|
|
NULL, /* si_connect */
|
|
NULL, /* si_accept */
|
|
NULL, /* si_poll */
|
|
pkt_sendmsg, /* si_sendmsg */
|
|
pkt_recvmsg, /* si_recvmsg */
|
|
pkt_close /* si_close */
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: pkt_sockif_alloc
|
|
*
|
|
* Description:
|
|
* Allocate and attach a raw packet connection structure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int pkt_sockif_alloc(FAR struct socket *psock)
|
|
{
|
|
/* Allocate the packet socket connection structure and save in the new
|
|
* socket instance.
|
|
*/
|
|
|
|
FAR struct pkt_conn_s *conn = pkt_alloc();
|
|
if (conn == NULL)
|
|
{
|
|
/* Failed to reserve a connection structure */
|
|
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Set the reference count on the connection structure. This reference
|
|
* count will be incremented only if the socket is dup'ed
|
|
*/
|
|
|
|
DEBUGASSERT(conn->crefs == 0);
|
|
conn->crefs = 1;
|
|
|
|
/* Save the pre-allocated connection in the socket structure */
|
|
|
|
psock->s_conn = conn;
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: pkt_setup
|
|
*
|
|
* Description:
|
|
* Called for socket() to verify that the provided socket type and
|
|
* protocol are usable by this address family. Perform any family-
|
|
* specific socket fields.
|
|
*
|
|
* Input Parameters:
|
|
* psock A pointer to a user allocated socket structure to be
|
|
* initialized.
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) is returned on success. Otherwise, a negated errno value is
|
|
* returned.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int pkt_setup(FAR struct socket *psock)
|
|
{
|
|
/* Allocate the appropriate connection structure. This reserves the
|
|
* connection structure, it is unallocated at this point. It will not
|
|
* actually be initialized until the socket is connected.
|
|
*
|
|
* SOCK_RAW and SOCK_CTRL are supported.
|
|
*/
|
|
|
|
if (psock->s_type == SOCK_RAW || psock->s_type == SOCK_CTRL)
|
|
{
|
|
return pkt_sockif_alloc(psock);
|
|
}
|
|
else
|
|
{
|
|
return -EPROTONOSUPPORT;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: pkt_sockcaps
|
|
*
|
|
* Description:
|
|
* Return the bit encoded capabilities of this socket.
|
|
*
|
|
* Input Parameters:
|
|
* psock - Socket structure of the socket whose capabilities are being
|
|
* queried.
|
|
*
|
|
* Returned Value:
|
|
* The set of socket capabilities is returned.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static sockcaps_t pkt_sockcaps(FAR struct socket *psock)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: pkt_addref
|
|
*
|
|
* Description:
|
|
* Increment the reference count on the underlying connection structure.
|
|
*
|
|
* Input Parameters:
|
|
* psock - Socket structure of the socket whose reference count will be
|
|
* incremented.
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void pkt_addref(FAR struct socket *psock)
|
|
{
|
|
FAR struct pkt_conn_s *conn;
|
|
|
|
DEBUGASSERT(psock->s_type == SOCK_RAW || psock->s_type == SOCK_CTRL);
|
|
|
|
conn = psock->s_conn;
|
|
DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
|
|
conn->crefs++;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: pkt_bind
|
|
*
|
|
* Description:
|
|
* pkt_bind() gives the socket 'psock' the local address 'addr'. 'addr'
|
|
* is 'addrlen' bytes long. Traditionally, this is called "assigning a
|
|
* name to a socket." When a socket is created with socket(), it exists
|
|
* in a name space (address family) but has no name assigned.
|
|
*
|
|
* Input Parameters:
|
|
* psock Socket structure of the socket to bind
|
|
* addr Socket local address
|
|
* addrlen Length of 'addr'
|
|
*
|
|
* Returned Value:
|
|
* 0 on success; A negated errno value is returned on failure. See
|
|
* bind() for a list a appropriate error values.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int pkt_bind(FAR struct socket *psock,
|
|
FAR const struct sockaddr *addr, socklen_t addrlen)
|
|
{
|
|
int ifindex;
|
|
|
|
/* Verify that a valid address has been provided */
|
|
|
|
if (addr->sa_family != AF_PACKET || addrlen < sizeof(struct sockaddr_ll))
|
|
{
|
|
nerr("ERROR: Invalid address length: %d < %zu\n",
|
|
addrlen, sizeof(struct sockaddr_ll));
|
|
return -EBADF;
|
|
}
|
|
|
|
/* Bind a raw socket to a network device. */
|
|
|
|
if (psock->s_type == SOCK_RAW || psock->s_type == SOCK_CTRL)
|
|
{
|
|
FAR struct pkt_conn_s *conn = psock->s_conn;
|
|
FAR struct net_driver_s *dev;
|
|
|
|
/* Look at the addr and identify the network interface */
|
|
|
|
ifindex = ((FAR struct sockaddr_ll *)addr)->sll_ifindex;
|
|
|
|
/* Check if we have that interface */
|
|
|
|
dev = netdev_findbyindex(ifindex);
|
|
if (dev == NULL)
|
|
{
|
|
return -EADDRNOTAVAIL;
|
|
}
|
|
|
|
/* Put ifindex into connection */
|
|
|
|
conn->ifindex = ifindex;
|
|
|
|
return OK;
|
|
}
|
|
else
|
|
{
|
|
return -EBADF;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: pkt_close
|
|
*
|
|
* Description:
|
|
* Performs the close operation on a raw packet socket instance
|
|
*
|
|
* Input Parameters:
|
|
* psock Socket instance
|
|
*
|
|
* Returned Value:
|
|
* 0 on success; a negated errno value is returned on any failure.
|
|
*
|
|
* Assumptions:
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int pkt_close(FAR struct socket *psock)
|
|
{
|
|
/* Perform some pre-close operations for the raw packet address type */
|
|
|
|
switch (psock->s_type)
|
|
{
|
|
case SOCK_RAW:
|
|
case SOCK_CTRL:
|
|
{
|
|
FAR struct pkt_conn_s *conn = psock->s_conn;
|
|
|
|
/* Is this the last reference to the connection structure (there
|
|
* could be more if the socket was dup'ed).
|
|
*/
|
|
|
|
if (conn->crefs <= 1)
|
|
{
|
|
/* Yes... free any read-ahead data */
|
|
|
|
iob_free_queue(&conn->readahead);
|
|
|
|
/* Then free the connection structure */
|
|
|
|
conn->crefs = 0; /* No more references on the connection */
|
|
pkt_free(psock->s_conn); /* Free network resources */
|
|
}
|
|
else
|
|
{
|
|
/* No.. Just decrement the reference count */
|
|
|
|
conn->crefs--;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
default:
|
|
return -EBADF;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
#endif /* CONFIG_NET_PKT */
|