diff options
-rw-r--r-- | drivers/net/tap.c | 74 |
1 files changed, 72 insertions, 2 deletions
diff --git a/drivers/net/tap.c b/drivers/net/tap.c index 7996ed7cbf18..a4ab4a791fe7 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c | |||
@@ -1146,14 +1146,84 @@ static const struct file_operations tap_fops = { | |||
1146 | #endif | 1146 | #endif |
1147 | }; | 1147 | }; |
1148 | 1148 | ||
1149 | static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp) | ||
1150 | { | ||
1151 | struct tun_xdp_hdr *hdr = xdp->data_hard_start; | ||
1152 | struct virtio_net_hdr *gso = &hdr->gso; | ||
1153 | int buflen = hdr->buflen; | ||
1154 | int vnet_hdr_len = 0; | ||
1155 | struct tap_dev *tap; | ||
1156 | struct sk_buff *skb; | ||
1157 | int err, depth; | ||
1158 | |||
1159 | if (q->flags & IFF_VNET_HDR) | ||
1160 | vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); | ||
1161 | |||
1162 | skb = build_skb(xdp->data_hard_start, buflen); | ||
1163 | if (!skb) { | ||
1164 | err = -ENOMEM; | ||
1165 | goto err; | ||
1166 | } | ||
1167 | |||
1168 | skb_reserve(skb, xdp->data - xdp->data_hard_start); | ||
1169 | skb_put(skb, xdp->data_end - xdp->data); | ||
1170 | |||
1171 | skb_set_network_header(skb, ETH_HLEN); | ||
1172 | skb_reset_mac_header(skb); | ||
1173 | skb->protocol = eth_hdr(skb)->h_proto; | ||
1174 | |||
1175 | if (vnet_hdr_len) { | ||
1176 | err = virtio_net_hdr_to_skb(skb, gso, tap_is_little_endian(q)); | ||
1177 | if (err) | ||
1178 | goto err_kfree; | ||
1179 | } | ||
1180 | |||
1181 | skb_probe_transport_header(skb, ETH_HLEN); | ||
1182 | |||
1183 | /* Move network header to the right position for VLAN tagged packets */ | ||
1184 | if ((skb->protocol == htons(ETH_P_8021Q) || | ||
1185 | skb->protocol == htons(ETH_P_8021AD)) && | ||
1186 | __vlan_get_protocol(skb, skb->protocol, &depth) != 0) | ||
1187 | skb_set_network_header(skb, depth); | ||
1188 | |||
1189 | rcu_read_lock(); | ||
1190 | tap = rcu_dereference(q->tap); | ||
1191 | if (tap) { | ||
1192 | skb->dev = tap->dev; | ||
1193 | dev_queue_xmit(skb); | ||
1194 | } else { | ||
1195 | kfree_skb(skb); | ||
1196 | } | ||
1197 | rcu_read_unlock(); | ||
1198 | |||
1199 | return 0; | ||
1200 | |||
1201 | err_kfree: | ||
1202 | kfree_skb(skb); | ||
1203 | err: | ||
1204 | rcu_read_lock(); | ||
1205 | tap = rcu_dereference(q->tap); | ||
1206 | if (tap && tap->count_tx_dropped) | ||
1207 | tap->count_tx_dropped(tap); | ||
1208 | rcu_read_unlock(); | ||
1209 | return err; | ||
1210 | } | ||
1211 | |||
1149 | static int tap_sendmsg(struct socket *sock, struct msghdr *m, | 1212 | static int tap_sendmsg(struct socket *sock, struct msghdr *m, |
1150 | size_t total_len) | 1213 | size_t total_len) |
1151 | { | 1214 | { |
1152 | struct tap_queue *q = container_of(sock, struct tap_queue, sock); | 1215 | struct tap_queue *q = container_of(sock, struct tap_queue, sock); |
1153 | struct tun_msg_ctl *ctl = m->msg_control; | 1216 | struct tun_msg_ctl *ctl = m->msg_control; |
1217 | struct xdp_buff *xdp; | ||
1218 | int i; | ||
1154 | 1219 | ||
1155 | if (ctl && ctl->type != TUN_MSG_UBUF) | 1220 | if (ctl && (ctl->type == TUN_MSG_PTR)) { |
1156 | return -EINVAL; | 1221 | for (i = 0; i < ctl->num; i++) { |
1222 | xdp = &((struct xdp_buff *)ctl->ptr)[i]; | ||
1223 | tap_get_user_xdp(q, xdp); | ||
1224 | } | ||
1225 | return 0; | ||
1226 | } | ||
1157 | 1227 | ||
1158 | return tap_get_user(q, ctl ? ctl->ptr : NULL, &m->msg_iter, | 1228 | return tap_get_user(q, ctl ? ctl->ptr : NULL, &m->msg_iter, |
1159 | m->msg_flags & MSG_DONTWAIT); | 1229 | m->msg_flags & MSG_DONTWAIT); |