Blame view
net/ipv6/ip6_input.c
8.46 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 |
/* * IPv6 input |
1ab1457c4 [NET] IPV6: Fix w... |
3 |
* Linux INET6 implementation |
1da177e4c Linux-2.6.12-rc2 |
4 5 6 7 8 |
* * Authors: * Pedro Roque <roque@di.fc.ul.pt> * Ian P. Morris <I.P.Morris@soton.ac.uk> * |
1da177e4c Linux-2.6.12-rc2 |
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
* Based in linux/net/ipv4/ip_input.c * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ /* Changes * * Mitsuru KANDA @USAGI and * YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs(). */ #include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> #include <linux/sockios.h> |
1da177e4c Linux-2.6.12-rc2 |
26 27 28 29 |
#include <linux/net.h> #include <linux/netdevice.h> #include <linux/in6.h> #include <linux/icmpv6.h> |
7bc570c8b [IPV6] MROUTE: Su... |
30 |
#include <linux/mroute6.h> |
5a0e3ad6a include cleanup: ... |
31 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include <linux/netfilter.h> #include <linux/netfilter_ipv6.h> #include <net/sock.h> #include <net/snmp.h> #include <net/ipv6.h> #include <net/protocol.h> #include <net/transp_v6.h> #include <net/rawv6.h> #include <net/ndisc.h> #include <net/ip6_route.h> #include <net/addrconf.h> #include <net/xfrm.h> |
c7109986d ipv6: Early TCP s... |
47 |
int ip6_rcv_finish(struct sk_buff *skb) |
1da177e4c Linux-2.6.12-rc2 |
48 |
{ |
c7109986d ipv6: Early TCP s... |
49 50 |
if (sysctl_ip_early_demux && !skb_dst(skb)) { const struct inet6_protocol *ipprot; |
c7109986d ipv6: Early TCP s... |
51 52 53 |
ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]); if (ipprot && ipprot->early_demux) ipprot->early_demux(skb); |
c7109986d ipv6: Early TCP s... |
54 55 |
} if (!skb_dst(skb)) |
1da177e4c Linux-2.6.12-rc2 |
56 57 58 59 |
ip6_route_input(skb); return dst_input(skb); } |
f2ccd8fa0 [NET]: Kill skb->... |
60 |
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) |
1da177e4c Linux-2.6.12-rc2 |
61 |
{ |
b71d1d426 inet: constify ip... |
62 |
const struct ipv6hdr *hdr; |
1da177e4c Linux-2.6.12-rc2 |
63 |
u32 pkt_len; |
a11d206d0 [IPV6]: Per-inter... |
64 |
struct inet6_dev *idev; |
483a47d2f ipv6: added net a... |
65 |
struct net *net = dev_net(skb->dev); |
1da177e4c Linux-2.6.12-rc2 |
66 |
|
a11d206d0 [IPV6]: Per-inter... |
67 68 |
if (skb->pkt_type == PACKET_OTHERHOST) { kfree_skb(skb); |
5c91face5 ipv6: correct ret... |
69 |
return NET_RX_DROP; |
a11d206d0 [IPV6]: Per-inter... |
70 71 72 |
} rcu_read_lock(); |
1da177e4c Linux-2.6.12-rc2 |
73 |
|
a11d206d0 [IPV6]: Per-inter... |
74 |
idev = __in6_dev_get(skb->dev); |
edf391ff1 snmp: add missing... |
75 |
IP6_UPD_PO_STATS_BH(net, idev, IPSTATS_MIB_IN, skb->len); |
1da177e4c Linux-2.6.12-rc2 |
76 |
|
778d80be5 ipv6: Add disable... |
77 78 |
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || !idev || unlikely(idev->cnf.disable_ipv6)) { |
483a47d2f ipv6: added net a... |
79 |
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDISCARDS); |
71f6f6dfd ipv6: Plug sk_buf... |
80 |
goto drop; |
1da177e4c Linux-2.6.12-rc2 |
81 |
} |
6b7fdc3ae [IPV6]: Clean skb... |
82 |
memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); |
1da177e4c Linux-2.6.12-rc2 |
83 84 85 86 87 88 |
/* * Store incoming device index. When the packet will * be queued, we cannot refer to skb->dev anymore. * * BTW, when we send a packet for our own local address on a * non-loopback interface (e.g. ethX), it is being delivered |
de3cb747f [NET]: Dynamicall... |
89 |
* via the loopback interface (lo) here; skb->dev = loopback_dev. |
1da177e4c Linux-2.6.12-rc2 |
90 91 92 93 |
* It, however, should be considered as if it is being * arrived via the sending interface (ethX), because of the * nature of scoping architecture. --yoshfuji */ |
adf30907d net: skb->dst acc... |
94 |
IP6CB(skb)->iif = skb_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex; |
1da177e4c Linux-2.6.12-rc2 |
95 |
|
2889139a6 [IPV6]: Remove re... |
96 |
if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) |
1da177e4c Linux-2.6.12-rc2 |
97 |
goto err; |
0660e03f6 [SK_BUFF]: Introd... |
98 |
hdr = ipv6_hdr(skb); |
1da177e4c Linux-2.6.12-rc2 |
99 100 101 |
if (hdr->version != 6) goto err; |
f630e43a2 ipv6: Drop packet... |
102 103 104 105 106 107 108 109 |
/* * RFC4291 2.5.3 * A packet received on an interface with a destination address * of loopback must be dropped. */ if (!(dev->flags & IFF_LOOPBACK) && ipv6_addr_loopback(&hdr->daddr)) goto err; |
1c4a154e5 ipv6: don't accep... |
110 111 112 113 114 115 116 117 118 119 120 |
/* RFC4291 Errata ID: 3480 * Interface-Local scope spans only a single interface on a * node and is useful only for loopback transmission of * multicast. Packets with interface-local scope received * from another node must be discarded. */ if (!(skb->pkt_type == PACKET_LOOPBACK || dev->flags & IFF_LOOPBACK) && ipv6_addr_is_multicast(&hdr->daddr) && IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1) goto err; |
20314092c ipv6: don't accep... |
121 122 123 124 125 126 127 128 |
/* RFC4291 2.7 * Nodes must not originate a packet to a multicast address whose scope * field contains the reserved value 0; if such a packet is received, it * must be silently dropped. */ if (ipv6_addr_is_multicast(&hdr->daddr) && IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0) goto err; |
c457338d7 ipv6: drop packet... |
129 130 131 132 133 134 135 |
/* * RFC4291 2.7 * Multicast addresses must not be used as source addresses in IPv6 * packets or appear in any Routing header. */ if (ipv6_addr_is_multicast(&hdr->saddr)) goto err; |
b0e380b1d [SK_BUFF]: unions... |
136 |
skb->transport_header = skb->network_header + sizeof(*hdr); |
951dbc8ac [IPV6]: Move next... |
137 |
IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); |
1da177e4c Linux-2.6.12-rc2 |
138 139 140 141 |
pkt_len = ntohs(hdr->payload_len); /* pkt_len may be zero if Jumbo payload option is present */ if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { |
60e5c1664 [IPv6]: Exclude t... |
142 |
if (pkt_len + sizeof(struct ipv6hdr) > skb->len) { |
483a47d2f ipv6: added net a... |
143 144 |
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INTRUNCATEDPKTS); |
60e5c1664 [IPv6]: Exclude t... |
145 146 |
goto drop; } |
1da177e4c Linux-2.6.12-rc2 |
147 |
if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { |
483a47d2f ipv6: added net a... |
148 |
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS); |
1da177e4c Linux-2.6.12-rc2 |
149 150 |
goto drop; } |
0660e03f6 [SK_BUFF]: Introd... |
151 |
hdr = ipv6_hdr(skb); |
1da177e4c Linux-2.6.12-rc2 |
152 153 154 |
} if (hdr->nexthdr == NEXTHDR_HOP) { |
e5bbef20e [IPV6]: Replace s... |
155 |
if (ipv6_parse_hopopts(skb) < 0) { |
483a47d2f ipv6: added net a... |
156 |
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS); |
a11d206d0 [IPV6]: Per-inter... |
157 |
rcu_read_unlock(); |
5c91face5 ipv6: correct ret... |
158 |
return NET_RX_DROP; |
1da177e4c Linux-2.6.12-rc2 |
159 |
} |
1da177e4c Linux-2.6.12-rc2 |
160 |
} |
a11d206d0 [IPV6]: Per-inter... |
161 |
rcu_read_unlock(); |
71f9dacd2 inet: Call skb_or... |
162 163 |
/* Must drop socket now because of tproxy. */ skb_orphan(skb); |
b2e0b385d netfilter: ipv6: ... |
164 |
return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, dev, NULL, |
6e23ae2a4 [NETFILTER]: Intr... |
165 |
ip6_rcv_finish); |
1da177e4c Linux-2.6.12-rc2 |
166 |
err: |
483a47d2f ipv6: added net a... |
167 |
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS); |
1da177e4c Linux-2.6.12-rc2 |
168 |
drop: |
a11d206d0 [IPV6]: Per-inter... |
169 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
170 |
kfree_skb(skb); |
5c91face5 ipv6: correct ret... |
171 |
return NET_RX_DROP; |
1da177e4c Linux-2.6.12-rc2 |
172 173 174 175 176 |
} /* * Deliver the packet to the host */ |
ad643a793 [IPV6]: Uninline ... |
177 |
static int ip6_input_finish(struct sk_buff *skb) |
1da177e4c Linux-2.6.12-rc2 |
178 |
{ |
f9242b6b2 inet: Sanitize in... |
179 |
struct net *net = dev_net(skb_dst(skb)->dev); |
41135cc83 net: constify str... |
180 |
const struct inet6_protocol *ipprot; |
f9242b6b2 inet: Sanitize in... |
181 |
struct inet6_dev *idev; |
1da177e4c Linux-2.6.12-rc2 |
182 |
unsigned int nhoff; |
a50feda54 ipv6: bool/const ... |
183 184 |
int nexthdr; bool raw; |
1da177e4c Linux-2.6.12-rc2 |
185 |
|
1da177e4c Linux-2.6.12-rc2 |
186 187 188 |
/* * Parse extension headers */ |
1da177e4c Linux-2.6.12-rc2 |
189 190 |
rcu_read_lock(); resubmit: |
adf30907d net: skb->dst acc... |
191 |
idev = ip6_dst_idev(skb_dst(skb)); |
ea2ae17d6 [SK_BUFF]: Introd... |
192 |
if (!pskb_pull(skb, skb_transport_offset(skb))) |
1da177e4c Linux-2.6.12-rc2 |
193 |
goto discard; |
951dbc8ac [IPV6]: Move next... |
194 |
nhoff = IP6CB(skb)->nhoff; |
d56f90a7c [SK_BUFF]: Introd... |
195 |
nexthdr = skb_network_header(skb)[nhoff]; |
1da177e4c Linux-2.6.12-rc2 |
196 |
|
69d6da0b0 [IPv6] RAW: Compa... |
197 |
raw = raw6_local_deliver(skb, nexthdr); |
f9242b6b2 inet: Sanitize in... |
198 |
if ((ipprot = rcu_dereference(inet6_protos[nexthdr])) != NULL) { |
1da177e4c Linux-2.6.12-rc2 |
199 |
int ret; |
1ab1457c4 [NET] IPV6: Fix w... |
200 |
|
1da177e4c Linux-2.6.12-rc2 |
201 |
if (ipprot->flags & INET6_PROTO_FINAL) { |
b71d1d426 inet: constify ip... |
202 |
const struct ipv6hdr *hdr; |
1da177e4c Linux-2.6.12-rc2 |
203 |
|
9fb9cbb10 [NETFILTER]: Add ... |
204 205 206 207 |
/* Free reference early: we don't need it any more, and it may hold ip_conntrack module loaded indefinitely. */ nf_reset(skb); |
d56f90a7c [SK_BUFF]: Introd... |
208 |
skb_postpull_rcsum(skb, skb_network_header(skb), |
cfe1fc775 [SK_BUFF]: Introd... |
209 |
skb_network_header_len(skb)); |
0660e03f6 [SK_BUFF]: Introd... |
210 |
hdr = ipv6_hdr(skb); |
1da177e4c Linux-2.6.12-rc2 |
211 212 213 |
if (ipv6_addr_is_multicast(&hdr->daddr) && !ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, &hdr->saddr) && |
daad15126 ipv6: Make ipv6_i... |
214 |
!ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) |
1da177e4c Linux-2.6.12-rc2 |
215 216 217 |
goto discard; } if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && |
1ab1457c4 [NET] IPV6: Fix w... |
218 |
!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) |
1da177e4c Linux-2.6.12-rc2 |
219 |
goto discard; |
1ab1457c4 [NET] IPV6: Fix w... |
220 |
|
e5bbef20e [IPV6]: Replace s... |
221 |
ret = ipprot->handler(skb); |
1da177e4c Linux-2.6.12-rc2 |
222 223 224 |
if (ret > 0) goto resubmit; else if (ret == 0) |
483a47d2f ipv6: added net a... |
225 |
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS); |
1da177e4c Linux-2.6.12-rc2 |
226 |
} else { |
69d6da0b0 [IPv6] RAW: Compa... |
227 |
if (!raw) { |
1da177e4c Linux-2.6.12-rc2 |
228 |
if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { |
483a47d2f ipv6: added net a... |
229 230 |
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INUNKNOWNPROTOS); |
fad87acae [IPV6]: Fix SKB l... |
231 |
icmpv6_send(skb, ICMPV6_PARAMPROB, |
3ffe533c8 ipv6: drop unused... |
232 |
ICMPV6_UNK_NEXTHDR, nhoff); |
1da177e4c Linux-2.6.12-rc2 |
233 |
} |
d8c6f4b9b ipv[4|6]: correct... |
234 235 |
kfree_skb(skb); } else { |
483a47d2f ipv6: added net a... |
236 |
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS); |
d8c6f4b9b ipv[4|6]: correct... |
237 238 |
consume_skb(skb); } |
1da177e4c Linux-2.6.12-rc2 |
239 240 241 242 243 |
} rcu_read_unlock(); return 0; discard: |
483a47d2f ipv6: added net a... |
244 |
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDISCARDS); |
1da177e4c Linux-2.6.12-rc2 |
245 246 247 248 249 250 251 252 |
rcu_read_unlock(); kfree_skb(skb); return 0; } int ip6_input(struct sk_buff *skb) { |
b2e0b385d netfilter: ipv6: ... |
253 |
return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, skb, skb->dev, NULL, |
6e23ae2a4 [NETFILTER]: Intr... |
254 |
ip6_input_finish); |
1da177e4c Linux-2.6.12-rc2 |
255 256 257 258 |
} int ip6_mc_input(struct sk_buff *skb) { |
b71d1d426 inet: constify ip... |
259 |
const struct ipv6hdr *hdr; |
a50feda54 ipv6: bool/const ... |
260 |
bool deliver; |
1da177e4c Linux-2.6.12-rc2 |
261 |
|
adf30907d net: skb->dst acc... |
262 263 |
IP6_UPD_PO_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INMCAST, |
edf391ff1 snmp: add missing... |
264 |
skb->len); |
1da177e4c Linux-2.6.12-rc2 |
265 |
|
0660e03f6 [SK_BUFF]: Introd... |
266 |
hdr = ipv6_hdr(skb); |
4c7966b86 [IPV6] MCAST: Ens... |
267 |
deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL); |
1da177e4c Linux-2.6.12-rc2 |
268 |
|
7bc570c8b [IPV6] MROUTE: Su... |
269 |
#ifdef CONFIG_IPV6_MROUTE |
1da177e4c Linux-2.6.12-rc2 |
270 |
/* |
7bc570c8b [IPV6] MROUTE: Su... |
271 |
* IPv6 multicast router mode is now supported ;) |
1da177e4c Linux-2.6.12-rc2 |
272 |
*/ |
53b7997fd ipv6 netns: Make ... |
273 |
if (dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding && |
ddf64354a ipv6: stop multic... |
274 275 |
!(ipv6_addr_type(&hdr->daddr) & (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)) && |
7bc570c8b [IPV6] MROUTE: Su... |
276 277 278 279 280 281 282 283 284 |
likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) { /* * Okay, we try to forward - split and duplicate * packets. */ struct sk_buff *skb2; struct inet6_skb_parm *opt = IP6CB(skb); /* Check for MLD */ |
dd3332bfc ipv6: Store Route... |
285 |
if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) { |
7bc570c8b [IPV6] MROUTE: Su... |
286 |
/* Check if this is a mld message */ |
7bc570c8b [IPV6] MROUTE: Su... |
287 |
u8 nexthdr = hdr->nexthdr; |
75f2811c6 ipv6: Add fragmen... |
288 |
__be16 frag_off; |
7bc570c8b [IPV6] MROUTE: Su... |
289 290 291 292 293 |
int offset; /* Check if the value of Router Alert * is for MLD (0x0000). */ |
dd3332bfc ipv6: Store Route... |
294 |
if (opt->ra == htons(IPV6_OPT_ROUTERALERT_MLD)) { |
a50feda54 ipv6: bool/const ... |
295 |
deliver = false; |
aba6096b2 [IPV6]: Kill seve... |
296 |
|
7bc570c8b [IPV6] MROUTE: Su... |
297 298 |
if (!ipv6_ext_hdr(nexthdr)) { /* BUG */ |
aba6096b2 [IPV6]: Kill seve... |
299 |
goto out; |
7bc570c8b [IPV6] MROUTE: Su... |
300 301 |
} offset = ipv6_skip_exthdr(skb, sizeof(*hdr), |
75f2811c6 ipv6: Add fragmen... |
302 |
&nexthdr, &frag_off); |
7bc570c8b [IPV6] MROUTE: Su... |
303 |
if (offset < 0) |
aba6096b2 [IPV6]: Kill seve... |
304 |
goto out; |
7bc570c8b [IPV6] MROUTE: Su... |
305 |
|
daad15126 ipv6: Make ipv6_i... |
306 |
if (!ipv6_is_mld(skb, nexthdr, offset)) |
aba6096b2 [IPV6]: Kill seve... |
307 |
goto out; |
7bc570c8b [IPV6] MROUTE: Su... |
308 |
|
daad15126 ipv6: Make ipv6_i... |
309 |
deliver = true; |
7bc570c8b [IPV6] MROUTE: Su... |
310 311 312 |
} /* unknown RA - process it normally */ } |
1da177e4c Linux-2.6.12-rc2 |
313 |
|
7bc570c8b [IPV6] MROUTE: Su... |
314 315 316 317 318 319 |
if (deliver) skb2 = skb_clone(skb, GFP_ATOMIC); else { skb2 = skb; skb = NULL; } |
1ab1457c4 [NET] IPV6: Fix w... |
320 |
|
7bc570c8b [IPV6] MROUTE: Su... |
321 |
if (skb2) { |
7bc570c8b [IPV6] MROUTE: Su... |
322 |
ip6_mr_input(skb2); |
1da177e4c Linux-2.6.12-rc2 |
323 324 |
} } |
7bc570c8b [IPV6] MROUTE: Su... |
325 |
out: |
aba6096b2 [IPV6]: Kill seve... |
326 327 |
#endif if (likely(deliver)) |
1da177e4c Linux-2.6.12-rc2 |
328 |
ip6_input(skb); |
aba6096b2 [IPV6]: Kill seve... |
329 330 331 |
else { /* discard */ kfree_skb(skb); |
1da177e4c Linux-2.6.12-rc2 |
332 |
} |
1da177e4c Linux-2.6.12-rc2 |
333 334 335 |
return 0; } |