OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [tags/] [linux-2.6/] [linux-2.6.24_or32_unified_v2.3/] [net/] [ipv6/] [ip6_input.c] - Blame information for rev 8

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 *      IPv6 input
3
 *      Linux INET6 implementation
4
 *
5
 *      Authors:
6
 *      Pedro Roque             <roque@di.fc.ul.pt>
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
/* Changes
19
 *
20
 *      Mitsuru KANDA @USAGI and
21
 *      YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs().
22
 */
23
 
24
#include <linux/errno.h>
25
#include <linux/types.h>
26
#include <linux/socket.h>
27
#include <linux/sockios.h>
28
#include <linux/net.h>
29
#include <linux/netdevice.h>
30
#include <linux/in6.h>
31
#include <linux/icmpv6.h>
32
 
33
#include <linux/netfilter.h>
34
#include <linux/netfilter_ipv6.h>
35
 
36
#include <net/sock.h>
37
#include <net/snmp.h>
38
 
39
#include <net/ipv6.h>
40
#include <net/protocol.h>
41
#include <net/transp_v6.h>
42
#include <net/rawv6.h>
43
#include <net/ndisc.h>
44
#include <net/ip6_route.h>
45
#include <net/addrconf.h>
46
#include <net/xfrm.h>
47
 
48
 
49
 
50
inline int ip6_rcv_finish( struct sk_buff *skb)
51
{
52
        if (skb->dst == NULL)
53
                ip6_route_input(skb);
54
 
55
        return dst_input(skb);
56
}
57
 
58
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
59
{
60
        struct ipv6hdr *hdr;
61
        u32             pkt_len;
62
        struct inet6_dev *idev;
63
 
64
        if (dev->nd_net != &init_net) {
65
                kfree_skb(skb);
66
                return 0;
67
        }
68
 
69
        if (skb->pkt_type == PACKET_OTHERHOST) {
70
                kfree_skb(skb);
71
                return 0;
72
        }
73
 
74
        rcu_read_lock();
75
 
76
        idev = __in6_dev_get(skb->dev);
77
 
78
        IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES);
79
 
80
        if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
81
                IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
82
                rcu_read_unlock();
83
                goto out;
84
        }
85
 
86
        memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
87
 
88
        /*
89
         * Store incoming device index. When the packet will
90
         * be queued, we cannot refer to skb->dev anymore.
91
         *
92
         * BTW, when we send a packet for our own local address on a
93
         * non-loopback interface (e.g. ethX), it is being delivered
94
         * via the loopback interface (lo) here; skb->dev = loopback_dev.
95
         * It, however, should be considered as if it is being
96
         * arrived via the sending interface (ethX), because of the
97
         * nature of scoping architecture. --yoshfuji
98
         */
99
        IP6CB(skb)->iif = skb->dst ? ip6_dst_idev(skb->dst)->dev->ifindex : dev->ifindex;
100
 
101
        if (unlikely(!pskb_may_pull(skb, sizeof(*hdr))))
102
                goto err;
103
 
104
        hdr = ipv6_hdr(skb);
105
 
106
        if (hdr->version != 6)
107
                goto err;
108
 
109
        skb->transport_header = skb->network_header + sizeof(*hdr);
110
        IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
111
 
112
        pkt_len = ntohs(hdr->payload_len);
113
 
114
        /* pkt_len may be zero if Jumbo payload option is present */
115
        if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
116
                if (pkt_len + sizeof(struct ipv6hdr) > skb->len) {
117
                        IP6_INC_STATS_BH(idev, IPSTATS_MIB_INTRUNCATEDPKTS);
118
                        goto drop;
119
                }
120
                if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) {
121
                        IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
122
                        goto drop;
123
                }
124
                hdr = ipv6_hdr(skb);
125
        }
126
 
127
        if (hdr->nexthdr == NEXTHDR_HOP) {
128
                if (ipv6_parse_hopopts(skb) < 0) {
129
                        IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
130
                        rcu_read_unlock();
131
                        return 0;
132
                }
133
        }
134
 
135
        rcu_read_unlock();
136
 
137
        return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish);
138
err:
139
        IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
140
drop:
141
        rcu_read_unlock();
142
        kfree_skb(skb);
143
out:
144
        return 0;
145
}
146
 
147
/*
148
 *      Deliver the packet to the host
149
 */
150
 
151
 
