diff --git a/Documentation/components/net/pkt.rst b/Documentation/components/net/pkt.rst index 9df38f43c35..f0ec185c1ff 100644 --- a/Documentation/components/net/pkt.rst +++ b/Documentation/components/net/pkt.rst @@ -17,6 +17,8 @@ Configuration Options Dynamic memory allocations for packet connections. ``CONFIG_NET_PKT_MAX_CONNS`` Maximum number of packet connections. +``NET_PKT_WRITE_BUFFERS`` + Use write buffers for packet sockets, support SOCK_NONBLOCK mode. Usage ===== @@ -25,7 +27,7 @@ Usage struct sockaddr_ll addr; uint8_t buffer[BUFSIZE]; - int sd = socket(AF_PACKET, SOCK_RAW, 0); /* Create a packet socket */ + int sd = socket(AF_PACKET, SOCK_RAW, 0); /* Create a Raw packet socket */ addr.sll_family = AF_PACKET; addr.sll_ifindex = if_nametoindex("eth0"); @@ -36,3 +38,23 @@ Usage send(sd, buffer, sizeof(buffer), 0); /* write(sd, buffer, sizeof(buffer)); */ close(sd); /* Close the socket */ + +.. code-block:: c + + struct sockaddr_ll addr; + uint8_t buffer[BUFSIZE]; + int sd = socket(AF_PACKET, SOCK_DGRAM, 0); /* Create a Dgram packet socket */ + + addr.sll_family = AF_PACKET; + addr.sll_ifindex = if_nametoindex("eth0"); + addr.sll_protocol = htons(ETH_P_IP); + bind(sd, (FAR struct sockaddr *)&addr, sizeof(addr)); /* Bind to device */ + + recv(sd, buffer, sizeof(buffer), 0); /* read(sd, buffer, sizeof(buffer)); */ + + memset(addr.sll_addr, 0xff, sizeof(addr.sll_addr)); /* Destination MAC address */ + addr.sll_halen = ETH_ALEN; + sendto(sd, buffer, sizeof(buffer), 0, /* SOCK_DGRAM can not use write() */ + (struct sockaddr *)&addr, sizeof(addr)); + + close(sd); /* Close the socket */ diff --git a/net/pkt/pkt.h b/net/pkt/pkt.h index 1fa27860e22..16f1c5f6199 100644 --- a/net/pkt/pkt.h +++ b/net/pkt/pkt.h @@ -196,6 +196,26 @@ FAR struct pkt_conn_s *pkt_active(FAR struct net_driver_s *dev); FAR struct pkt_conn_s *pkt_nextconn(FAR struct pkt_conn_s *conn); +/**************************************************************************** + * Name: pkt_sendmsg_is_valid + * + * Description: + * Validate the sendmsg() parameters for a packet socket. + * + * Input Parameters: + * psock - The socket structure to validate + * msg - The message header containing the data to be sent + * dev - The network device to be used to send the packet + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int pkt_sendmsg_is_valid(FAR struct socket *psock, + FAR const struct msghdr *msg, + FAR struct net_driver_s **dev); + /**************************************************************************** * Name: pkt_callback * diff --git a/net/pkt/pkt_conn.c b/net/pkt/pkt_conn.c index 2acda198926..bd81a10f1b1 100644 --- a/net/pkt/pkt_conn.c +++ b/net/pkt/pkt_conn.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -42,6 +43,7 @@ #include #include "devif/devif.h" +#include "netdev/netdev.h" #include "pkt/pkt.h" #include "utils/utils.h" @@ -217,4 +219,77 @@ FAR struct pkt_conn_s *pkt_nextconn(FAR struct pkt_conn_s *conn) } } +/**************************************************************************** + * Name: pkt_sendmsg_is_valid + * + * Description: + * Validate the sendmsg() parameters for a packet socket. + * + * Input Parameters: + * psock - The socket structure to validate + * msg - The message header containing the data to be sent + * dev - The network device to be used to send the packet + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int pkt_sendmsg_is_valid(FAR struct socket *psock, + FAR const struct msghdr *msg, + FAR struct net_driver_s **dev) +{ + FAR struct sockaddr_ll *addr = msg->msg_name; + + /* Only single iov supported */ + + if (msg->msg_iovlen != 1) + { + return -ENOTSUP; + } + + /* Verify that the sockfd corresponds to valid, allocated socket */ + + if (psock == NULL || psock->s_conn == NULL) + { + return -EBADF; + } + + if (psock->s_type == SOCK_DGRAM) + { + if (msg->msg_name == NULL || + msg->msg_namelen < sizeof(struct sockaddr_ll) || + addr->sll_halen < ETHER_ADDR_LEN) + { + return -EINVAL; + } + + /* Get the device driver that will service this transfer */ + + *dev = netdev_findbyindex(addr->sll_ifindex); + } + else if (psock->s_type == SOCK_RAW) + { + if (msg->msg_name != NULL) + { + return -EAFNOSUPPORT; + } + + /* Get the device driver that will service this transfer */ + + *dev = pkt_find_device(psock->s_conn); + } + else + { + return -ENOTSUP; + } + + if (*dev == NULL) + { + return -ENODEV; + } + + return OK; +} + #endif /* CONFIG_NET && CONFIG_NET_PKT */ diff --git a/net/pkt/pkt_recvmsg.c b/net/pkt/pkt_recvmsg.c index 08b93092de9..8d3b179ca4d 100644 --- a/net/pkt/pkt_recvmsg.c +++ b/net/pkt/pkt_recvmsg.c @@ -61,6 +61,7 @@ struct pkt_recvfrom_s sem_t pr_sem; /* Semaphore signals recv completion */ ssize_t pr_recvlen; /* The received length */ int pr_result; /* Success:OK, failure:negated errno */ + uint8_t pr_type; /* Protocol type */ }; /**************************************************************************** @@ -152,7 +153,7 @@ static inline void pkt_add_recvlen(FAR struct pkt_recvfrom_s *pstate, static void pkt_recvfrom_newdata(FAR struct net_driver_s *dev, FAR struct pkt_recvfrom_s *pstate) { - unsigned int offset; + unsigned int offset = 0; size_t recvlen; #ifdef CONFIG_NET_TIMESTAMP @@ -169,7 +170,10 @@ static void pkt_recvfrom_newdata(FAR struct net_driver_s *dev, /* Copy the new packet data into the user buffer */ - offset = (dev->d_appdata - dev->d_iob->io_data) - dev->d_iob->io_offset; + if (pstate->pr_type == SOCK_RAW) + { + offset = -NET_LL_HDRLEN(dev); + } recvlen = iob_copyout(pstate->pr_msg->msg_iov->iov_base, dev->d_iob, recvlen, offset); @@ -270,6 +274,7 @@ static uint16_t pkt_recvfrom_eventhandler(FAR struct net_driver_s *dev, * conn The PKT connection of interest * msg Receive info and buffer for receive data * pstate A pointer to the state structure to be initialized + * type Protocol type * * Returned Value: * None @@ -280,7 +285,8 @@ static uint16_t pkt_recvfrom_eventhandler(FAR struct net_driver_s *dev, static void pkt_recvfrom_initialize(FAR struct pkt_conn_s *conn, FAR struct msghdr *msg, - FAR struct pkt_recvfrom_s *pstate) + FAR struct pkt_recvfrom_s *pstate, + uint8_t type) { /* Initialize the state structure. */ @@ -289,6 +295,7 @@ static void pkt_recvfrom_initialize(FAR struct pkt_conn_s *conn, pstate->pr_conn = conn; pstate->pr_msg = msg; + pstate->pr_type = type; } /* The only un-initialization that has to be performed is destroying the @@ -365,6 +372,7 @@ static inline void pkt_readahead(FAR struct pkt_recvfrom_s *pstate) FAR struct pkt_conn_s *conn = pstate->pr_conn; FAR struct iob_s *iob; int recvlen; + int offset = 0; /* Check there is any packets already buffered in a read-ahead buffer. */ @@ -394,8 +402,23 @@ static inline void pkt_readahead(FAR struct pkt_recvfrom_s *pstate) /* Copy to user */ + if (pstate->pr_type == SOCK_DGRAM) + { + FAR struct net_driver_s *dev = pkt_find_device(conn); + if (dev != NULL) + { + /* For SOCK_DGRAM, we need skip the l2 header */ + + offset = NET_LL_HDRLEN(dev); + } + else + { + offset = sizeof(struct eth_hdr_s); + } + } + recvlen = iob_copyout(pstate->pr_msg->msg_iov->iov_base, iob, - pstate->pr_msg->msg_iov->iov_len, 0); + pstate->pr_msg->msg_iov->iov_len, offset); /* Update the accumulated size of the data read */ @@ -471,7 +494,7 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg, return -ENOTSUP; } - if (psock->s_type != SOCK_RAW) + if (psock->s_type != SOCK_DGRAM && psock->s_type != SOCK_RAW) { nerr("ERROR: Unsupported socket type: %d\n", psock->s_type); ret = -ENOSYS; @@ -483,7 +506,7 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg, * locked because we don't want anything to happen until we are ready. */ - pkt_recvfrom_initialize(conn, msg, &state); + pkt_recvfrom_initialize(conn, msg, &state, psock->s_type); net_lock(); diff --git a/net/pkt/pkt_sendmsg_buffered.c b/net/pkt/pkt_sendmsg_buffered.c index 5a13642fe80..baf4d89aaa0 100644 --- a/net/pkt/pkt_sendmsg_buffered.c +++ b/net/pkt/pkt_sendmsg_buffered.c @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -208,43 +209,20 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg, { FAR const void *buf = msg->msg_iov->iov_base; size_t len = msg->msg_iov->iov_len; + FAR struct sockaddr_ll *addr = msg->msg_name; FAR struct net_driver_s *dev; FAR struct pkt_conn_s *conn; FAR struct iob_s *iob; bool nonblock; + int offset = 0; int ret = OK; - /* Validity check, only single iov supported */ + /* Validity check */ - if (msg->msg_iovlen != 1) + ret = pkt_sendmsg_is_valid(psock, msg, &dev); + if (ret != OK) { - return -ENOTSUP; - } - - if (msg->msg_name != NULL) - { - /* pkt_sendto */ - - nerr("ERROR: sendto() not supported for raw packet sockets\n"); - return -EAFNOSUPPORT; - } - - /* Verify that the sockfd corresponds to valid, allocated socket */ - - if (psock == NULL || psock->s_conn == NULL) - { - return -EBADF; - } - - /* Only SOCK_RAW is supported */ - - if (psock->s_type != SOCK_RAW) - { - /* EDESTADDRREQ. Signifies that the socket is not connection-mode and - * no peer address is set. - */ - - return -EDESTADDRREQ; + return ret; } if (len <= 0) @@ -254,16 +232,14 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg, net_lock(); - /* Get the device driver that will service this transfer */ - - dev = pkt_find_device(psock->s_conn); - if (dev == NULL) + conn = psock->s_conn; + if (psock->s_type == SOCK_DGRAM) { - ret = -ENODEV; - goto errout_with_lock; + /* Set the interface index for devif_poll can match the conn */ + + conn->ifindex = addr->sll_ifindex; } - conn = psock->s_conn; nonblock = _SS_ISNONBLOCK(conn->sconn.s_flags) || (flags & MSG_DONTWAIT) != 0; @@ -322,9 +298,14 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg, * buffer space if the socket was opened non-blocking. */ + if (psock->s_type == SOCK_RAW) + { + offset = -NET_LL_HDRLEN(dev); + } + if (nonblock) { - ret = iob_trycopyin(iob, buf, len, -NET_LL_HDRLEN(dev), false); + ret = iob_trycopyin(iob, buf, len, offset, false); } else { @@ -337,7 +318,7 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg, */ blresult = net_breaklock(&count); - ret = iob_copyin(iob, buf, len, -NET_LL_HDRLEN(dev), false); + ret = iob_copyin(iob, buf, len, offset, false); if (blresult >= 0) { net_restorelock(count); @@ -350,6 +331,15 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg, goto errout_with_iob; } + if (psock->s_type == SOCK_DGRAM) + { + FAR struct eth_hdr_s *ethhdr = + (FAR struct eth_hdr_s *)(IOB_DATA(iob) - NET_LL_HDRLEN(dev)); + memcpy(ethhdr->dest, addr->sll_addr, ETHER_ADDR_LEN); + memcpy(ethhdr->src, &dev->d_mac.ether, ETHER_ADDR_LEN); + ethhdr->type = addr->sll_protocol; + } + if (nonblock) { ret = iob_tryadd_queue(iob, &conn->write_q); diff --git a/net/pkt/pkt_sendmsg_unbuffered.c b/net/pkt/pkt_sendmsg_unbuffered.c index b7d7bb510b4..ee70d64eb1e 100644 --- a/net/pkt/pkt_sendmsg_unbuffered.c +++ b/net/pkt/pkt_sendmsg_unbuffered.c @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -65,6 +66,7 @@ struct send_s FAR const uint8_t *snd_buffer; /* Points to the buffer of data to send */ size_t snd_buflen; /* Number of bytes in the buffer to send */ ssize_t snd_sent; /* The number of bytes sent */ + FAR struct sockaddr_ll *addr; /* The address of the destination */ }; /**************************************************************************** @@ -108,8 +110,16 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, { /* Copy the packet data into the device packet buffer and send it */ - int ret = devif_send(dev, pstate->snd_buffer, - pstate->snd_buflen, -NET_LL_HDRLEN(dev)); + int ret; + int offset = -NET_LL_HDRLEN(dev); + + if (pstate->snd_sock->s_type == SOCK_DGRAM) + { + offset = 0; + } + + ret = devif_send(dev, pstate->snd_buffer, + pstate->snd_buflen, offset); if (ret <= 0) { pstate->snd_sent = ret; @@ -120,6 +130,15 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev, pstate->snd_sent = pstate->snd_buflen; pstate->snd_conn->pendiob = dev->d_iob; + if (pstate->snd_sock->s_type == SOCK_DGRAM) + { + FAR struct eth_hdr_s *ethhdr = NETLLBUF; + memcpy(ethhdr->dest, pstate->addr->sll_addr, ETHER_ADDR_LEN); + memcpy(ethhdr->src, &dev->d_mac.ether, ETHER_ADDR_LEN); + ethhdr->type = pstate->addr->sll_protocol; + dev->d_len += NET_LL_HDRLEN(dev); + } + /* Make sure no ARP request overwrites this ARP request. This * flag will be cleared in arp_out(). */ @@ -171,49 +190,27 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, { FAR const void *buf = msg->msg_iov->iov_base; size_t len = msg->msg_iov->iov_len; + FAR struct sockaddr_ll *addr = msg->msg_name; FAR struct net_driver_s *dev; + FAR struct pkt_conn_s *conn; struct send_s state; int ret = OK; - /* Validity check, only single iov supported */ + /* Validity check */ - if (msg->msg_iovlen != 1) + ret = pkt_sendmsg_is_valid(psock, msg, &dev); + if (ret != OK) { - return -ENOTSUP; + return ret; } - if (msg->msg_name != NULL) + conn = psock->s_conn; + + if (psock->s_type == SOCK_DGRAM) { - /* pkt_sendto */ + /* Set the interface index for devif_poll can match the conn */ - nerr("ERROR: sendto() not supported for raw packet sockets\n"); - return -EAFNOSUPPORT; - } - - /* Verify that the sockfd corresponds to valid, allocated socket */ - - if (psock == NULL || psock->s_conn == NULL) - { - return -EBADF; - } - - /* Only SOCK_RAW is supported */ - - if (psock->s_type != SOCK_RAW) - { - /* EDESTADDRREQ. Signifies that the socket is not connection-mode and - * no peer address is set. - */ - - return -EDESTADDRREQ; - } - - /* Get the device driver that will service this transfer */ - - dev = pkt_find_device(psock->s_conn); - if (dev == NULL) - { - return -ENODEV; + conn->ifindex = addr->sll_ifindex; } /* Perform the send operation */ @@ -229,12 +226,11 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, state.snd_sock = psock; /* Socket descriptor to use */ state.snd_buflen = len; /* Number of bytes to send */ state.snd_buffer = buf; /* Buffer to send from */ - state.snd_conn = psock->s_conn; /* Connection info */ + state.snd_conn = conn; /* Connection info */ + state.addr = addr; /* Destination address */ if (len > 0) { - FAR struct pkt_conn_s *conn = psock->s_conn; - /* Allocate resource to receive a callback */ state.snd_cb = pkt_callback_alloc(dev, conn); diff --git a/net/pkt/pkt_setsockopt.c b/net/pkt/pkt_setsockopt.c index 9c340117404..b3f1015ef32 100644 --- a/net/pkt/pkt_setsockopt.c +++ b/net/pkt/pkt_setsockopt.c @@ -82,9 +82,9 @@ int pkt_setsockopt(FAR struct socket *psock, int level, int option, return -ENOPROTOOPT; } - if (psock->s_type != SOCK_RAW) + if (psock->s_type != SOCK_DGRAM && psock->s_type != SOCK_RAW) { - nerr("ERROR: Not a RAW PKT socket\n"); + nerr("ERROR: Not a valid PKT socket\n"); return -ENOTCONN; } diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c index eabd02218d1..f720eb3eed5 100644 --- a/net/pkt/pkt_sockif.c +++ b/net/pkt/pkt_sockif.c @@ -165,7 +165,8 @@ static int pkt_setup(FAR struct socket *psock) * SOCK_RAW and SOCK_CTRL are supported. */ - if (psock->s_type == SOCK_RAW || psock->s_type == SOCK_CTRL) + if (psock->s_type == SOCK_DGRAM || psock->s_type == SOCK_RAW || + psock->s_type == SOCK_CTRL) { return pkt_sockif_alloc(psock); } @@ -255,7 +256,8 @@ static int pkt_bind(FAR struct socket *psock, /* Bind a raw socket to a network device. */ - if (psock->s_type == SOCK_RAW || psock->s_type == SOCK_CTRL) + if (psock->s_type == SOCK_DGRAM || 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; @@ -347,6 +349,7 @@ static int pkt_close(FAR struct socket *psock) switch (psock->s_type) { + case SOCK_DGRAM: case SOCK_RAW: case SOCK_CTRL: {