~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/nsh/nsh.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Network Service Header
  4  *
  5  * Copyright (c) 2017 Red Hat, Inc. -- Jiri Benc <jbenc@redhat.com>
  6  */
  7 
  8 #include <linux/module.h>
  9 #include <linux/netdevice.h>
 10 #include <linux/skbuff.h>
 11 #include <net/gso.h>
 12 #include <net/nsh.h>
 13 #include <net/tun_proto.h>
 14 
 15 int nsh_push(struct sk_buff *skb, const struct nshhdr *pushed_nh)
 16 {
 17         struct nshhdr *nh;
 18         size_t length = nsh_hdr_len(pushed_nh);
 19         u8 next_proto;
 20 
 21         if (skb->mac_len) {
 22                 next_proto = TUN_P_ETHERNET;
 23         } else {
 24                 next_proto = tun_p_from_eth_p(skb->protocol);
 25                 if (!next_proto)
 26                         return -EAFNOSUPPORT;
 27         }
 28 
 29         /* Add the NSH header */
 30         if (skb_cow_head(skb, length) < 0)
 31                 return -ENOMEM;
 32 
 33         skb_push(skb, length);
 34         nh = (struct nshhdr *)(skb->data);
 35         memcpy(nh, pushed_nh, length);
 36         nh->np = next_proto;
 37         skb_postpush_rcsum(skb, nh, length);
 38 
 39         skb->protocol = htons(ETH_P_NSH);
 40         skb_reset_mac_header(skb);
 41         skb_reset_network_header(skb);
 42         skb_reset_mac_len(skb);
 43 
 44         return 0;
 45 }
 46 EXPORT_SYMBOL_GPL(nsh_push);
 47 
 48 int nsh_pop(struct sk_buff *skb)
 49 {
 50         struct nshhdr *nh;
 51         size_t length;
 52         __be16 inner_proto;
 53 
 54         if (!pskb_may_pull(skb, NSH_BASE_HDR_LEN))
 55                 return -ENOMEM;
 56         nh = (struct nshhdr *)(skb->data);
 57         length = nsh_hdr_len(nh);
 58         if (length < NSH_BASE_HDR_LEN)
 59                 return -EINVAL;
 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 
 77 static struct sk_buff *nsh_gso_segment(struct sk_buff *skb,
 78                                        netdev_features_t features)
 79 {
 80         unsigned int outer_hlen, mac_len, nsh_len;
 81         struct sk_buff *segs = ERR_PTR(-EINVAL);
 82         u16 mac_offset = skb->mac_header;
 83         __be16 outer_proto, proto;
 84 
 85         skb_reset_network_header(skb);
 86 
 87         outer_proto = skb->protocol;
 88         outer_hlen = skb_mac_header_len(skb);
 89         mac_len = skb->mac_len;
 90 
 91         if (unlikely(!pskb_may_pull(skb, NSH_BASE_HDR_LEN)))
 92                 goto out;
 93         nsh_len = nsh_hdr_len(nsh_hdr(skb));
 94         if (nsh_len < NSH_BASE_HDR_LEN)
 95                 goto out;
 96         if (unlikely(!pskb_may_pull(skb, nsh_len)))
 97                 goto out;
 98 
 99         proto = tun_p_to_eth_p(nsh_hdr(skb)->np);
100         if (!proto)
101                 goto out;
102 
103         __skb_pull(skb, nsh_len);
104 
105         skb_reset_mac_header(skb);
106         skb->mac_len = proto == htons(ETH_P_TEB) ? ETH_HLEN : 0;
107         skb->protocol = proto;
108 
109         features &= NETIF_F_SG;
110         segs = skb_mac_gso_segment(skb, features);
111         if (IS_ERR_OR_NULL(segs)) {
112                 skb_gso_error_unwind(skb, htons(ETH_P_NSH), nsh_len,
113                                      mac_offset, mac_len);
114                 goto out;
115         }
116 
117         for (skb = segs; skb; skb = skb->next) {
118                 skb->protocol = outer_proto;
119                 __skb_push(skb, nsh_len + outer_hlen);
120                 skb_reset_mac_header(skb);
121                 skb_set_network_header(skb, outer_hlen);
122                 skb->mac_len = mac_len;
123         }
124 
125 out:
126         return segs;
127 }
128 
129 static struct packet_offload nsh_packet_offload __read_mostly = {
130         .type = htons(ETH_P_NSH),
131         .priority = 15,
132         .callbacks = {
133                 .gso_segment = nsh_gso_segment,
134         },
135 };
136 
137 static int __init nsh_init_module(void)
138 {
139         dev_add_offload(&nsh_packet_offload);
140         return 0;
141 }
142 
143 static void __exit nsh_cleanup_module(void)
144 {
145         dev_remove_offload(&nsh_packet_offload);
146 }
147 
148 module_init(nsh_init_module);
149 module_exit(nsh_cleanup_module);
150 
151 MODULE_AUTHOR("Jiri Benc <jbenc@redhat.com>");
152 MODULE_DESCRIPTION("NSH protocol");
153 MODULE_LICENSE("GPL v2");
154 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php