diff options
Diffstat (limited to 'net/nsh/nsh.c')
-rw-r--r-- | net/nsh/nsh.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/net/nsh/nsh.c b/net/nsh/nsh.c index 58fb827439a8..d7da99a0b0b8 100644 --- a/net/nsh/nsh.c +++ b/net/nsh/nsh.c | |||
@@ -14,6 +14,66 @@ | |||
14 | #include <net/nsh.h> | 14 | #include <net/nsh.h> |
15 | #include <net/tun_proto.h> | 15 | #include <net/tun_proto.h> |
16 | 16 | ||
17 | int nsh_push(struct sk_buff *skb, const struct nshhdr *pushed_nh) | ||
18 | { | ||
19 | struct nshhdr *nh; | ||
20 | size_t length = nsh_hdr_len(pushed_nh); | ||
21 | u8 next_proto; | ||
22 | |||
23 | if (skb->mac_len) { | ||
24 | next_proto = TUN_P_ETHERNET; | ||
25 | } else { | ||
26 | next_proto = tun_p_from_eth_p(skb->protocol); | ||
27 | if (!next_proto) | ||
28 | return -EAFNOSUPPORT; | ||
29 | } | ||
30 | |||
31 | /* Add the NSH header */ | ||
32 | if (skb_cow_head(skb, length) < 0) | ||
33 | return -ENOMEM; | ||
34 | |||
35 | skb_push(skb, length); | ||
36 | nh = (struct nshhdr *)(skb->data); | ||
37 | memcpy(nh, pushed_nh, length); | ||
38 | nh->np = next_proto; | ||
39 | skb_postpush_rcsum(skb, nh, length); | ||
40 | |||
41 | skb->protocol = htons(ETH_P_NSH); | ||
42 | skb_reset_mac_header(skb); | ||
43 | skb_reset_network_header(skb); | ||
44 | skb_reset_mac_len(skb); | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | EXPORT_SYMBOL_GPL(nsh_push); | ||
49 | |||
50 | int nsh_pop(struct sk_buff *skb) | ||
51 | { | ||
52 | struct nshhdr *nh; | ||
53 | size_t length; | ||
54 | __be16 inner_proto; | ||
55 | |||
56 | if (!pskb_may_pull(skb, NSH_BASE_HDR_LEN)) | ||
57 | return -ENOMEM; | ||
58 | nh = (struct nshhdr *)(skb->data); | ||
59 | length = nsh_hdr_len(nh); | ||
60 | inner_proto = tun_p_to_eth_p(nh->np); | ||
61 | if (!pskb_may_pull(skb, length)) | ||
62 | return -ENOMEM; | ||
63 | |||
64 | if (!inner_proto) | ||
65 | return -EAFNOSUPPORT; | ||
66 | |||
67 | skb_pull_rcsum(skb, length); | ||
68 | skb_reset_mac_header(skb); | ||
69 | skb_reset_network_header(skb); | ||
70 | skb_reset_mac_len(skb); | ||
71 | skb->protocol = inner_proto; | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(nsh_pop); | ||
76 | |||
17 | static struct sk_buff *nsh_gso_segment(struct sk_buff *skb, | 77 | static struct sk_buff *nsh_gso_segment(struct sk_buff *skb, |
18 | netdev_features_t features) | 78 | netdev_features_t features) |
19 | { | 79 | { |