aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/Makefile2
-rw-r--r--net/ipv6/exthdrs.c44
-rw-r--r--net/ipv6/exthdrs_core.c44
-rw-r--r--net/ipv6/ip6_output.c65
-rw-r--r--net/ipv6/output_core.c76
5 files changed, 121 insertions, 110 deletions
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 7f250773ecc9..cdca302f395c 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -41,6 +41,6 @@ obj-$(CONFIG_IPV6_SIT) += sit.o
41obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o 41obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
42obj-$(CONFIG_IPV6_GRE) += ip6_gre.o 42obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
43 43
44obj-y += addrconf_core.o exthdrs_core.o 44obj-y += addrconf_core.o exthdrs_core.o output_core.o
45 45
46obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o 46obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 70fbf6bc5a87..a786a20ad823 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -50,50 +50,6 @@
50#include <asm/uaccess.h> 50#include <asm/uaccess.h>
51#include "ip6_offload.h" 51#include "ip6_offload.h"
52 52
53int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
54{
55 const unsigned char *nh = skb_network_header(skb);
56 int packet_len = skb->tail - skb->network_header;
57 struct ipv6_opt_hdr *hdr;
58 int len;
59
60 if (offset + 2 > packet_len)
61 goto bad;
62 hdr = (struct ipv6_opt_hdr *)(nh + offset);
63 len = ((hdr->hdrlen + 1) << 3);
64
65 if (offset + len > packet_len)
66 goto bad;
67
68 offset += 2;
69 len -= 2;
70
71 while (len > 0) {
72 int opttype = nh[offset];
73 int optlen;
74
75 if (opttype == type)
76 return offset;
77
78 switch (opttype) {
79 case IPV6_TLV_PAD1:
80 optlen = 1;
81 break;
82 default:
83 optlen = nh[offset + 1] + 2;
84 if (optlen > len)
85 goto bad;
86 break;
87 }
88 offset += optlen;
89 len -= optlen;
90 }
91 /* not_found */
92 bad:
93 return -1;
94}
95EXPORT_SYMBOL_GPL(ipv6_find_tlv);
96
97/* 53/*
98 * Parsing tlv encoded headers. 54 * Parsing tlv encoded headers.
99 * 55 *
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c
index f73d59a14131..e7d756e19d1d 100644
--- a/net/ipv6/exthdrs_core.c
+++ b/net/ipv6/exthdrs_core.c
@@ -111,3 +111,47 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
111 return start; 111 return start;
112} 112}
113EXPORT_SYMBOL(ipv6_skip_exthdr); 113EXPORT_SYMBOL(ipv6_skip_exthdr);
114
115int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
116{
117 const unsigned char *nh = skb_network_header(skb);
118 int packet_len = skb->tail - skb->network_header;
119 struct ipv6_opt_hdr *hdr;
120 int len;
121
122 if (offset + 2 > packet_len)
123 goto bad;
124 hdr = (struct ipv6_opt_hdr *)(nh + offset);
125 len = ((hdr->hdrlen + 1) << 3);
126
127 if (offset + len > packet_len)
128 goto bad;
129
130 offset += 2;
131 len -= 2;
132
133 while (len > 0) {
134 int opttype = nh[offset];
135 int optlen;
136
137 if (opttype == type)
138 return offset;
139
140 switch (opttype) {
141 case IPV6_TLV_PAD1:
142 optlen = 1;
143 break;
144 default:
145 optlen = nh[offset + 1] + 2;
146 if (optlen > len)
147 goto bad;
148 break;
149 }
150 offset += optlen;
151 len -= optlen;
152 }
153 /* not_found */
154 bad:
155 return -1;
156}
157EXPORT_SYMBOL_GPL(ipv6_find_tlv);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 3deaa4e2e8e2..5552d13ae92f 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -544,71 +544,6 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
544 skb_copy_secmark(to, from); 544 skb_copy_secmark(to, from);
545} 545}
546 546
547int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
548{
549 u16 offset = sizeof(struct ipv6hdr);
550 struct ipv6_opt_hdr *exthdr =
551 (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
552 unsigned int packet_len = skb->tail - skb->network_header;
553 int found_rhdr = 0;
554 *nexthdr = &ipv6_hdr(skb)->nexthdr;
555
556 while (offset + 1 <= packet_len) {
557
558 switch (**nexthdr) {
559
560 case NEXTHDR_HOP:
561 break;
562 case NEXTHDR_ROUTING:
563 found_rhdr = 1;
564 break;
565 case NEXTHDR_DEST:
566#if IS_ENABLED(CONFIG_IPV6_MIP6)
567 if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
568 break;
569#endif
570 if (found_rhdr)
571 return offset;
572 break;
573 default :
574 return offset;
575 }
576
577 offset += ipv6_optlen(exthdr);
578 *nexthdr = &exthdr->nexthdr;
579 exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
580 offset);
581 }
582
583 return offset;
584}
585
586void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
587{
588 static atomic_t ipv6_fragmentation_id;
589 int old, new;
590
591 if (rt && !(rt->dst.flags & DST_NOPEER)) {
592 struct inet_peer *peer;
593 struct net *net;
594
595 net = dev_net(rt->dst.dev);
596 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
597 if (peer) {
598 fhdr->identification = htonl(inet_getid(peer, 0));
599 inet_putpeer(peer);
600 return;
601 }
602 }
603 do {
604 old = atomic_read(&ipv6_fragmentation_id);
605 new = old + 1;
606 if (!new)
607 new = 1;
608 } while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old);
609 fhdr->identification = htonl(new);
610}
611
612int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) 547int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
613{ 548{
614 struct sk_buff *frag; 549 struct sk_buff *frag;
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
new file mode 100644
index 000000000000..c2e73e647e44
--- /dev/null
+++ b/net/ipv6/output_core.c
@@ -0,0 +1,76 @@
1/*
2 * IPv6 library code, needed by static components when full IPv6 support is
3 * not configured or static. These functions are needed by GSO/GRO implementation.
4 */
5#include <linux/export.h>
6#include <net/ipv6.h>
7#include <net/ip6_fib.h>
8
9void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
10{
11 static atomic_t ipv6_fragmentation_id;
12 int old, new;
13
14#if IS_ENABLED(CONFIG_IPV6)
15 if (rt && !(rt->dst.flags & DST_NOPEER)) {
16 struct inet_peer *peer;
17 struct net *net;
18
19 net = dev_net(rt->dst.dev);
20 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);
21 if (peer) {
22 fhdr->identification = htonl(inet_getid(peer, 0));
23 inet_putpeer(peer);
24 return;
25 }
26 }
27#endif
28 do {
29 old = atomic_read(&ipv6_fragmentation_id);
30 new = old + 1;
31 if (!new)
32 new = 1;
33 } while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old);
34 fhdr->identification = htonl(new);
35}
36EXPORT_SYMBOL(ipv6_select_ident);
37
38int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
39{
40 u16 offset = sizeof(struct ipv6hdr);
41 struct ipv6_opt_hdr *exthdr =
42 (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
43 unsigned int packet_len = skb->tail - skb->network_header;
44 int found_rhdr = 0;
45 *nexthdr = &ipv6_hdr(skb)->nexthdr;
46
47 while (offset + 1 <= packet_len) {
48
49 switch (**nexthdr) {
50
51 case NEXTHDR_HOP:
52 break;
53 case NEXTHDR_ROUTING:
54 found_rhdr = 1;
55 break;
56 case NEXTHDR_DEST:
57#if IS_ENABLED(CONFIG_IPV6_MIP6)
58 if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
59 break;
60#endif
61 if (found_rhdr)
62 return offset;
63 break;
64 default :
65 return offset;
66 }
67
68 offset += ipv6_optlen(exthdr);
69 *nexthdr = &exthdr->nexthdr;
70 exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
71 offset);
72 }
73
74 return offset;
75}
76EXPORT_SYMBOL(ip6_find_1stfragopt);