diff options
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r-- | net/core/skbuff.c | 82 |
1 files changed, 76 insertions, 6 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c1a33033cbe2..8d289697cc7a 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <linux/scatterlist.h> | 62 | #include <linux/scatterlist.h> |
63 | #include <linux/errqueue.h> | 63 | #include <linux/errqueue.h> |
64 | #include <linux/prefetch.h> | 64 | #include <linux/prefetch.h> |
65 | #include <linux/if_vlan.h> | ||
65 | 66 | ||
66 | #include <net/protocol.h> | 67 | #include <net/protocol.h> |
67 | #include <net/dst.h> | 68 | #include <net/dst.h> |
@@ -2646,7 +2647,7 @@ EXPORT_SYMBOL(skb_prepare_seq_read); | |||
2646 | * skb_seq_read() will return the remaining part of the block. | 2647 | * skb_seq_read() will return the remaining part of the block. |
2647 | * | 2648 | * |
2648 | * Note 1: The size of each block of data returned can be arbitrary, | 2649 | * Note 1: The size of each block of data returned can be arbitrary, |
2649 | * this limitation is the cost for zerocopy seqeuental | 2650 | * this limitation is the cost for zerocopy sequential |
2650 | * reads of potentially non linear data. | 2651 | * reads of potentially non linear data. |
2651 | * | 2652 | * |
2652 | * Note 2: Fragment lists within fragments are not implemented | 2653 | * Note 2: Fragment lists within fragments are not implemented |
@@ -2780,7 +2781,7 @@ EXPORT_SYMBOL(skb_find_text); | |||
2780 | /** | 2781 | /** |
2781 | * skb_append_datato_frags - append the user data to a skb | 2782 | * skb_append_datato_frags - append the user data to a skb |
2782 | * @sk: sock structure | 2783 | * @sk: sock structure |
2783 | * @skb: skb structure to be appened with user data. | 2784 | * @skb: skb structure to be appended with user data. |
2784 | * @getfrag: call back function to be used for getting the user data | 2785 | * @getfrag: call back function to be used for getting the user data |
2785 | * @from: pointer to user message iov | 2786 | * @from: pointer to user message iov |
2786 | * @length: length of the iov message | 2787 | * @length: length of the iov message |
@@ -2976,9 +2977,9 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, | |||
2976 | tail = nskb; | 2977 | tail = nskb; |
2977 | 2978 | ||
2978 | __copy_skb_header(nskb, head_skb); | 2979 | __copy_skb_header(nskb, head_skb); |
2979 | nskb->mac_len = head_skb->mac_len; | ||
2980 | 2980 | ||
2981 | skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom); | 2981 | skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom); |
2982 | skb_reset_mac_len(nskb); | ||
2982 | 2983 | ||
2983 | skb_copy_from_linear_data_offset(head_skb, -tnl_hlen, | 2984 | skb_copy_from_linear_data_offset(head_skb, -tnl_hlen, |
2984 | nskb->data - tnl_hlen, | 2985 | nskb->data - tnl_hlen, |
@@ -3151,6 +3152,9 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) | |||
3151 | NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE_STOLEN_HEAD; | 3152 | NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE_STOLEN_HEAD; |
3152 | goto done; | 3153 | goto done; |
3153 | } | 3154 | } |
3155 | /* switch back to head shinfo */ | ||
3156 | pinfo = skb_shinfo(p); | ||
3157 | |||
3154 | if (pinfo->frag_list) | 3158 | if (pinfo->frag_list) |
3155 | goto merge; | 3159 | goto merge; |
3156 | if (skb_gro_len(p) != pinfo->gso_size) | 3160 | if (skb_gro_len(p) != pinfo->gso_size) |
@@ -3490,10 +3494,10 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) | |||
3490 | } | 3494 | } |
3491 | EXPORT_SYMBOL(sock_queue_err_skb); | 3495 | EXPORT_SYMBOL(sock_queue_err_skb); |
3492 | 3496 | ||
3493 | void skb_tstamp_tx(struct sk_buff *orig_skb, | 3497 | void __skb_tstamp_tx(struct sk_buff *orig_skb, |
3494 | struct skb_shared_hwtstamps *hwtstamps) | 3498 | struct skb_shared_hwtstamps *hwtstamps, |
3499 | struct sock *sk, int tstype) | ||
3495 | { | 3500 | { |
3496 | struct sock *sk = orig_skb->sk; | ||
3497 | struct sock_exterr_skb *serr; | 3501 | struct sock_exterr_skb *serr; |
3498 | struct sk_buff *skb; | 3502 | struct sk_buff *skb; |
3499 | int err; | 3503 | int err; |
@@ -3521,12 +3525,26 @@ void skb_tstamp_tx(struct sk_buff *orig_skb, | |||
3521 | memset(serr, 0, sizeof(*serr)); | 3525 | memset(serr, 0, sizeof(*serr)); |
3522 | serr->ee.ee_errno = ENOMSG; | 3526 | serr->ee.ee_errno = ENOMSG; |
3523 | serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; | 3527 | serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; |
3528 | serr->ee.ee_info = tstype; | ||
3529 | if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) { | ||
3530 | serr->ee.ee_data = skb_shinfo(skb)->tskey; | ||
3531 | if (sk->sk_protocol == IPPROTO_TCP) | ||
3532 | serr->ee.ee_data -= sk->sk_tskey; | ||
3533 | } | ||
3524 | 3534 | ||
3525 | err = sock_queue_err_skb(sk, skb); | 3535 | err = sock_queue_err_skb(sk, skb); |
3526 | 3536 | ||
3527 | if (err) | 3537 | if (err) |
3528 | kfree_skb(skb); | 3538 | kfree_skb(skb); |
3529 | } | 3539 | } |
3540 | EXPORT_SYMBOL_GPL(__skb_tstamp_tx); | ||
3541 | |||
3542 | void skb_tstamp_tx(struct sk_buff *orig_skb, | ||
3543 | struct skb_shared_hwtstamps *hwtstamps) | ||
3544 | { | ||
3545 | return __skb_tstamp_tx(orig_skb, hwtstamps, orig_skb->sk, | ||
3546 | SCM_TSTAMP_SND); | ||
3547 | } | ||
3530 | EXPORT_SYMBOL_GPL(skb_tstamp_tx); | 3548 | EXPORT_SYMBOL_GPL(skb_tstamp_tx); |
3531 | 3549 | ||
3532 | void skb_complete_wifi_ack(struct sk_buff *skb, bool acked) | 3550 | void skb_complete_wifi_ack(struct sk_buff *skb, bool acked) |
@@ -3959,3 +3977,55 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) | |||
3959 | return shinfo->gso_size; | 3977 | return shinfo->gso_size; |
3960 | } | 3978 | } |
3961 | EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); | 3979 | EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); |
3980 | |||
3981 | static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) | ||
3982 | { | ||
3983 | if (skb_cow(skb, skb_headroom(skb)) < 0) { | ||
3984 | kfree_skb(skb); | ||
3985 | return NULL; | ||
3986 | } | ||
3987 | |||
3988 | memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN); | ||
3989 | skb->mac_header += VLAN_HLEN; | ||
3990 | return skb; | ||
3991 | } | ||
3992 | |||
3993 | struct sk_buff *skb_vlan_untag(struct sk_buff *skb) | ||
3994 | { | ||
3995 | struct vlan_hdr *vhdr; | ||
3996 | u16 vlan_tci; | ||
3997 | |||
3998 | if (unlikely(vlan_tx_tag_present(skb))) { | ||
3999 | /* vlan_tci is already set-up so leave this for another time */ | ||
4000 | return skb; | ||
4001 | } | ||
4002 | |||
4003 | skb = skb_share_check(skb, GFP_ATOMIC); | ||
4004 | if (unlikely(!skb)) | ||
4005 | goto err_free; | ||
4006 | |||
4007 | if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) | ||
4008 | goto err_free; | ||
4009 | |||
4010 | vhdr = (struct vlan_hdr *)skb->data; | ||
4011 | vlan_tci = ntohs(vhdr->h_vlan_TCI); | ||
4012 | __vlan_hwaccel_put_tag(skb, skb->protocol, vlan_tci); | ||
4013 | |||
4014 | skb_pull_rcsum(skb, VLAN_HLEN); | ||
4015 | vlan_set_encap_proto(skb, vhdr); | ||
4016 | |||
4017 | skb = skb_reorder_vlan_header(skb); | ||
4018 | if (unlikely(!skb)) | ||
4019 | goto err_free; | ||
4020 | |||
4021 | skb_reset_network_header(skb); | ||
4022 | skb_reset_transport_header(skb); | ||
4023 | skb_reset_mac_len(skb); | ||
4024 | |||
4025 | return skb; | ||
4026 | |||
4027 | err_free: | ||
4028 | kfree_skb(skb); | ||
4029 | return NULL; | ||
4030 | } | ||
4031 | EXPORT_SYMBOL(skb_vlan_untag); | ||