mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	tuntap: use common code for virtio_net_hdr and skb GSO conversion
Replace open coded conversion between virtio_net_hdr to skb GSO info with
virtio_net_hdr_{from,to}_skb
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
			
			
This commit is contained in:
		
							parent
							
								
									fd88d68b38
								
							
						
					
					
						commit
						3416609363
					
				
					 1 changed files with 21 additions and 76 deletions
				
			
		| 
						 | 
					@ -1254,15 +1254,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
 | 
				
			||||||
		return -EFAULT;
 | 
							return -EFAULT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
 | 
					 | 
				
			||||||
		if (!skb_partial_csum_set(skb, tun16_to_cpu(tun, gso.csum_start),
 | 
					 | 
				
			||||||
					  tun16_to_cpu(tun, gso.csum_offset))) {
 | 
					 | 
				
			||||||
			this_cpu_inc(tun->pcpu_stats->rx_frame_errors);
 | 
					 | 
				
			||||||
			kfree_skb(skb);
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (tun->flags & TUN_TYPE_MASK) {
 | 
						switch (tun->flags & TUN_TYPE_MASK) {
 | 
				
			||||||
	case IFF_TUN:
 | 
						case IFF_TUN:
 | 
				
			||||||
		if (tun->flags & IFF_NO_PI) {
 | 
							if (tun->flags & IFF_NO_PI) {
 | 
				
			||||||
| 
						 | 
					@ -1289,37 +1280,11 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
 | 
						err = virtio_net_hdr_to_skb(skb, &gso, tun_is_little_endian(tun));
 | 
				
			||||||
		pr_debug("GSO!\n");
 | 
						if (err) {
 | 
				
			||||||
		switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
 | 
							this_cpu_inc(tun->pcpu_stats->rx_frame_errors);
 | 
				
			||||||
		case VIRTIO_NET_HDR_GSO_TCPV4:
 | 
							kfree_skb(skb);
 | 
				
			||||||
			skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
 | 
							return -EINVAL;
 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case VIRTIO_NET_HDR_GSO_TCPV6:
 | 
					 | 
				
			||||||
			skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case VIRTIO_NET_HDR_GSO_UDP:
 | 
					 | 
				
			||||||
			skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			this_cpu_inc(tun->pcpu_stats->rx_frame_errors);
 | 
					 | 
				
			||||||
			kfree_skb(skb);
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (gso.gso_type & VIRTIO_NET_HDR_GSO_ECN)
 | 
					 | 
				
			||||||
			skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		skb_shinfo(skb)->gso_size = tun16_to_cpu(tun, gso.gso_size);
 | 
					 | 
				
			||||||
		if (skb_shinfo(skb)->gso_size == 0) {
 | 
					 | 
				
			||||||
			this_cpu_inc(tun->pcpu_stats->rx_frame_errors);
 | 
					 | 
				
			||||||
			kfree_skb(skb);
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Header must be checked, and gso_segs computed. */
 | 
					 | 
				
			||||||
		skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
 | 
					 | 
				
			||||||
		skb_shinfo(skb)->gso_segs = 0;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* copy skb_ubuf_info for callback when skb has no error */
 | 
						/* copy skb_ubuf_info for callback when skb has no error */
 | 
				
			||||||
| 
						 | 
					@ -1399,46 +1364,26 @@ static ssize_t tun_put_user(struct tun_struct *tun,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (vnet_hdr_sz) {
 | 
						if (vnet_hdr_sz) {
 | 
				
			||||||
		struct virtio_net_hdr gso = { 0 }; /* no info leak */
 | 
							struct virtio_net_hdr gso = { 0 }; /* no info leak */
 | 
				
			||||||
 | 
							int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (iov_iter_count(iter) < vnet_hdr_sz)
 | 
							if (iov_iter_count(iter) < vnet_hdr_sz)
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (skb_is_gso(skb)) {
 | 
							ret = virtio_net_hdr_from_skb(skb, &gso,
 | 
				
			||||||
 | 
										      tun_is_little_endian(tun));
 | 
				
			||||||
 | 
							if (ret) {
 | 
				
			||||||
			struct skb_shared_info *sinfo = skb_shinfo(skb);
 | 
								struct skb_shared_info *sinfo = skb_shinfo(skb);
 | 
				
			||||||
 | 
								pr_err("unexpected GSO type: "
 | 
				
			||||||
			/* This is a hint as to how much should be linear. */
 | 
								       "0x%x, gso_size %d, hdr_len %d\n",
 | 
				
			||||||
			gso.hdr_len = cpu_to_tun16(tun, skb_headlen(skb));
 | 
								       sinfo->gso_type, tun16_to_cpu(tun, gso.gso_size),
 | 
				
			||||||
			gso.gso_size = cpu_to_tun16(tun, sinfo->gso_size);
 | 
								       tun16_to_cpu(tun, gso.hdr_len));
 | 
				
			||||||
			if (sinfo->gso_type & SKB_GSO_TCPV4)
 | 
								print_hex_dump(KERN_ERR, "tun: ",
 | 
				
			||||||
				gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
 | 
									       DUMP_PREFIX_NONE,
 | 
				
			||||||
			else if (sinfo->gso_type & SKB_GSO_TCPV6)
 | 
									       16, 1, skb->head,
 | 
				
			||||||
				gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
 | 
									       min((int)tun16_to_cpu(tun, gso.hdr_len), 64), true);
 | 
				
			||||||
			else if (sinfo->gso_type & SKB_GSO_UDP)
 | 
								WARN_ON_ONCE(1);
 | 
				
			||||||
				gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
 | 
								return -EINVAL;
 | 
				
			||||||
			else {
 | 
							}
 | 
				
			||||||
				pr_err("unexpected GSO type: "
 | 
					 | 
				
			||||||
				       "0x%x, gso_size %d, hdr_len %d\n",
 | 
					 | 
				
			||||||
				       sinfo->gso_type, tun16_to_cpu(tun, gso.gso_size),
 | 
					 | 
				
			||||||
				       tun16_to_cpu(tun, gso.hdr_len));
 | 
					 | 
				
			||||||
				print_hex_dump(KERN_ERR, "tun: ",
 | 
					 | 
				
			||||||
					       DUMP_PREFIX_NONE,
 | 
					 | 
				
			||||||
					       16, 1, skb->head,
 | 
					 | 
				
			||||||
					       min((int)tun16_to_cpu(tun, gso.hdr_len), 64), true);
 | 
					 | 
				
			||||||
				WARN_ON_ONCE(1);
 | 
					 | 
				
			||||||
				return -EINVAL;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (sinfo->gso_type & SKB_GSO_TCP_ECN)
 | 
					 | 
				
			||||||
				gso.gso_type |= VIRTIO_NET_HDR_GSO_ECN;
 | 
					 | 
				
			||||||
		} else
 | 
					 | 
				
			||||||
			gso.gso_type = VIRTIO_NET_HDR_GSO_NONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (skb->ip_summed == CHECKSUM_PARTIAL) {
 | 
					 | 
				
			||||||
			gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
 | 
					 | 
				
			||||||
			gso.csum_start = cpu_to_tun16(tun, skb_checksum_start_offset(skb) +
 | 
					 | 
				
			||||||
						      vlan_hlen);
 | 
					 | 
				
			||||||
			gso.csum_offset = cpu_to_tun16(tun, skb->csum_offset);
 | 
					 | 
				
			||||||
		} else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
 | 
					 | 
				
			||||||
			gso.flags = VIRTIO_NET_HDR_F_DATA_VALID;
 | 
					 | 
				
			||||||
		} /* else everything is zero */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (copy_to_iter(&gso, sizeof(gso), iter) != sizeof(gso))
 | 
							if (copy_to_iter(&gso, sizeof(gso), iter) != sizeof(gso))
 | 
				
			||||||
			return -EFAULT;
 | 
								return -EFAULT;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue