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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [ipv6/] [icmp.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      Internet Control Message Protocol (ICMPv6)
3
 *      Linux INET6 implementation
4
 *
5
 *      Authors:
6
 *      Pedro Roque             <roque@di.fc.ul.pt>
7
 *
8
 *      $Id: icmp.c,v 1.1.1.1 2004-04-15 01:14:46 phoenix Exp $
9
 *
10
 *      Based on net/ipv4/icmp.c
11
 *
12
 *      RFC 1885
13
 *
14
 *      This program is free software; you can redistribute it and/or
15
 *      modify it under the terms of the GNU General Public License
16
 *      as published by the Free Software Foundation; either version
17
 *      2 of the License, or (at your option) any later version.
18
 */
19
 
20
/*
21
 *      Changes:
22
 *
23
 *      Andi Kleen              :       exception handling
24
 *      Andi Kleen                      add rate limits. never reply to a icmp.
25
 *                                      add more length checks and other fixes.
26
 *      yoshfuji                :       ensure to sent parameter problem for
27
 *                                      fragments.
28
 *      YOSHIFUJI Hideaki @USAGI:       added sysctl for icmp rate limit.
29
 */
30
 
31
#include <linux/module.h>
32
#include <linux/errno.h>
33
#include <linux/types.h>
34
#include <linux/socket.h>
35
#include <linux/in.h>
36
#include <linux/kernel.h>
37
#include <linux/sched.h>
38
#include <linux/sockios.h>
39
#include <linux/net.h>
40
#include <linux/skbuff.h>
41
#include <linux/init.h>
42
 
43
#ifdef CONFIG_SYSCTL
44
#include <linux/sysctl.h>
45
#endif
46
 
47
#include <linux/inet.h>
48
#include <linux/netdevice.h>
49
#include <linux/icmpv6.h>
50
 
51
#include <net/ip.h>
52
#include <net/sock.h>
53
 
54
#include <net/ipv6.h>
55
#include <net/checksum.h>
56
#include <net/protocol.h>
57
#include <net/raw.h>
58
#include <net/rawv6.h>
59
#include <net/transp_v6.h>
60
#include <net/ip6_route.h>
61
#include <net/addrconf.h>
62
#include <net/icmp.h>
63
 
64
#include <asm/uaccess.h>
65
#include <asm/system.h>
66
 
67
struct icmpv6_mib icmpv6_statistics[NR_CPUS*2];
68
 
69
/*
70
 *      ICMP socket(s) for flow control.
71
 */
72
 
73
static struct socket *__icmpv6_socket[NR_CPUS];
74
#define icmpv6_socket   __icmpv6_socket[smp_processor_id()]
75
#define icmpv6_socket_cpu(X) __icmpv6_socket[(X)]
76
 
77
int icmpv6_rcv(struct sk_buff *skb);
78
 
79
static struct inet6_protocol icmpv6_protocol =
80
{
81
        icmpv6_rcv,             /* handler              */
82
        NULL,                   /* error control        */
83
        NULL,                   /* next                 */
84
        IPPROTO_ICMPV6,         /* protocol ID          */
85
        0,                       /* copy                 */
86
        NULL,                   /* data                 */
87
        "ICMPv6"                /* name                 */
88
};
89
 
90
struct icmpv6_msg {
91
        struct icmp6hdr         icmph;
92
        struct sk_buff          *skb;
93
        int                     offset;
94
        struct in6_addr         *daddr;
95
        int                     len;
96
        __u32                   csum;
97
};
98
 
99
 
100
static int icmpv6_xmit_lock(void)
101
{
102
        local_bh_disable();
103
        if (unlikely(!spin_trylock(&icmpv6_socket->sk->lock.slock))) {
104
                /* This can happen if the output path (f.e. SIT or
105
                 * ip6ip6 tunnel) signals dst_link_failure() for an
106
                 * outgoing ICMP6 packet.
107
                 */
108
                local_bh_enable();
109
                return 1;
110
        }
111
        return 0;
112
}
113
 
114
static void icmpv6_xmit_unlock(void)
115
{
116
        spin_unlock_bh(&icmpv6_socket->sk->lock.slock);
117
}
118
 
119
/*
120
 *      getfrag callback
121
 */
122
 
123
static int icmpv6_getfrag(const void *data, struct in6_addr *saddr,
124
                           char *buff, unsigned int offset, unsigned int len)
125
{
126
        struct icmpv6_msg *msg = (struct icmpv6_msg *) data;
127
        struct icmp6hdr *icmph;
128
        __u32 csum;
129
 
130
        if (offset) {
131
                csum = skb_copy_and_csum_bits(msg->skb, msg->offset +
132
                                              (offset - sizeof(struct icmp6hdr)),
133
                                              buff, len, msg->csum);
134
                msg->csum = csum;
135
                return 0;
136
        }
137
 
138
        csum = csum_partial_copy_nocheck((void *) &msg->icmph, buff,
139
                                         sizeof(struct icmp6hdr), msg->csum);
140
 
141
        csum = skb_copy_and_csum_bits(msg->skb, msg->offset,
142
                                      buff + sizeof(struct icmp6hdr),
143
                                      len - sizeof(struct icmp6hdr), csum);
144
 
145
        icmph = (struct icmp6hdr *) buff;
146
 
147
        icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,
148
                                             IPPROTO_ICMPV6, csum);
149
        return 0;
150
}
151
 
