.. | .. |
---|
103 | 103 | if (gso_type && skb->network_header) { |
---|
104 | 104 | struct flow_keys_basic keys; |
---|
105 | 105 | |
---|
106 | | - if (!skb->protocol) |
---|
107 | | - virtio_net_hdr_set_proto(skb, hdr); |
---|
| 106 | + if (!skb->protocol) { |
---|
| 107 | + __be16 protocol = dev_parse_header_protocol(skb); |
---|
| 108 | + |
---|
| 109 | + if (!protocol) |
---|
| 110 | + virtio_net_hdr_set_proto(skb, hdr); |
---|
| 111 | + else if (!virtio_net_hdr_match_proto(protocol, hdr->gso_type)) |
---|
| 112 | + return -EINVAL; |
---|
| 113 | + else |
---|
| 114 | + skb->protocol = protocol; |
---|
| 115 | + } |
---|
108 | 116 | retry: |
---|
109 | | - if (!skb_flow_dissect_flow_keys_basic(skb, &keys, |
---|
| 117 | + if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys, |
---|
110 | 118 | NULL, 0, 0, 0, |
---|
111 | 119 | 0)) { |
---|
112 | 120 | /* UFO does not specify ipv4 or 6: try both */ |
---|
.. | .. |
---|
140 | 148 | if (gso_type & SKB_GSO_UDP) |
---|
141 | 149 | nh_off -= thlen; |
---|
142 | 150 | |
---|
| 151 | + /* Kernel has a special handling for GSO_BY_FRAGS. */ |
---|
| 152 | + if (gso_size == GSO_BY_FRAGS) |
---|
| 153 | + return -EINVAL; |
---|
| 154 | + |
---|
143 | 155 | /* Too small packets are not really GSO ones. */ |
---|
144 | 156 | if (skb->len - nh_off > gso_size) { |
---|
145 | 157 | shinfo->gso_size = gso_size; |
---|