tun.c (93cd6fa6806cb3455e8231578840afb031606352) tun.c (cbbd26b8b1a6af9c02e2b6523e12bd50cc765059)
1/*
2 * TUN - Universal TUN/TAP device driver.
3 * Copyright (C) 1999-2002 Maxim Krasnyansky <maxk@qualcomm.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.

--- 1157 unchanged lines hidden (view full) ---

1166 size_t len = total_len, align = tun->align, linear;
1167 struct virtio_net_hdr gso = { 0 };
1168 struct tun_pcpu_stats *stats;
1169 int good_linear;
1170 int copylen;
1171 bool zerocopy = false;
1172 int err;
1173 u32 rxhash;
1/*
2 * TUN - Universal TUN/TAP device driver.
3 * Copyright (C) 1999-2002 Maxim Krasnyansky <maxk@qualcomm.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.

--- 1157 unchanged lines hidden (view full) ---

1166 size_t len = total_len, align = tun->align, linear;
1167 struct virtio_net_hdr gso = { 0 };
1168 struct tun_pcpu_stats *stats;
1169 int good_linear;
1170 int copylen;
1171 bool zerocopy = false;
1172 int err;
1173 u32 rxhash;
1174 ssize_t n;
1175
1176 if (!(tun->dev->flags & IFF_UP))
1177 return -EIO;
1178
1179 if (!(tun->flags & IFF_NO_PI)) {
1180 if (len < sizeof(pi))
1181 return -EINVAL;
1182 len -= sizeof(pi);
1183
1174
1175 if (!(tun->dev->flags & IFF_UP))
1176 return -EIO;
1177
1178 if (!(tun->flags & IFF_NO_PI)) {
1179 if (len < sizeof(pi))
1180 return -EINVAL;
1181 len -= sizeof(pi);
1182
1184 n = copy_from_iter(&pi, sizeof(pi), from);
1185 if (n != sizeof(pi))
1183 if (!copy_from_iter_full(&pi, sizeof(pi), from))
1186 return -EFAULT;
1187 }
1188
1189 if (tun->flags & IFF_VNET_HDR) {
1190 if (len < tun->vnet_hdr_sz)
1191 return -EINVAL;
1192 len -= tun->vnet_hdr_sz;
1193
1184 return -EFAULT;
1185 }
1186
1187 if (tun->flags & IFF_VNET_HDR) {
1188 if (len < tun->vnet_hdr_sz)
1189 return -EINVAL;
1190 len -= tun->vnet_hdr_sz;
1191
1194 n = copy_from_iter(&gso, sizeof(gso), from);
1195 if (n != sizeof(gso))
1192 if (!copy_from_iter_full(&gso, sizeof(gso), from))
1196 return -EFAULT;
1197
1198 if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
1199 tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2 > tun16_to_cpu(tun, gso.hdr_len))
1200 gso.hdr_len = cpu_to_tun16(tun, tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2);
1201
1202 if (tun16_to_cpu(tun, gso.hdr_len) > len)
1203 return -EINVAL;

--- 37 unchanged lines hidden (view full) ---

1241 if (IS_ERR(skb)) {
1242 if (PTR_ERR(skb) != -EAGAIN)
1243 this_cpu_inc(tun->pcpu_stats->rx_dropped);
1244 return PTR_ERR(skb);
1245 }
1246
1247 if (zerocopy)
1248 err = zerocopy_sg_from_iter(skb, from);
1193 return -EFAULT;
1194
1195 if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
1196 tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2 > tun16_to_cpu(tun, gso.hdr_len))
1197 gso.hdr_len = cpu_to_tun16(tun, tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2);
1198
1199 if (tun16_to_cpu(tun, gso.hdr_len) > len)
1200 return -EINVAL;

--- 37 unchanged lines hidden (view full) ---

1238 if (IS_ERR(skb)) {
1239 if (PTR_ERR(skb) != -EAGAIN)
1240 this_cpu_inc(tun->pcpu_stats->rx_dropped);
1241 return PTR_ERR(skb);
1242 }
1243
1244 if (zerocopy)
1245 err = zerocopy_sg_from_iter(skb, from);
1249 else
1246 else {
1250 err = skb_copy_datagram_from_iter(skb, 0, from, len);
1247 err = skb_copy_datagram_from_iter(skb, 0, from, len);
1248 if (!err && msg_control) {
1249 struct ubuf_info *uarg = msg_control;
1250 uarg->callback(uarg, false);
1251 }
1252 }
1251
1252 if (err) {
1253 this_cpu_inc(tun->pcpu_stats->rx_dropped);
1254 kfree_skb(skb);
1255 return -EFAULT;
1256 }
1257
1258 err = virtio_net_hdr_to_skb(skb, &gso, tun_is_little_endian(tun));

--- 29 unchanged lines hidden (view full) ---

1288 break;
1289 }
1290
1291 /* copy skb_ubuf_info for callback when skb has no error */
1292 if (zerocopy) {
1293 skb_shinfo(skb)->destructor_arg = msg_control;
1294 skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
1295 skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
1253
1254 if (err) {
1255 this_cpu_inc(tun->pcpu_stats->rx_dropped);
1256 kfree_skb(skb);
1257 return -EFAULT;
1258 }
1259
1260 err = virtio_net_hdr_to_skb(skb, &gso, tun_is_little_endian(tun));

--- 29 unchanged lines hidden (view full) ---

1290 break;
1291 }
1292
1293 /* copy skb_ubuf_info for callback when skb has no error */
1294 if (zerocopy) {
1295 skb_shinfo(skb)->destructor_arg = msg_control;
1296 skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
1297 skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
1296 } else if (msg_control) {
1297 struct ubuf_info *uarg = msg_control;
1298 uarg->callback(uarg, false);
1299 }
1300
1301 skb_reset_network_header(skb);
1302 skb_probe_transport_header(skb, 0);
1303
1304 rxhash = skb_get_hash(skb);
1305 netif_rx_ni(skb);
1306

--- 1263 unchanged lines hidden ---
1298 }
1299
1300 skb_reset_network_header(skb);
1301 skb_probe_transport_header(skb, 0);
1302
1303 rxhash = skb_get_hash(skb);
1304 netif_rx_ni(skb);
1305

--- 1263 unchanged lines hidden ---