152
 
153
/*
154
 * Slightly more convenient version of icmpv6_send.
155
 */
156
void icmpv6_param_prob(struct sk_buff *skb, int code, int pos)
157
{
158
        icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev);
159
        kfree_skb(skb);
160
}
161
 
162
/*
163
 * Figure out, may we reply to this packet with icmp error.
164
 *
165
 * We do not reply, if:
166
 *      - it was icmp error message.
167
 *      - it is truncated, so that it is known, that protocol is ICMPV6
168
 *        (i.e. in the middle of some exthdr)
169
 *
170
 *      --ANK (980726)
171
 */
172
 
173
static int is_ineligible(struct sk_buff *skb)
174
{
175
        int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data;
176
        int len = skb->len - ptr;
177
        __u8 nexthdr = skb->nh.ipv6h->nexthdr;
178
 
179
        if (len < 0)
180
                return 1;
181
 
182
        ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len);
183
        if (ptr < 0)
184
                return 0;
185
        if (nexthdr == IPPROTO_ICMPV6) {
186
                u8 type;
187
                if (skb_copy_bits(skb, ptr+offsetof(struct icmp6hdr, icmp6_type),
188
                                  &type, 1)
189
                    || !(type & ICMPV6_INFOMSG_MASK))
190
                        return 1;
191
        }
192
        return 0;
193
}
194
 
195
int sysctl_icmpv6_time = 1*HZ;
196
 
197
/*
198
 * Check the ICMP output rate limit
199
 */
200
static inline int icmpv6_xrlim_allow(struct sock *sk, int type,
201
                                     struct flowi *fl)
202
{
203
        struct dst_entry *dst;
204
        int res = 0;
205
 
206
        /* Informational messages are not limited. */
207
        if (type & ICMPV6_INFOMSG_MASK)
208
                return 1;
209
 
210
        /* Do not limit pmtu discovery, it would break it. */
211
        if (type == ICMPV6_PKT_TOOBIG)
212
                return 1;
213
 
214
        /*
215
         * Look up the output route.
216
         * XXX: perhaps the expire for routing entries cloned by
217
         * this lookup should be more aggressive (not longer than timeout).
218
         */
219
        dst = ip6_route_output(sk, fl);
220
        if (dst->error) {
221
                IP6_INC_STATS(Ip6OutNoRoutes);
222
        } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
223
                res = 1;
224
        } else {
225
                struct rt6_info *rt = (struct rt6_info *)dst;
226
                int tmo = sysctl_icmpv6_time;
227
 
228
                /* Give more bandwidth to wider prefixes. */
229
                if (rt->rt6i_dst.plen < 128)
230
                        tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
231
 
232
                res = xrlim_allow(dst, tmo);
233
        }
234
        dst_release(dst);
235
        return res;
236
}
237
 
238
/*
239
 *      an inline helper for the "simple" if statement below
240
 *      checks if parameter problem report is caused by an
241
 *      unrecognized IPv6 option that has the Option Type
242
 *      highest-order two bits set to 10
243
 */
244
 
245
static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset)
246
{
247
        u8 optval;
248
 
249
        offset += skb->nh.raw - skb->data;
250
        if (skb_copy_bits(skb, offset, &optval, 1))
251
                return 1;
252
        return (optval&0xC0) == 0x80;
253
}
254
 
