static int
netdev_linux_send(struct netdev *netdev_, const void *data, size_t size)
{
- struct sockaddr_ll sll;
- struct msghdr msg;
- struct iovec iov;
- int ifindex;
- int error;
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ for (;;) {
+ ssize_t retval;
- error = get_ifindex(netdev_, &ifindex);
- if (error) {
- return error;
- }
+ if (netdev->fd < 0) {
+ /* Use our AF_PACKET socket to send to this device. */
+ struct sockaddr_ll sll;
+ struct msghdr msg;
+ struct iovec iov;
+ int ifindex;
+ int error;
- /* We don't bother setting most fields in sockaddr_ll because the kernel
- * ignores them for SOCK_RAW. */
- memset(&sll, 0, sizeof sll);
- sll.sll_family = AF_PACKET;
- sll.sll_ifindex = ifindex;
+ error = get_ifindex(netdev_, &ifindex);
+ if (error) {
+ return error;
+ }
- iov.iov_base = (void *) data;
- iov.iov_len = size;
+ /* We don't bother setting most fields in sockaddr_ll because the
+ * kernel ignores them for SOCK_RAW. */
+ memset(&sll, 0, sizeof sll);
+ sll.sll_family = AF_PACKET;
+ sll.sll_ifindex = ifindex;
- msg.msg_name = &sll;
- msg.msg_namelen = sizeof sll;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = 0;
+ iov.iov_base = (void *) data;
+ iov.iov_len = size;
+
+ msg.msg_name = &sll;
+ msg.msg_namelen = sizeof sll;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ retval = sendmsg(af_packet_sock, &msg, 0);
+ } else {
+ /* Use the netdev's own fd to send to this device. This is
+ * essential for tap devices, because packets sent to a tap device
+ * with an AF_PACKET socket will loop back to be *received* again
+ * on the tap device. */
+ retval = write(netdev->fd, data, size);
+ }
- for (;;) {
- ssize_t retval = sendmsg(af_packet_sock, &msg, 0);
if (retval < 0) {
/* The Linux AF_PACKET implementation never blocks waiting for room
* for packets, instead returning ENOBUFS. Translate this into