Index: usr.sbin/bhyve/net_backends.c
===================================================================
--- usr.sbin/bhyve/net_backends.c
+++ usr.sbin/bhyve/net_backends.c
@@ -46,6 +46,7 @@
 #include <sys/uio.h>
 
 #include <net/if.h>
+#include <net/if_tap.h>
 #include <net/netmap.h>
 #include <net/netmap_virt.h>
 #define NETMAP_WITH_LIBS
@@ -158,14 +159,97 @@
 
 #define WPRINTF(params) printf params
 
+/*
+ * The virtio-net features supported by the tap and netmap
+ * backends.
+ */
+#define NETMAP_FEATURES (VIRTIO_NET_F_CSUM | VIRTIO_NET_F_HOST_TSO4 | \
+		VIRTIO_NET_F_HOST_TSO6 | VIRTIO_NET_F_HOST_UFO | \
+		VIRTIO_NET_F_GUEST_CSUM | VIRTIO_NET_F_GUEST_TSO4 | \
+		VIRTIO_NET_F_GUEST_TSO6 | VIRTIO_NET_F_GUEST_UFO | \
+		VIRTIO_NET_F_MRG_RXBUF)
+#define TAP_FEATURES	NETMAP_FEATURES
+
 /*
  * The tap backend
  */
 
 struct tap_priv {
+	char ifname[IFNAMSIZ];
 	struct mevent *mevp;
 };
 
+#define TAP_VHDR_IFCAPS	(IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 \
+			| IFCAP_VLAN_HWCSUM | IFCAP_TSO \
+			| IFCAP_LRO | IFCAP_VLAN_HWTSO)
+
+static int
+tap_set_vnet_hdr_len(struct net_backend *be, unsigned vnet_hdr_len)
+{
+	struct tap_priv *priv = (struct tap_priv *)be->opaque;
+	int ival = vnet_hdr_len;
+	struct ifreq ifreq;
+	int ret;
+	int s;
+
+	/*
+	 * Configure the virtio-net header length, using the tap(4) character
+	 * device interface.
+	 */
+	ret = ioctl(be->fd, TAPSVNETHDR, &ival);
+	if (ret) {
+		WPRINTF(("ioctl(TAPSVNETHDR) failed: %s\n",
+					strerror(errno)));
+		return (ret);
+	}
+
+	/*
+	 * Open a socket to run ioctl() commands on the tap(4) network
+	 * interface.
+	 */
+	s = socket(AF_LOCAL, SOCK_DGRAM, 0);
+	if (s < 0) {
+		WPRINTF(("socket(AF_LOCAL) failed: %s\n", strerror(errno)));
+		return (s);
+	}
+
+	/*
+	 * Get interface capabilities: enabled capabilities are stored
+	 * in ifreq.ifr_curcap, while supported ones are stored in
+	 * ifreq.ifr_reqcap.
+	 */
+	memset(&ifreq, 0, sizeof(ifreq));
+	strlcpy(ifreq.ifr_name, priv->ifname, sizeof(ifreq.ifr_name));
+
+	ret = ioctl(s, SIOCGIFCAP, &ifreq);
+	if (ret) {
+		WPRINTF(("ioctl(SIOCGIFCAP) failed: %s\n", strerror(errno)));
+		close(s);
+		return (ret);
+	}
+
+	/*
+	 * Enable or disable tap(4) capabilities for TX/RX checksum and
+	 * TSO/LRO.
+	 */
+	if (vnet_hdr_len != 0) {
+		assert((ifreq.ifr_reqcap & TAP_VHDR_IFCAPS) == TAP_VHDR_IFCAPS);
+		ifreq.ifr_reqcap = ifreq.ifr_curcap | TAP_VHDR_IFCAPS;
+	} else {
+		ifreq.ifr_reqcap = ifreq.ifr_curcap & (~TAP_VHDR_IFCAPS);
+	}
+	ret = ioctl(s, SIOCSIFCAP, &ifreq);
+	if (ret) {
+		WPRINTF(("ioctl(SIOCSIFCAP) failed: %s\n", strerror(errno)));
+		close(s);
+		return (ret);
+	}
+
+	close(s);
+
+	return (0);
+}
+
 static void
 tap_cleanup(struct net_backend *be)
 {
@@ -196,6 +280,11 @@
 		return (-1);
 	}
 
+	if (strlcpy(priv->ifname, devname, sizeof(priv->ifname)) >=
+	    sizeof(priv->ifname)) {
+		WPRINTF(("TAP device name too long\n"));
+		return (-1);
+	}
 	strcpy(tbuf, "/dev/");
 	strlcat(tbuf, devname, sizeof(tbuf));
 
@@ -215,7 +304,7 @@
 	}
 
 #ifndef WITHOUT_CAPSICUM
-	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
+	cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE, CAP_IOCTL);
 	if (caph_rights_limit(be->fd, &rights) == -1)
 		errx(EX_OSERR, "Unable to apply rights for sandbox");
 #endif
@@ -278,16 +367,35 @@
 static uint64_t
 tap_get_cap(struct net_backend *be)
 {
+	int ret;
 
-	return (0); /* no capabilities for now */
+	/*
+	 * Check if we are able to set the virtio net header.
+	 * If we are not, we tell the caller that we do not support
+	 * any offload.
+	 */
+	if (tap_set_vnet_hdr_len(be, sizeof(struct virtio_net_rxhdr))) {
+		return (0);
+	}
+
+	ret = tap_set_vnet_hdr_len(be, 0);
+	assert(ret == 0);
+
+	return (TAP_FEATURES);
 }
 
 static int
 tap_set_cap(struct net_backend *be, uint64_t features,
 		unsigned vnet_hdr_len)
 {
+	int ret;
 
-	return ((features || vnet_hdr_len) ? -1 : 0);
+	ret = tap_set_vnet_hdr_len(be, vnet_hdr_len);
+	assert(ret == 0);
+
+	be->be_vnet_hdr_len = vnet_hdr_len;
+
+	return 0;
 }
 
 static struct net_backend tap_backend = {
@@ -324,13 +432,6 @@
  * The netmap backend
  */
 
-/* The virtio-net features supported by netmap. */
-#define NETMAP_FEATURES (VIRTIO_NET_F_CSUM | VIRTIO_NET_F_HOST_TSO4 | \
-		VIRTIO_NET_F_HOST_TSO6 | VIRTIO_NET_F_HOST_UFO | \
-		VIRTIO_NET_F_GUEST_CSUM | VIRTIO_NET_F_GUEST_TSO4 | \
-		VIRTIO_NET_F_GUEST_TSO6 | VIRTIO_NET_F_GUEST_UFO | \
-		VIRTIO_NET_F_MRG_RXBUF)
-
 struct netmap_priv {
 	char ifname[IFNAMSIZ];
 	struct nm_desc *nmd;
@@ -415,8 +516,11 @@
 {
 	struct netmap_priv *priv = (struct netmap_priv *)be->opaque;
 
-	strlcpy(priv->ifname, devname, sizeof(priv->ifname));
-	priv->ifname[sizeof(priv->ifname) - 1] = '\0';
+	if (strlcpy(priv->ifname, devname, sizeof(priv->ifname)) >=
+	    sizeof(priv->ifname)) {
+		WPRINTF(("netmap interface name too long\n"));
+		return (-1);
+	}
 
 	priv->nmd = nm_open(priv->ifname, NULL, NETMAP_NO_TX_POLL, NULL);
 	if (priv->nmd == NULL) {