152
static int ip6_input_finish(struct sk_buff *skb)
153
{
154
        struct inet6_protocol *ipprot;
155
        struct sock *raw_sk;
156
        unsigned int nhoff;
157
        int nexthdr;
158
        u8 hash;
159
        struct inet6_dev *idev;
160
 
161
        /*
162
         *      Parse extension headers
163
         */
164
 
165
        rcu_read_lock();
166
resubmit:
167
        idev = ip6_dst_idev(skb->dst);
168
        if (!pskb_pull(skb, skb_transport_offset(skb)))
169
                goto discard;
170
        nhoff = IP6CB(skb)->nhoff;
171
        nexthdr = skb_network_header(skb)[nhoff];
172
 
173
        raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]);
174
        if (raw_sk && !ipv6_raw_deliver(skb, nexthdr))
175
                raw_sk = NULL;
176
 
177
        hash = nexthdr & (MAX_INET_PROTOS - 1);
178
        if ((ipprot = rcu_dereference(inet6_protos[hash])) != NULL) {
179
                int ret;
180
 
181
                if (ipprot->flags & INET6_PROTO_FINAL) {
182
                        struct ipv6hdr *hdr;
183
 
184
                        /* Free reference early: we don't need it any more,
185
                           and it may hold ip_conntrack module loaded
186
                           indefinitely. */
187
                        nf_reset(skb);
188
 
189
                        skb_postpull_rcsum(skb, skb_network_header(skb),
190
                                           skb_network_header_len(skb));
191
                        hdr = ipv6_hdr(skb);
192
                        if (ipv6_addr_is_multicast(&hdr->daddr) &&
193
                            !ipv6_chk_mcast_addr(skb->dev, &hdr->daddr,
194
                            &hdr->saddr) &&
195
                            !ipv6_is_mld(skb, nexthdr))
196
                                goto discard;
197
                }
198
                if (!(ipprot->flags & INET6_PROTO_NOPOLICY) &&
199
                    !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
200
                        goto discard;
201
 
202
                ret = ipprot->handler(skb);
203
                if (ret > 0)
204
                        goto resubmit;
205
                else if (ret == 0)
206
                        IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS);
207
        } else {
208
                if (!raw_sk) {
209
                        if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
210
                                IP6_INC_STATS_BH(idev, IPSTATS_MIB_INUNKNOWNPROTOS);
211
                                icmpv6_send(skb, ICMPV6_PARAMPROB,
212
                                            ICMPV6_UNK_NEXTHDR, nhoff,
213
                                            skb->dev);
214
                        }
215
                } else
216
                        IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS);
217
                kfree_skb(skb);
218
        }
219
        rcu_read_unlock();
220
        return 0;
221
 
222
discard:
223
        IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
224
        rcu_read_unlock();
225
        kfree_skb(skb);
226
        return 0;
227
}
228
 
229
 
230
int ip6_input(struct sk_buff *skb)
231
{
232
        return NF_HOOK(PF_INET6,NF_IP6_LOCAL_IN, skb, skb->dev, NULL, ip6_input_finish);
233
}
234
 
235
int ip6_mc_input(struct sk_buff *skb)
236
{
237
        struct ipv6hdr *hdr;
238
        int deliver;
239
 
240
        IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCASTPKTS);
241
 
242
        hdr = ipv6_hdr(skb);
243
        deliver = unlikely(skb->dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) ||
244
            ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);
245
 
246
        /*
247
         *      IPv6 multicast router mode isnt currently supported.
248
         */
249
#if 0
250
        if (ipv6_config.multicast_route) {
251
                int addr_type;
252
 
253
                addr_type = ipv6_addr_type(&hdr->daddr);
254
 
255
                if (!(addr_type & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_LINKLOCAL))) {
256
                        struct sk_buff *skb2;
257
                        struct dst_entry *dst;
258
 
259
                        dst = skb->dst;
260
 
261
                        if (deliver) {
262
                                skb2 = skb_clone(skb, GFP_ATOMIC);
263
                                dst_output(skb2);
264
                        } else {
265
                                dst_output(skb);
266
                                return 0;
267
                        }
268
                }
269
        }
270
#endif
271
 
272
        if (likely(deliver)) {
273
                ip6_input(skb);
274
                return 0;
275
        }
276
        /* discard */
277
        kfree_skb(skb);
278
 
279
        return 0;
280
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.