255
/*
256
 *      Send an ICMP message in response to a packet in error
257
 */
258
 
259
void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
260
                 struct net_device *dev)
261
{
262
        struct ipv6hdr *hdr = skb->nh.ipv6h;
263
        struct sock *sk = icmpv6_socket->sk;
264
        struct in6_addr *saddr = NULL;
265
        int iif = 0;
266
        struct icmpv6_msg msg;
267
        struct flowi fl;
268
        int addr_type = 0;
269
        int len;
270
 
271
        if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail)
272
                return;
273
 
274
        /*
275
         *      Make sure we respect the rules
276
         *      i.e. RFC 1885 2.4(e)
277
         *      Rule (e.1) is enforced by not using icmpv6_send
278
         *      in any code that processes icmp errors.
279
         */
280
        addr_type = ipv6_addr_type(&hdr->daddr);
281
 
282
        if (ipv6_chk_addr(&hdr->daddr, skb->dev))
283
                saddr = &hdr->daddr;
284
 
285
        /*
286
         *      Dest addr check
287
         */
288
 
289
        if ((addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST)) {
290
                if (type != ICMPV6_PKT_TOOBIG &&
291
                    !(type == ICMPV6_PARAMPROB &&
292
                      code == ICMPV6_UNK_OPTION &&
293
                      (opt_unrec(skb, info))))
294
                        return;
295
 
296
                saddr = NULL;
297
        }
298
 
299
        addr_type = ipv6_addr_type(&hdr->saddr);
300
 
301
        /*
302
         *      Source addr check
303
         */
304
 
305
        if (addr_type & IPV6_ADDR_LINKLOCAL)
306
                iif = skb->dev->ifindex;
307
 
308
        /*
309
         *      Must not send if we know that source is Anycast also.
310
         *      for now we don't know that.
311
         */
312
        if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
313
                if (net_ratelimit())
314
                        printk(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n");
315
                return;
316
        }
317
 
318
        /*
319
         *      Never answer to a ICMP packet.
320
         */
321
        if (is_ineligible(skb)) {
322
                if (net_ratelimit())
323
                        printk(KERN_DEBUG "icmpv6_send: no reply to icmp error\n");
324
                return;
325
        }
326
 
327
        fl.proto = IPPROTO_ICMPV6;
328
        fl.nl_u.ip6_u.daddr = &hdr->saddr;
329
        fl.nl_u.ip6_u.saddr = saddr;
330
        fl.oif = iif;
331
        fl.fl6_flowlabel = 0;
332
        fl.uli_u.icmpt.type = type;
333
        fl.uli_u.icmpt.code = code;
334
 
335
        if (icmpv6_xmit_lock())
336
                return;
337
 
338
        if (!icmpv6_xrlim_allow(sk, type, &fl))
339
                goto out;
340
 
341
        /*
342
         *      ok. kick it. checksum will be provided by the
343
         *      getfrag_t callback.
344
         */
345
 
346
        msg.icmph.icmp6_type = type;
347
        msg.icmph.icmp6_code = code;
348
        msg.icmph.icmp6_cksum = 0;
349
        msg.icmph.icmp6_pointer = htonl(info);
350
 
351
        msg.skb = skb;
352
        msg.offset = skb->nh.raw - skb->data;
353
        msg.csum = 0;
354
        msg.daddr = &hdr->saddr;
355
 
356
        len = skb->len - msg.offset + sizeof(struct icmp6hdr);
357
        len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr));
358
 
359
        if (len < 0) {
360
                if (net_ratelimit())
361
                        printk(KERN_DEBUG "icmp: len problem\n");
362
                goto out;
363
        }
364
 
365
        msg.len = len;
366
 
367
        ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
368
                       MSG_DONTWAIT);
369
        if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
370
                (&(icmpv6_statistics[smp_processor_id()*2].Icmp6OutDestUnreachs))[type-1]++;
371
        ICMP6_INC_STATS_BH(Icmp6OutMsgs);
372
out:
373
        icmpv6_xmit_unlock();
374
}
375
 
376
static void icmpv6_echo_reply(struct sk_buff *skb)
377
{
378
        struct sock *sk = icmpv6_socket->sk;
379
        struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
380
        struct in6_addr *saddr;
381
        struct icmpv6_msg msg;
382
        struct flowi fl;
383
 
384
        saddr = &skb->nh.ipv6h->daddr;
385
 
386
        if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST ||
387
            ipv6_chk_acast_addr(0, saddr))
