1 /*
2  *	IPv6 input
3  *	Linux INET6 implementation
4  *
5  *	Authors:
6  *	Pedro Roque		<pedro_m@yahoo.com>
7  *	Ian P. Morris		<I.P.Morris@soton.ac.uk>
8  *
9  *	$Id: ip6_input.c,v 1.19 2000/12/13 18:31:50 davem Exp $
10  *
11  *	Based in linux/net/ipv4/ip_input.c
12  *
13  *	This program is free software; you can redistribute it and/or
14  *      modify it under the terms of the GNU General Public License
15  *      as published by the Free Software Foundation; either version
16  *      2 of the License, or (at your option) any later version.
17  */
18 
19 #include <linux/errno.h>
20 #include <linux/types.h>
21 #include <linux/socket.h>
22 #include <linux/sockios.h>
23 #include <linux/sched.h>
24 #include <linux/net.h>
25 #include <linux/netdevice.h>
26 #include <linux/in6.h>
27 #include <linux/icmpv6.h>
28 
29 #include <linux/netfilter.h>
30 #include <linux/netfilter_ipv6.h>
31 
32 #include <net/sock.h>
33 #include <net/snmp.h>
34 
35 #include <net/ipv6.h>
36 #include <net/protocol.h>
37 #include <net/transp_v6.h>
38 #include <net/rawv6.h>
39 #include <net/ndisc.h>
40 #include <net/ip6_route.h>
41 #include <net/addrconf.h>
42 
43 
44 
ip6_rcv_finish(struct sk_buff * skb)45 static inline int ip6_rcv_finish( struct sk_buff *skb)
46 {
47 	if (skb->dst == NULL)
48 		ip6_route_input(skb);
49 
50 	return skb->dst->input(skb);
51 }
52 
ipv6_rcv(struct sk_buff * skb,struct net_device * dev,struct packet_type * pt)53 int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
54 {
55 	struct ipv6hdr *hdr;
56 	u32 		pkt_len;
57 
58 	if (skb->pkt_type == PACKET_OTHERHOST)
59 		goto drop;
60 
61 	IP6_INC_STATS_BH(Ip6InReceives);
62 
63 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
64 		goto out;
65 
66 	/* Store incoming device index. When the packet will
67 	   be queued, we cannot refer to skb->dev anymore.
68 	 */
69 	((struct inet6_skb_parm *)skb->cb)->iif = dev->ifindex;
70 
71 	if (skb->len < sizeof(struct ipv6hdr))
72 		goto err;
73 
74 	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
75 		goto drop;
76 
77 	hdr = skb->nh.ipv6h;
78 
79 	if (hdr->version != 6)
80 		goto err;
81 
82 	pkt_len = ntohs(hdr->payload_len);
83 
84 	/* pkt_len may be zero if Jumbo payload option is present */
85 	if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
86 		if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
87 			goto truncated;
88 		if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
89 			if (__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr)))
90 				goto drop;
91 			hdr = skb->nh.ipv6h;
92 			if (skb->ip_summed == CHECKSUM_HW)
93 				skb->ip_summed = CHECKSUM_NONE;
94 		}
95 	}
96 
97 	if (hdr->nexthdr == NEXTHDR_HOP) {
98 		skb->h.raw = (u8*)(hdr+1);
99 		if (ipv6_parse_hopopts(skb, offsetof(struct ipv6hdr, nexthdr)) < 0) {
100 			IP6_INC_STATS_BH(Ip6InHdrErrors);
101 			return 0;
102 		}
103 		hdr = skb->nh.ipv6h;
104 	}
105 
106 	return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish);
107 truncated:
108 	IP6_INC_STATS_BH(Ip6InTruncatedPkts);
109 err:
110 	IP6_INC_STATS_BH(Ip6InHdrErrors);
111 drop:
112 	kfree_skb(skb);
113 out:
114 	return 0;
115 }
116 
117 /*
118  *	Deliver the packet to the host
119  */
120 
121 
ip6_input_finish(struct sk_buff * skb)122 static inline int ip6_input_finish(struct sk_buff *skb)
123 {
124 	struct ipv6hdr *hdr = skb->nh.ipv6h;
125 	struct inet6_protocol *ipprot;
126 	struct sock *raw_sk;
127 	int nhoff;
128 	int nexthdr;
129 	int found = 0;
130 	u8 hash;
131 
132 	skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
133 
134 	/*
135 	 *	Parse extension headers
136 	 */
137 
138 	nexthdr = hdr->nexthdr;
139 	nhoff = offsetof(struct ipv6hdr, nexthdr);
140 
141 	/* Skip  hop-by-hop options, they are already parsed. */
142 	if (nexthdr == NEXTHDR_HOP) {
143 		nhoff = sizeof(struct ipv6hdr);
144 		nexthdr = skb->h.raw[0];
145 		skb->h.raw += (skb->h.raw[1]+1)<<3;
146 	}
147 
148 	/* This check is sort of optimization.
149 	   It would be stupid to detect for optional headers,
150 	   which are missing with probability of 200%
151 	 */
152 	if (nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP) {
153 		nhoff = ipv6_parse_exthdrs(&skb, nhoff);
154 		if (nhoff < 0)
155 			return 0;
156 		nexthdr = skb->nh.raw[nhoff];
157 		hdr = skb->nh.ipv6h;
158 	}
159 
160 	if (!pskb_pull(skb, skb->h.raw - skb->data))
161 		goto discard;
162 
163 	if (skb->ip_summed == CHECKSUM_HW)
164 		skb->csum = csum_sub(skb->csum,
165 				     csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
166 
167 	raw_sk = raw_v6_htable[nexthdr&(MAX_INET_PROTOS-1)];
168 	if (raw_sk)
169 		raw_sk = ipv6_raw_deliver(skb, nexthdr);
170 
171 	hash = nexthdr & (MAX_INET_PROTOS - 1);
172 	for (ipprot = (struct inet6_protocol *) inet6_protos[hash];
173 	     ipprot != NULL;
174 	     ipprot = (struct inet6_protocol *) ipprot->next) {
175 		struct sk_buff *buff = skb;
176 
177 		if (ipprot->protocol != nexthdr)
178 			continue;
179 
180 		if (ipprot->copy || raw_sk)
181 			buff = skb_clone(skb, GFP_ATOMIC);
182 
183 		if (buff)
184 			ipprot->handler(buff);
185 		found = 1;
186 	}
187 
188 	if (raw_sk) {
189 		rawv6_rcv(raw_sk, skb);
190 		sock_put(raw_sk);
191 		found = 1;
192 	}
193 
194 	/*
195 	 *	not found: send ICMP parameter problem back
196 	 */
197 	if (!found) {
198 		IP6_INC_STATS_BH(Ip6InUnknownProtos);
199 		icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
200 	}
201 
202 	return 0;
203 
204 discard:
205 	kfree_skb(skb);
206 	return 0;
207 }
208 
209 
ip6_input(struct sk_buff * skb)210 int ip6_input(struct sk_buff *skb)
211 {
212 	return NF_HOOK(PF_INET6,NF_IP6_LOCAL_IN, skb, skb->dev, NULL, ip6_input_finish);
213 }
214 
ip6_mc_input(struct sk_buff * skb)215 int ip6_mc_input(struct sk_buff *skb)
216 {
217 	struct ipv6hdr *hdr;
218 	int deliver = 0;
219 	int discard = 1;
220 
221 	IP6_INC_STATS_BH(Ip6InMcastPkts);
222 
223 	hdr = skb->nh.ipv6h;
224 	if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, &hdr->saddr))
225 		deliver = 1;
226 
227 	/*
228 	 *	IPv6 multicast router mode isnt currently supported.
229 	 */
230 #if 0
231 	if (ipv6_config.multicast_route) {
232 		int addr_type;
233 
234 		addr_type = ipv6_addr_type(&hdr->daddr);
235 
236 		if (!(addr_type & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_LINKLOCAL))) {
237 			struct sk_buff *skb2;
238 			struct dst_entry *dst;
239 
240 			dst = skb->dst;
241 
242 			if (deliver) {
243 				skb2 = skb_clone(skb, GFP_ATOMIC);
244 			} else {
245 				discard = 0;
246 				skb2 = skb;
247 			}
248 
249 			dst->output(skb2);
250 		}
251 	}
252 #endif
253 
254 	if (deliver) {
255 		discard = 0;
256 		ip6_input(skb);
257 	}
258 
259 	if (discard)
260 		kfree_skb(skb);
261 
262 	return 0;
263 }
264