diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/Makefile | 2 | ||||
-rw-r--r-- | net/ipv6/exthdrs.c | 44 | ||||
-rw-r--r-- | net/ipv6/exthdrs_core.c | 44 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 65 | ||||
-rw-r--r-- | net/ipv6/output_core.c | 76 |
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 | |||
41 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | 41 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
42 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o | 42 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o |
43 | 43 | ||
44 | obj-y += addrconf_core.o exthdrs_core.o | 44 | obj-y += addrconf_core.o exthdrs_core.o output_core.o |
45 | 45 | ||
46 | obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o | 46 | obj-$(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 | ||
53 | int 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 | } | ||
95 | EXPORT_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 | } |
113 | EXPORT_SYMBOL(ipv6_skip_exthdr); | 113 | EXPORT_SYMBOL(ipv6_skip_exthdr); |
114 | |||
115 | int 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 | } | ||
157 | EXPORT_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 | ||
547 | int 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 | |||
586 | void 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 | |||
612 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | 547 | int 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 | |||
9 | void 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 | } | ||
36 | EXPORT_SYMBOL(ipv6_select_ident); | ||
37 | |||
38 | int 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 | } | ||
76 | EXPORT_SYMBOL(ip6_find_1stfragopt); | ||