388
                saddr = NULL;
389
 
390
        msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY;
391
        msg.icmph.icmp6_code = 0;
392
        msg.icmph.icmp6_cksum = 0;
393
        msg.icmph.icmp6_identifier = icmph->icmp6_identifier;
394
        msg.icmph.icmp6_sequence = icmph->icmp6_sequence;
395
 
396
        msg.skb = skb;
397
        msg.offset = 0;
398
        msg.csum = 0;
399
        msg.len = skb->len + sizeof(struct icmp6hdr);
400
        msg.daddr =  &skb->nh.ipv6h->saddr;
401
 
402
        fl.proto = IPPROTO_ICMPV6;
403
        fl.nl_u.ip6_u.daddr = msg.daddr;
404
        fl.nl_u.ip6_u.saddr = saddr;
405
        fl.oif = skb->dev->ifindex;
406
        fl.fl6_flowlabel = 0;
407
        fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY;
408
        fl.uli_u.icmpt.code = 0;
409
 
410
        if (icmpv6_xmit_lock())
411
                return;
412
 
413
        ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1,
414
                       MSG_DONTWAIT);
415
        ICMP6_INC_STATS_BH(Icmp6OutEchoReplies);
416
        ICMP6_INC_STATS_BH(Icmp6OutMsgs);
417
 
418
        icmpv6_xmit_unlock();
419
}
420
 
421
static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
422
{
423
        struct in6_addr *saddr, *daddr;
424
        struct inet6_protocol *ipprot;
425
        struct sock *sk;
426
        int inner_offset;
427
        int hash;
428
        u8 nexthdr;
429
 
430
        if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
431
                return;
432
 
433
        nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr;
434
        if (ipv6_ext_hdr(nexthdr)) {
435
                /* now skip over extension headers */
436
                inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, skb->len - sizeof(struct ipv6hdr));
437
                if (inner_offset<0)
438
                        return;
439
        } else {
440
                inner_offset = sizeof(struct ipv6hdr);
441
        }
442
 
443
        /* Checkin header including 8 bytes of inner protocol header. */
444
        if (!pskb_may_pull(skb, inner_offset+8))
445
                return;
446
 
447
        saddr = &skb->nh.ipv6h->saddr;
448
        daddr = &skb->nh.ipv6h->daddr;
449
 
450
        /* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
451
           Without this we will not able f.e. to make source routed
452
           pmtu discovery.
453
           Corresponding argument (opt) to notifiers is already added.
454
           --ANK (980726)
455
         */
456
 
457
        hash = nexthdr & (MAX_INET_PROTOS - 1);
458
 
459
        for (ipprot = (struct inet6_protocol *) inet6_protos[hash];
460
             ipprot != NULL;
461
             ipprot=(struct inet6_protocol *)ipprot->next) {
462
                if (ipprot->protocol != nexthdr)
463
                        continue;
464
 
465
                if (ipprot->err_handler)
466
                        ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
467
        }
468
 
469
        read_lock(&raw_v6_lock);
470
        if ((sk = raw_v6_htable[hash]) != NULL) {
471
                while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) {
472
                        rawv6_err(sk, skb, NULL, type, code, inner_offset, info);
473
                        sk = sk->next;
474
                }
475
        }
476
        read_unlock(&raw_v6_lock);
477
}
478
 
479
/*
480
 *      Handle icmp messages
481
 */
482
 
483
int icmpv6_rcv(struct sk_buff *skb)
484
{
485
        struct net_device *dev = skb->dev;
486
        struct in6_addr *saddr, *daddr;
487
        struct ipv6hdr *orig_hdr;
488
        struct icmp6hdr *hdr;
489
        int type;
490
 
491
        ICMP6_INC_STATS_BH(Icmp6InMsgs);
492
 
493
        saddr = &skb->nh.ipv6h->saddr;
494
        daddr = &skb->nh.ipv6h->daddr;
495
 
496
        /* Perform checksum. */
497
        if (skb->ip_summed == CHECKSUM_HW) {
498
                skb->ip_summed = CHECKSUM_UNNECESSARY;
499
                if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
500
                                    skb->csum)) {
501
                        if (net_ratelimit())
502
                                printk(KERN_DEBUG "ICMPv6 hw checksum failed\n");
503
                        skb->ip_summed = CHECKSUM_NONE;
504
                }
505
        }
506
        if (skb->ip_summed == CHECKSUM_NONE) {
507
                if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6,
508
                                    skb_checksum(skb, 0, skb->len, 0))) {
509
                        if (net_ratelimit())
510
                                printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
511
                                       ntohs(saddr->s6_addr16[0]),
512
                                       ntohs(saddr->s6_addr16[1]),
513
                                       ntohs(saddr->s6_addr16[2]),
514
                                       ntohs(saddr->s6_addr16[3]),
515
                                       ntohs(saddr->s6_addr16[4]),
516
                                       ntohs(saddr->s6_addr16[5]),
517
                                       ntohs(saddr->s6_addr16[6]),
518
                                       ntohs(saddr->s6_addr16[7]),
519
                                       ntohs(daddr->s6_addr16[0]),
520
                                       ntohs(daddr->s6_addr16[1]),
521
                                       ntohs(daddr->s6_addr16[2]),
522
                                       ntohs(daddr->s6_addr16[3]),
523
                                       ntohs(daddr->s6_addr16[4]),
524
                                       ntohs(daddr->s6_addr16[5]),
525
                                       ntohs(daddr->s6_addr16[6]),
526
                                       ntohs(daddr->s6_addr16[7]));
527
                        goto discard_it;
528
                }
529
        }
530
 
531
        if (!pskb_pull(skb, sizeof(struct icmp6hdr)))
532
                goto discard_it;
533
 
534
        hdr = (struct icmp6hdr *) skb->h.raw;
535
 
536
        type = hdr->icmp6_type;
537
 
538
        if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
539
                (&icmpv6_statistics[smp_processor_id()*2].Icmp6InDestUnreachs)[type-ICMPV6_DEST_UNREACH]++;
540
        else if (type >= ICMPV6_ECHO_REQUEST && type <= NDISC_REDIRECT)
541
                (&icmpv6_statistics[smp_processor_id()*2].Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++;
542
 
543
        switch (type) {
544
        case ICMPV6_ECHO_REQUEST:
545
                icmpv6_echo_reply(skb);
546
                break;
547
 
548
        case ICMPV6_ECHO_REPLY:
549
                /* we coulnd't care less */
550
                break;
551
 
552
        case ICMPV6_PKT_TOOBIG:
553
                /* BUGGG_FUTURE: if packet contains rthdr, we cannot update
554
                   standard destination cache. Seems, only "advanced"
555
                   destination cache will allow to solve this problem
556
                   --ANK (980726)
557
                 */
558
                if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
559
                        goto discard_it;
560
                hdr = (struct icmp6hdr *) skb->h.raw;
561
                orig_hdr = (struct ipv6hdr *) (hdr + 1);
562
                rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
563
                                   ntohl(hdr->icmp6_mtu));
564
 
565
                /*
566
                 *      Drop through to notify
567
                 */
568
 
569
        case ICMPV6_DEST_UNREACH:
570
        case ICMPV6_TIME_EXCEED:
571
        case ICMPV6_PARAMPROB:
572
                icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
573
                break;
574
 
575
        case NDISC_ROUTER_SOLICITATION:
576
        case NDISC_ROUTER_ADVERTISEMENT:
577
        case NDISC_NEIGHBOUR_SOLICITATION:
578
        case NDISC_NEIGHBOUR_ADVERTISEMENT:
579
        case NDISC_REDIRECT:
580
                if (skb_is_nonlinear(skb) &&
581
                    skb_linearize(skb, GFP_ATOMIC) != 0) {
582
                        kfree_skb(skb);
583
                        return 0;
584
                }
585
 
586
                ndisc_rcv(skb);
587
                break;
588
 
589
        case ICMPV6_MGM_QUERY:
590
                igmp6_event_query(skb);
591
                break;
592
 
593
        case ICMPV6_MGM_REPORT:
594
                igmp6_event_report(skb);
595
                break;
596
 
597
        case ICMPV6_MGM_REDUCTION:
598
                break;
599
 
600
        default:
601
                if (net_ratelimit())
602
                        printk(KERN_DEBUG "icmpv6: msg of unkown type\n");
603
 
604
                /* informational */
605
                if (type & ICMPV6_INFOMSG_MASK)
606
                        break;
607
 
608
                /*
609
                 * error of unkown type.
610
                 * must pass to upper level
611
                 */
612
 
613
                icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
614
        };
615
        kfree_skb(skb);
616
        return 0;
617
 
618
discard_it:
619
        ICMP6_INC_STATS_BH(Icmp6InErrors);
620
        kfree_skb(skb);
621
        return 0;
622
}
623
 
624
int __init icmpv6_init(struct net_proto_family *ops)
625
{
626
        struct sock *sk;
627
        int err, i, j;
628
 
629
        for (i = 0; i < NR_CPUS; i++) {
630
                icmpv6_socket_cpu(i) = sock_alloc();
631
                if (icmpv6_socket_cpu(i) == NULL) {
632
                        printk(KERN_ERR
633
                               "Failed to create the ICMP6 control socket.\n");
634
                        err = -1;
635
                        goto fail;
636
                }
637
                icmpv6_socket_cpu(i)->inode->i_uid = 0;
638
                icmpv6_socket_cpu(i)->inode->i_gid = 0;
639
                icmpv6_socket_cpu(i)->type = SOCK_RAW;
640
 
641
                if ((err = ops->create(icmpv6_socket_cpu(i), IPPROTO_ICMPV6)) < 0) {
642
                        printk(KERN_ERR
643
                               "Failed to initialize the ICMP6 control socket "
644
                               "(err %d).\n",
645
                               err);
646
                        goto fail;
647
                }
648
 
649
                sk = icmpv6_socket_cpu(i)->sk;
650
                sk->allocation = GFP_ATOMIC;
651
 
652
                /* Enough space for 2 64K ICMP packets, including
653
                 * sk_buff struct overhead.
654
                 */
655
                sk->sndbuf =
656
                        (2 * ((64 * 1024) + sizeof(struct sk_buff)));
657
 
658
                sk->prot->unhash(sk);
659
        }
660
 
661
        inet6_add_protocol(&icmpv6_protocol);
662
 
663
        return 0;
664
fail:
665
        for (j = 0; j < i; j++) {
666
                sock_release(icmpv6_socket_cpu(j));
667
                icmpv6_socket_cpu(j) = NULL;
668
        }
669
        return err;
670
}
671
 
672
void icmpv6_cleanup(void)
673
{
674
        int i;
675
 
676
        for (i = 0; i < NR_CPUS; i++) {
677
                sock_release(icmpv6_socket_cpu(i));
678
                icmpv6_socket_cpu(i) = NULL;
679
        }
680
        inet6_del_protocol(&icmpv6_protocol);
681
}
682
 
683
static struct icmp6_err {
684
        int err;
685
        int fatal;
686
} tab_unreach[] = {
687
        { ENETUNREACH,  0},      /* NOROUTE              */
688
        { EACCES,       1},     /* ADM_PROHIBITED       */
689
        { EHOSTUNREACH, 0},      /* Was NOT_NEIGHBOUR, now reserved */
690
        { EHOSTUNREACH, 0},      /* ADDR_UNREACH         */
691
        { ECONNREFUSED, 1},     /* PORT_UNREACH         */
692
};
693
 
694
int icmpv6_err_convert(int type, int code, int *err)
695
{
696
        int fatal = 0;
697
 
698
        *err = EPROTO;
699
 
700
        switch (type) {
701
        case ICMPV6_DEST_UNREACH:
702
                fatal = 1;
703
                if (code <= ICMPV6_PORT_UNREACH) {
704
                        *err  = tab_unreach[code].err;
705
                        fatal = tab_unreach[code].fatal;
706
                }
707
                break;
708
 
709
        case ICMPV6_PKT_TOOBIG:
710
                *err = EMSGSIZE;
711
                break;
712
 
713
        case ICMPV6_PARAMPROB:
714
                *err = EPROTO;
715
                fatal = 1;
716
                break;
717
 
718
        case ICMPV6_TIME_EXCEED:
719
                *err = EHOSTUNREACH;
720
                break;
721
        };
722
 
723
        return fatal;
724
}
725
 
726
#ifdef CONFIG_SYSCTL
727
ctl_table ipv6_icmp_table[] = {
728
        {NET_IPV6_ICMP_RATELIMIT, "ratelimit",
729
        &sysctl_icmpv6_time, sizeof(int), 0644, NULL, &proc_dointvec},
730
        {0},
731
};
732
#endif
733
 

powered by: WebSVN 2.1.0

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