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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      UDP over IPv6
3
 *      Linux INET6 implementation
4
 *
5
 *      Authors:
6
 *      Pedro Roque             <roque@di.fc.ul.pt>
7
 *
8
 *      Based on linux/ipv4/udp.c
9
 *
10
 *      $Id: udp.c,v 1.1.1.1 2004-04-15 01:14:35 phoenix Exp $
11
 *
12
 *      Fixes:
13
 *      Hideaki YOSHIFUJI       :       sin6_scope_id support
14
 *      YOSHIFUJI Hideaki @USAGI and:   Support IPV6_V6ONLY socket option, which
15
 *      Alexey Kuznetsov                allow both IPv4 and IPv6 sockets to bind
16
 *                                      a single port at the same time.
17
 *
18
 *      This program is free software; you can redistribute it and/or
19
 *      modify it under the terms of the GNU General Public License
20
 *      as published by the Free Software Foundation; either version
21
 *      2 of the License, or (at your option) any later version.
22
 */
23
 
24
#include <linux/config.h>
25
#include <linux/errno.h>
26
#include <linux/types.h>
27
#include <linux/socket.h>
28
#include <linux/sockios.h>
29
#include <linux/sched.h>
30
#include <linux/net.h>
31
#include <linux/in6.h>
32
#include <linux/netdevice.h>
33
#include <linux/if_arp.h>
34
#include <linux/ipv6.h>
35
#include <linux/icmpv6.h>
36
#include <linux/init.h>
37
#include <asm/uaccess.h>
38
 
39
#include <net/sock.h>
40
#include <net/snmp.h>
41
 
42
#include <net/ipv6.h>
43
#include <net/ndisc.h>
44
#include <net/protocol.h>
45
#include <net/transp_v6.h>
46
#include <net/ip6_route.h>
47
#include <net/addrconf.h>
48
#include <net/ip.h>
49
#include <net/udp.h>
50
#include <net/inet_common.h>
51
 
52
#include <net/checksum.h>
53
 
54
struct udp_mib udp_stats_in6[NR_CPUS*2];
55
 
56
/* Grrr, addr_type already calculated by caller, but I don't want
57
 * to add some silly "cookie" argument to this method just for that.
58
 */
59
static int udp_v6_get_port(struct sock *sk, unsigned short snum)
60
{
61
        write_lock_bh(&udp_hash_lock);
62
        if (snum == 0) {
63
                int best_size_so_far, best, result, i;
64
 
65
                if (udp_port_rover > sysctl_local_port_range[1] ||
66
                    udp_port_rover < sysctl_local_port_range[0])
67
                        udp_port_rover = sysctl_local_port_range[0];
68
                best_size_so_far = 32767;
69
                best = result = udp_port_rover;
70
                for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
71
                        struct sock *sk;
72
                        int size;
73
 
74
                        sk = udp_hash[result & (UDP_HTABLE_SIZE - 1)];
75
                        if (!sk) {
76
                                if (result > sysctl_local_port_range[1])
77
                                        result = sysctl_local_port_range[0] +
78
                                                ((result - sysctl_local_port_range[0]) &
79
                                                 (UDP_HTABLE_SIZE - 1));
80
                                goto gotit;
81
                        }
82
                        size = 0;
83
                        do {
84
                                if (++size >= best_size_so_far)
85
                                        goto next;
86
                        } while ((sk = sk->next) != NULL);
87
                        best_size_so_far = size;
88
                        best = result;
89
                next:;
90
                }
91
                result = best;
92
                for(;; result += UDP_HTABLE_SIZE) {
93
                        if (result > sysctl_local_port_range[1])
94
                                result = sysctl_local_port_range[0]
95
                                        + ((result - sysctl_local_port_range[0]) &
96
                                           (UDP_HTABLE_SIZE - 1));
97
                        if (!udp_lport_inuse(result))
98
                                break;
99
                }
100
gotit:
101
                udp_port_rover = snum = result;
102
        } else {
103
                struct sock *sk2;
104
                int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
105
 
106
                for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
107
                     sk2 != NULL;
108
                     sk2 = sk2->next) {
109
                        if (sk2->num == snum &&
110
                            sk2 != sk &&
111
                            (!sk2->bound_dev_if ||
112
                             !sk->bound_dev_if ||
113
                             sk2->bound_dev_if == sk->bound_dev_if) &&
114
                            ((!sk2->rcv_saddr && !ipv6_only_sock(sk)) ||
115
                             (sk2->family == AF_INET6 &&
116
                              ipv6_addr_any(&sk2->net_pinfo.af_inet6.rcv_saddr) &&
117
                              !(ipv6_only_sock(sk2) && addr_type == IPV6_ADDR_MAPPED)) ||
118
                             (addr_type == IPV6_ADDR_ANY &&
119
                              (!ipv6_only_sock(sk) ||
120
                               !(sk2->family == AF_INET6 ? (ipv6_addr_type(&sk2->net_pinfo.af_inet6.rcv_saddr) == IPV6_ADDR_MAPPED) : 1))) ||
121
                             (sk2->family == AF_INET6 &&
122
                              !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
123
                                             &sk2->net_pinfo.af_inet6.rcv_saddr)) ||
124
                             (addr_type == IPV6_ADDR_MAPPED &&
125
                              !ipv6_only_sock(sk2) &&
126
                              (!sk2->rcv_saddr ||
127
                               !sk->rcv_saddr ||
128
                               sk->rcv_saddr == sk2->rcv_saddr))) &&
129
                            (!sk2->reuse || !sk->reuse))
130
                                goto fail;
131
                }
132
        }
133
 
134
        sk->num = snum;
135
        if (sk->pprev == NULL) {
136
                struct sock **skp = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
137
                if ((sk->next = *skp) != NULL)
138
                        (*skp)->pprev = &sk->next;
139
                *skp = sk;
140
                sk->pprev = skp;
141
                sock_prot_inc_use(sk->prot);
142
                sock_hold(sk);
143
        }
144
        write_unlock_bh(&udp_hash_lock);
145
        return 0;
146
 
147
fail:
148
        write_unlock_bh(&udp_hash_lock);
149
        return 1;
150
}
151
 
152
static void udp_v6_hash(struct sock *sk)
153
{
154
        BUG();
155
}
156
 
157
static void udp_v6_unhash(struct sock *sk)
158
{
159
        write_lock_bh(&udp_hash_lock);
160
        if (sk->pprev) {
161
                if (sk->next)
162
                        sk->next->pprev = sk->pprev;
163
                *sk->pprev = sk->next;
164
                sk->pprev = NULL;
165
                sk->num = 0;
166
                sock_prot_dec_use(sk->prot);
167
                __sock_put(sk);
168
        }
169
        write_unlock_bh(&udp_hash_lock);
170
}
171
 
172
static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
173
                                  struct in6_addr *daddr, u16 dport, int dif)
174
{
175
        struct sock *sk, *result = NULL;
176
        unsigned short hnum = ntohs(dport);
177
        int badness = -1;
178
 
179
        read_lock(&udp_hash_lock);
180
        for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) {
181
                if((sk->num == hnum)            &&
182
                   (sk->family == PF_INET6)) {
183
                        struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
184
                        int score = 0;
185
                        if(sk->dport) {
186
                                if(sk->dport != sport)
187
                                        continue;
188
                                score++;
189
                        }
190
                        if(!ipv6_addr_any(&np->rcv_saddr)) {
191
                                if(ipv6_addr_cmp(&np->rcv_saddr, daddr))
192
                                        continue;
193
                                score++;
194
                        }
195
                        if(!ipv6_addr_any(&np->daddr)) {
196
                                if(ipv6_addr_cmp(&np->daddr, saddr))
197
                                        continue;
198
                                score++;
199
                        }
200
                        if(sk->bound_dev_if) {
201
                                if(sk->bound_dev_if != dif)
202
                                        continue;
203
                                score++;
204
                        }
205
                        if(score == 4) {
206
                                result = sk;
207
                                break;
208
                        } else if(score > badness) {
209
                                result = sk;
210
                                badness = score;
211
                        }
212
                }
213
        }
214
        if (result)
215
                sock_hold(result);
216
        read_unlock(&udp_hash_lock);
217
        return result;
218
}
219
 
220
/*
221
 *
222
 */
223
 
224
int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
225
{
226
        struct sockaddr_in6     *usin = (struct sockaddr_in6 *) uaddr;
227
        struct ipv6_pinfo       *np = &sk->net_pinfo.af_inet6;
228
        struct in6_addr         *daddr;
229
        struct in6_addr         saddr;
230
        struct dst_entry        *dst;
231
        struct flowi            fl;
232
        struct ip6_flowlabel    *flowlabel = NULL;
233
        int                     addr_type;
234
        int                     err;
235
 
236
        if (usin->sin6_family == AF_INET) {
237
                if (__ipv6_only_sock(sk))
238
                        return -EAFNOSUPPORT;
239
                err = udp_connect(sk, uaddr, addr_len);
240
                goto ipv4_connected;
241
        }
242
 
243
        if (addr_len < SIN6_LEN_RFC2133)
244
                return -EINVAL;
245
 
246
        if (usin->sin6_family != AF_INET6)
247
                return -EAFNOSUPPORT;
248
 
249
        fl.fl6_flowlabel = 0;
250
        if (np->sndflow) {
251
                fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
252
                if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
253
                        flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
254
                        if (flowlabel == NULL)
255
                                return -EINVAL;
256
                        ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
257
                }
258
        }
259
 
260
        addr_type = ipv6_addr_type(&usin->sin6_addr);
261
 
262
        if (addr_type == IPV6_ADDR_ANY) {
263
                /*
264
                 *      connect to self
265
                 */
266
                usin->sin6_addr.s6_addr[15] = 0x01;
267
        }
268
 
269
        daddr = &usin->sin6_addr;
270
 
271
        if (addr_type == IPV6_ADDR_MAPPED) {
272
                struct sockaddr_in sin;
273
 
274
                if (__ipv6_only_sock(sk))
275
                        return -ENETUNREACH;
276
 
277
                sin.sin_family = AF_INET;
278
                sin.sin_addr.s_addr = daddr->s6_addr32[3];
279
                sin.sin_port = usin->sin6_port;
280
 
281
                err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin));
282
 
283
ipv4_connected:
284
                if (err < 0)
285
                        return err;
286
 
287
                ipv6_addr_set(&np->daddr, 0, 0,
288
                              htonl(0x0000ffff),
289
                              sk->daddr);
290
 
291
                if(ipv6_addr_any(&np->saddr)) {
292
                        ipv6_addr_set(&np->saddr, 0, 0,
293
                                      htonl(0x0000ffff),
294
                                      sk->saddr);
295
                }
296
 
297
                if(ipv6_addr_any(&np->rcv_saddr)) {
298
                        ipv6_addr_set(&np->rcv_saddr, 0, 0,
299
                                      htonl(0x0000ffff),
300
                                      sk->rcv_saddr);
301
                }
302
                return 0;
303
        }
304
 
305
        if (addr_type&IPV6_ADDR_LINKLOCAL) {
306
                if (addr_len >= sizeof(struct sockaddr_in6) &&
307
                    usin->sin6_scope_id) {
308
                        if (sk->bound_dev_if && sk->bound_dev_if != usin->sin6_scope_id) {
309
                                fl6_sock_release(flowlabel);
310
                                return -EINVAL;
311
                        }
312
                        sk->bound_dev_if = usin->sin6_scope_id;
313
                        if (!sk->bound_dev_if && (addr_type&IPV6_ADDR_MULTICAST))
314
                                fl.oif = np->mcast_oif;
315
                }
316
 
317
                /* Connect to link-local address requires an interface */
318
                if (sk->bound_dev_if == 0)
319
                        return -EINVAL;
320
        }
321
 
322
        ipv6_addr_copy(&np->daddr, daddr);
323
        np->flow_label = fl.fl6_flowlabel;
324
 
325
        sk->dport = usin->sin6_port;
326
 
327
        /*
328
         *      Check for a route to destination an obtain the
329
         *      destination cache for it.
330
         */
331
 
332
        fl.proto = IPPROTO_UDP;
333
        fl.fl6_dst = &np->daddr;
334
        fl.fl6_src = &saddr;
335
        fl.oif = sk->bound_dev_if;
336
        fl.uli_u.ports.dport = sk->dport;
337
        fl.uli_u.ports.sport = sk->sport;
338
 
339
        if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST))
340
                fl.oif = np->mcast_oif;
341
 
342
        if (flowlabel) {
343
                if (flowlabel->opt && flowlabel->opt->srcrt) {
344
                        struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
345
                        fl.fl6_dst = rt0->addr;
346
                }
347
        } else if (np->opt && np->opt->srcrt) {
348
                struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
349
                fl.fl6_dst = rt0->addr;
350
        }
351
 
352
        dst = ip6_route_output(sk, &fl);
353
 
354
        if ((err = dst->error) != 0) {
355
                dst_release(dst);
356
                fl6_sock_release(flowlabel);
357
                return err;
358
        }
359
 
360
        ip6_dst_store(sk, dst, fl.fl6_dst);
361
 
362
        /* get the source adddress used in the apropriate device */
363
 
364
        err = ipv6_get_saddr(dst, daddr, &saddr);
365
 
366
        if (err == 0) {
367
                if(ipv6_addr_any(&np->saddr))
368
                        ipv6_addr_copy(&np->saddr, &saddr);
369
 
370
                if(ipv6_addr_any(&np->rcv_saddr)) {
371
                        ipv6_addr_copy(&np->rcv_saddr, &saddr);
372
                        sk->rcv_saddr = LOOPBACK4_IPV6;
373
                }
374
                sk->state = TCP_ESTABLISHED;
375
        }
376
        fl6_sock_release(flowlabel);
377
 
378
        return err;
379
}
380
 
381
static void udpv6_close(struct sock *sk, long timeout)
382
{
383
        inet_sock_release(sk);
384
}
385
 
386
/*
387
 *      This should be easy, if there is something there we
388
 *      return it, otherwise we block.
389
 */
390
 
391
int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
392
                  int noblock, int flags, int *addr_len)
393
{
394
        struct sk_buff *skb;
395
        int copied, err;
396
 
397
        if (addr_len)
398
                *addr_len=sizeof(struct sockaddr_in6);
399
 
400
        if (flags & MSG_ERRQUEUE)
401
                return ipv6_recv_error(sk, msg, len);
402
 
403
try_again:
404
        skb = skb_recv_datagram(sk, flags, noblock, &err);
405
        if (!skb)
406
                goto out;
407
 
408
        copied = skb->len - sizeof(struct udphdr);
409
        if (copied > len) {
410
                copied = len;
411
                msg->msg_flags |= MSG_TRUNC;
412
        }
413
 
414
        if (skb->ip_summed==CHECKSUM_UNNECESSARY) {
415
                err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
416
                                              copied);
417
        } else if (msg->msg_flags&MSG_TRUNC) {
418
                if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)))
419
                        goto csum_copy_err;
420
                err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
421
                                              copied);
422
        } else {
423
                err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov);
424
                if (err == -EINVAL)
425
                        goto csum_copy_err;
426
        }
427
        if (err)
428
                goto out_free;
429
 
430
        sock_recv_timestamp(msg, sk, skb);
431
 
432
        /* Copy the address. */
433
        if (msg->msg_name) {
434
                struct sockaddr_in6 *sin6;
435
 
436
                sin6 = (struct sockaddr_in6 *) msg->msg_name;
437
                sin6->sin6_family = AF_INET6;
438
                sin6->sin6_port = skb->h.uh->source;
439
                sin6->sin6_flowinfo = 0;
440
                sin6->sin6_scope_id = 0;
441
 
442
                if (skb->protocol == htons(ETH_P_IP)) {
443
                        ipv6_addr_set(&sin6->sin6_addr, 0, 0,
444
                                      htonl(0xffff), skb->nh.iph->saddr);
445
                        if (sk->protinfo.af_inet.cmsg_flags)
446
                                ip_cmsg_recv(msg, skb);
447
                } else {
448
                        memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
449
                               sizeof(struct in6_addr));
450
 
451
                        if (sk->net_pinfo.af_inet6.rxopt.all)
452
                                datagram_recv_ctl(sk, msg, skb);
453
                        if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
454
                                struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
455
                                sin6->sin6_scope_id = opt->iif;
456
                        }
457
                }
458
        }
459
        err = copied;
460
 
461
out_free:
462
        skb_free_datagram(sk, skb);
463
out:
464
        return err;
465
 
466
csum_copy_err:
467
        /* Clear queue. */
468
        if (flags&MSG_PEEK) {
469
                int clear = 0;
470
                spin_lock_irq(&sk->receive_queue.lock);
471
                if (skb == skb_peek(&sk->receive_queue)) {
472
                        __skb_unlink(skb, &sk->receive_queue);
473
                        clear = 1;
474
                }
475
                spin_unlock_irq(&sk->receive_queue.lock);
476
                if (clear)
477
                        kfree_skb(skb);
478
        }
479
 
480
        skb_free_datagram(sk, skb);
481
 
482
        if (flags & MSG_DONTWAIT) {
483
                UDP6_INC_STATS_USER(UdpInErrors);
484
                return -EAGAIN;
485
        }
486
        goto try_again;
487
}
488
 
489
void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
490
               int type, int code, int offset, __u32 info)
491
{
492
        struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
493
        struct net_device *dev = skb->dev;
494
        struct in6_addr *saddr = &hdr->saddr;
495
        struct in6_addr *daddr = &hdr->daddr;
496
        struct udphdr *uh = (struct udphdr*)(skb->data+offset);
497
        struct sock *sk;
498
        int err;
499
 
500
        sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, dev->ifindex);
501
 
502
        if (sk == NULL)
503
                return;
504
 
505
        if (!icmpv6_err_convert(type, code, &err) &&
506
            !sk->net_pinfo.af_inet6.recverr)
507
                goto out;
508
 
509
        if (sk->state!=TCP_ESTABLISHED &&
510
            !sk->net_pinfo.af_inet6.recverr)
511
                goto out;
512
 
513
        if (sk->net_pinfo.af_inet6.recverr)
514
                ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));
515
 
516
        sk->err = err;
517
        sk->error_report(sk);
518
out:
519
        sock_put(sk);
520
}
521
 
522
static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
523
{
524
#if defined(CONFIG_FILTER)
525
        if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
526
                if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
527
                        UDP6_INC_STATS_BH(UdpInErrors);
528
                        IP6_INC_STATS_BH(Ip6InDiscards);
529
                        kfree_skb(skb);
530
                        return 0;
531
                }
532
                skb->ip_summed = CHECKSUM_UNNECESSARY;
533
        }
534
#endif
535
        if (sock_queue_rcv_skb(sk,skb)<0) {
536
                UDP6_INC_STATS_BH(UdpInErrors);
537
                IP6_INC_STATS_BH(Ip6InDiscards);
538
                kfree_skb(skb);
539
                return 0;
540
        }
541
        IP6_INC_STATS_BH(Ip6InDelivers);
542
        UDP6_INC_STATS_BH(UdpInDatagrams);
543
        return 0;
544
}
545
 
546
static struct sock *udp_v6_mcast_next(struct sock *sk,
547
                                      u16 loc_port, struct in6_addr *loc_addr,
548
                                      u16 rmt_port, struct in6_addr *rmt_addr,
549
                                      int dif)
550
{
551
        struct sock *s = sk;
552
        unsigned short num = ntohs(loc_port);
553
        for(; s; s = s->next) {
554
                if(s->num == num) {
555
                        struct ipv6_pinfo *np = &s->net_pinfo.af_inet6;
556
                        if(s->dport) {
557
                                if(s->dport != rmt_port)
558
                                        continue;
559
                        }
560
                        if(!ipv6_addr_any(&np->daddr) &&
561
                           ipv6_addr_cmp(&np->daddr, rmt_addr))
562
                                continue;
563
 
564
                        if (s->bound_dev_if && s->bound_dev_if != dif)
565
                                continue;
566
 
567
                        if(!ipv6_addr_any(&np->rcv_saddr)) {
568
                                if(ipv6_addr_cmp(&np->rcv_saddr, loc_addr) == 0)
569
                                        return s;
570
                                continue;
571
                        }
572
                        if(!inet6_mc_check(s, loc_addr, rmt_addr))
573
                                continue;
574
                        return s;
575
                }
576
        }
577
        return NULL;
578
}
579
 
580
/*
581
 * Note: called only from the BH handler context,
582
 * so we don't need to lock the hashes.
583
 */
584
static void udpv6_mcast_deliver(struct udphdr *uh,
585
                                struct in6_addr *saddr, struct in6_addr *daddr,
586
                                struct sk_buff *skb)
587
{
588
        struct sock *sk, *sk2;
589
        struct sk_buff *buff;
590
        int dif;
591
 
592
        read_lock(&udp_hash_lock);
593
        sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];
594
        dif = skb->dev->ifindex;
595
        sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);
596
        if (!sk)
597
                goto free_skb;
598
 
599
        buff = NULL;
600
        sk2 = sk;
601
        while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, daddr,
602
                                                  uh->source, saddr, dif))) {
603
                if (!buff) {
604
                        buff = skb_clone(skb, GFP_ATOMIC);
605
                        if (!buff)
606
                                continue;
607
                }
608
                if (sock_queue_rcv_skb(sk2, buff) >= 0)
609
                        buff = NULL;
610
        }
611
        if (buff)
612
                kfree_skb(buff);
613
        if (sock_queue_rcv_skb(sk, skb) < 0) {
614
free_skb:
615
                kfree_skb(skb);
616
        }
617
        read_unlock(&udp_hash_lock);
618
}
619
 
620
int udpv6_rcv(struct sk_buff *skb)
621
{
622
        struct sock *sk;
623
        struct udphdr *uh;
624
        struct net_device *dev = skb->dev;
625
        struct in6_addr *saddr, *daddr;
626
        u32 ulen = 0;
627
 
628
        if (!pskb_may_pull(skb, sizeof(struct udphdr)))
629
                goto short_packet;
630
 
631
        saddr = &skb->nh.ipv6h->saddr;
632
        daddr = &skb->nh.ipv6h->daddr;
633
        uh = skb->h.uh;
634
 
635
        ulen = ntohs(uh->len);
636
 
637
        /* Check for jumbo payload */
638
        if (ulen == 0)
639
                ulen = skb->len;
640
 
641
        if (ulen > skb->len || ulen < sizeof(*uh))
642
                goto short_packet;
643
 
644
        if (uh->check == 0) {
645
                /* IPv6 draft-v2 section 8.1 says that we SHOULD log
646
                   this error. Well, it is reasonable.
647
                 */
648
                if (net_ratelimit())
649
                        printk(KERN_INFO "IPv6: udp checksum is 0\n");
650
                goto discard;
651
        }
652
 
653
        if (ulen < skb->len) {
654
                if (__pskb_trim(skb, ulen))
655
                        goto discard;
656
                saddr = &skb->nh.ipv6h->saddr;
657
                daddr = &skb->nh.ipv6h->daddr;
658
                uh = skb->h.uh;
659
        }
660
 
661
        if (skb->ip_summed==CHECKSUM_HW) {
662
                skb->ip_summed = CHECKSUM_UNNECESSARY;
663
                if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) {
664
                        NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "udp v6 hw csum failure.\n"));
665
                        skb->ip_summed = CHECKSUM_NONE;
666
                }
667
        }
668
        if (skb->ip_summed != CHECKSUM_UNNECESSARY)
669
                skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0);
670
 
671
        /*
672
         *      Multicast receive code
673
         */
674
        if (ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST) {
675
                udpv6_mcast_deliver(uh, saddr, daddr, skb);
676
                return 0;
677
        }
678
 
679
        /* Unicast */
680
 
681
        /*
682
         * check socket cache ... must talk to Alan about his plans
683
         * for sock caches... i'll skip this for now.
684
         */
685
        sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, dev->ifindex);
686
 
687
        if (sk == NULL) {
688
                if (skb->ip_summed != CHECKSUM_UNNECESSARY &&
689
                    (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)))
690
                        goto discard;
691
                UDP6_INC_STATS_BH(UdpNoPorts);
692
 
693
                icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev);
694
 
695
                kfree_skb(skb);
696
                return(0);
697
        }
698
 
699
        /* deliver */
700
 
701
        udpv6_queue_rcv_skb(sk, skb);
702
        sock_put(sk);
703
        return(0);
704
 
705
short_packet:
706
        if (net_ratelimit())
707
                printk(KERN_DEBUG "UDP: short packet: %d/%u\n", ulen, skb->len);
708
 
709
discard:
710
        UDP6_INC_STATS_BH(UdpInErrors);
711
        kfree_skb(skb);
712
        return(0);
713
}
714
 
715
/*
716
 *      Sending
717
 */
718
 
719
struct udpv6fakehdr
720
{
721
        struct udphdr   uh;
722
        struct iovec    *iov;
723
        __u32           wcheck;
724
        __u32           pl_len;
725
        struct in6_addr *daddr;
726
};
727
 
728
/*
729
 *      with checksum
730
 */
731
 
732
static int udpv6_getfrag(const void *data, struct in6_addr *addr,
733
                         char *buff, unsigned int offset, unsigned int len)
734
{
735
        struct udpv6fakehdr *udh = (struct udpv6fakehdr *) data;
736
        char *dst;
737
        int final = 0;
738
        int clen = len;
739
 
740
        dst = buff;
741
 
742
        if (offset) {
743
                offset -= sizeof(struct udphdr);
744
        } else {
745
                dst += sizeof(struct udphdr);
746
                final = 1;
747
                clen -= sizeof(struct udphdr);
748
        }
749
 
750
        if (csum_partial_copy_fromiovecend(dst, udh->iov, offset,
751
                                           clen, &udh->wcheck))
752
                return -EFAULT;
753
 
754
        if (final) {
755
                struct in6_addr *daddr;
756
 
757
                udh->wcheck = csum_partial((char *)udh, sizeof(struct udphdr),
758
                                           udh->wcheck);
759
 
760
                if (udh->daddr) {
761
                        daddr = udh->daddr;
762
                } else {
763
                        /*
764
                         *      use packet destination address
765
                         *      this should improve cache locality
766
                         */
767
                        daddr = addr + 1;
768
                }
769
                udh->uh.check = csum_ipv6_magic(addr, daddr,
770
                                                udh->pl_len, IPPROTO_UDP,
771
                                                udh->wcheck);
772
                if (udh->uh.check == 0)
773
                        udh->uh.check = -1;
774
 
775
                memcpy(buff, udh, sizeof(struct udphdr));
776
        }
777
        return 0;
778
}
779
 
780
static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
781
{
782
        struct ipv6_txoptions opt_space;
783
        struct udpv6fakehdr udh;
784
        struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
785
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
786
        struct ipv6_txoptions *opt = NULL;
787
        struct ip6_flowlabel *flowlabel = NULL;
788
        struct flowi fl;
789
        int addr_len = msg->msg_namelen;
790
        struct in6_addr *daddr;
791
        int len = ulen + sizeof(struct udphdr);
792
        int addr_type;
793
        int hlimit = -1;
794
 
795
        int err;
796
 
797
        /* Rough check on arithmetic overflow,
798
           better check is made in ip6_build_xmit
799
           */
800
        if (ulen < 0 || ulen > INT_MAX - sizeof(struct udphdr))
801
                return -EMSGSIZE;
802
 
803
        fl.fl6_flowlabel = 0;
804
        fl.oif = 0;
805
 
806
        if (sin6) {
807
                if (sin6->sin6_family == AF_INET) {
808
                        if (__ipv6_only_sock(sk))
809
                                return -ENETUNREACH;
810
                        return udp_sendmsg(sk, msg, ulen);
811
                }
812
 
813
                if (addr_len < SIN6_LEN_RFC2133)
814
                        return -EINVAL;
815
 
816
                if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
817
                        return -EINVAL;
818
 
819
                if (sin6->sin6_port == 0)
820
                        return -EINVAL;
821
 
822
                udh.uh.dest = sin6->sin6_port;
823
                daddr = &sin6->sin6_addr;
824
 
825
                if (np->sndflow) {
826
                        fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
827
                        if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
828
                                flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
829
                                if (flowlabel == NULL)
830
                                        return -EINVAL;
831
                                daddr = &flowlabel->dst;
832
                        }
833
                }
834
 
835
                /* Otherwise it will be difficult to maintain sk->dst_cache. */
836
                if (sk->state == TCP_ESTABLISHED &&
837
                    !ipv6_addr_cmp(daddr, &sk->net_pinfo.af_inet6.daddr))
838
                        daddr = &sk->net_pinfo.af_inet6.daddr;
839
 
840
                if (addr_len >= sizeof(struct sockaddr_in6) &&
841
                    sin6->sin6_scope_id &&
842
                    ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
843
                        fl.oif = sin6->sin6_scope_id;
844
        } else {
845
                if (sk->state != TCP_ESTABLISHED)
846
                        return -EDESTADDRREQ;
847
 
848
                udh.uh.dest = sk->dport;
849
                daddr = &sk->net_pinfo.af_inet6.daddr;
850
                fl.fl6_flowlabel = np->flow_label;
851
        }
852
 
853
        addr_type = ipv6_addr_type(daddr);
854
 
855
        if (addr_type == IPV6_ADDR_MAPPED) {
856
                struct sockaddr_in sin;
857
 
858
                if (__ipv6_only_sock(sk))
859
                        return -ENETUNREACH;
860
 
861
                sin.sin_family = AF_INET;
862
                sin.sin_addr.s_addr = daddr->s6_addr32[3];
863
                sin.sin_port = udh.uh.dest;
864
                msg->msg_name = (struct sockaddr *)(&sin);
865
                msg->msg_namelen = sizeof(sin);
866
                fl6_sock_release(flowlabel);
867
 
868
                return udp_sendmsg(sk, msg, ulen);
869
        }
870
 
871
        udh.daddr = NULL;
872
        if (!fl.oif)
873
                fl.oif = sk->bound_dev_if;
874
        fl.fl6_src = NULL;
875
 
876
        if (msg->msg_controllen) {
877
                opt = &opt_space;
878
                memset(opt, 0, sizeof(struct ipv6_txoptions));
879
 
880
                err = datagram_send_ctl(msg, &fl, opt, &hlimit);
881
                if (err < 0) {
882
                        fl6_sock_release(flowlabel);
883
                        return err;
884
                }
885
                if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
886
                        flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
887
                        if (flowlabel == NULL)
888
                                return -EINVAL;
889
                }
890
                if (!(opt->opt_nflen|opt->opt_flen))
891
                        opt = NULL;
892
        }
893
        if (opt == NULL)
894
                opt = np->opt;
895
        if (flowlabel)
896
                opt = fl6_merge_options(&opt_space, flowlabel, opt);
897
        if (opt && opt->srcrt)
898
                udh.daddr = daddr;
899
 
900
        udh.uh.source = sk->sport;
901
        udh.uh.len = len < 0x10000 ? htons(len) : 0;
902
        udh.uh.check = 0;
903
        udh.iov = msg->msg_iov;
904
        udh.wcheck = 0;
905
        udh.pl_len = len;
906
 
907
        fl.proto = IPPROTO_UDP;
908
        fl.fl6_dst = daddr;
909
        if (fl.fl6_src == NULL && !ipv6_addr_any(&np->saddr))
910
                fl.fl6_src = &np->saddr;
911
        fl.uli_u.ports.dport = udh.uh.dest;
912
        fl.uli_u.ports.sport = udh.uh.source;
913
 
914
        err = ip6_build_xmit(sk, udpv6_getfrag, &udh, &fl, len, opt, hlimit,
915
                             msg->msg_flags);
916
 
917
        fl6_sock_release(flowlabel);
918
 
919
        if (err < 0)
920
                return err;
921
 
922
        UDP6_INC_STATS_USER(UdpOutDatagrams);
923
        return ulen;
924
}
925
 
926
static struct inet6_protocol udpv6_protocol =
927
{
928
        udpv6_rcv,              /* UDP handler          */
929
        udpv6_err,              /* UDP error control    */
930
        NULL,                   /* next                 */
931
        IPPROTO_UDP,            /* protocol ID          */
932
        0,                       /* copy                 */
933
        NULL,                   /* data                 */
934
        "UDPv6"                 /* name                 */
935
};
936
 
937
#define LINE_LEN 190
938
#define LINE_FMT "%-190s\n"
939
 
940
static void get_udp6_sock(struct sock *sp, char *tmpbuf, int i)
941
{
942
        struct in6_addr *dest, *src;
943
        __u16 destp, srcp;
944
 
945
        dest  = &sp->net_pinfo.af_inet6.daddr;
946
        src   = &sp->net_pinfo.af_inet6.rcv_saddr;
947
        destp = ntohs(sp->dport);
948
        srcp  = ntohs(sp->sport);
949
        sprintf(tmpbuf,
950
                "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
951
                "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",
952
                i,
953
                src->s6_addr32[0], src->s6_addr32[1],
954
                src->s6_addr32[2], src->s6_addr32[3], srcp,
955
                dest->s6_addr32[0], dest->s6_addr32[1],
956
                dest->s6_addr32[2], dest->s6_addr32[3], destp,
957
                sp->state,
958
                atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
959
                0, 0L, 0,
960
                sock_i_uid(sp), 0,
961
                sock_i_ino(sp),
962
                atomic_read(&sp->refcnt), sp);
963
}
964
 
965
int udp6_get_info(char *buffer, char **start, off_t offset, int length)
966
{
967
        int len = 0, num = 0, i;
968
        off_t pos = 0;
969
        off_t begin;
970
        char tmpbuf[LINE_LEN+2];
971
 
972
        if (offset < LINE_LEN+1)
973
                len += sprintf(buffer, LINE_FMT,
974
                               "  sl  "                                         /* 6 */
975
                               "local_address                         "         /* 38 */
976
                               "remote_address                        "         /* 38 */
977
                               "st tx_queue rx_queue tr tm->when retrnsmt"      /* 41 */
978
                               "   uid  timeout inode");                        /* 21 */
979
                                                                                /*----*/
980
                                                                                /*144 */
981
        pos = LINE_LEN+1;
982
        read_lock(&udp_hash_lock);
983
        for (i = 0; i < UDP_HTABLE_SIZE; i++) {
984
                struct sock *sk;
985
 
986
                for (sk = udp_hash[i]; sk; sk = sk->next, num++) {
987
                        if (sk->family != PF_INET6)
988
                                continue;
989
                        pos += LINE_LEN+1;
990
                        if (pos <= offset)
991
                                continue;
992
                        get_udp6_sock(sk, tmpbuf, i);
993
                        len += sprintf(buffer+len, LINE_FMT, tmpbuf);
994
                        if(len >= length)
995
                                goto out;
996
                }
997
        }
998
out:
999
        read_unlock(&udp_hash_lock);
1000
        begin = len - (pos - offset);
1001
        *start = buffer + begin;
1002
        len -= begin;
1003
        if(len > length)
1004
                len = length;
1005
        if (len < 0)
1006
                len = 0;
1007
        return len;
1008
}
1009
 
1010
struct proto udpv6_prot = {
1011
        name:           "UDP",
1012
        close:          udpv6_close,
1013
        connect:        udpv6_connect,
1014
        disconnect:     udp_disconnect,
1015
        ioctl:          udp_ioctl,
1016
        destroy:        inet6_destroy_sock,
1017
        setsockopt:     ipv6_setsockopt,
1018
        getsockopt:     ipv6_getsockopt,
1019
        sendmsg:        udpv6_sendmsg,
1020
        recvmsg:        udpv6_recvmsg,
1021
        backlog_rcv:    udpv6_queue_rcv_skb,
1022
        hash:           udp_v6_hash,
1023
        unhash:         udp_v6_unhash,
1024
        get_port:       udp_v6_get_port,
1025
};
1026
 
1027
extern struct proto_ops inet6_dgram_ops;
1028
 
1029
static struct inet_protosw udpv6_protosw = {
1030
        type:        SOCK_DGRAM,
1031
        protocol:    IPPROTO_UDP,
1032
        prot:        &udpv6_prot,
1033
        ops:         &inet6_dgram_ops,
1034
        capability:  -1,
1035
        no_check:    UDP_CSUM_DEFAULT,
1036
        flags:       INET_PROTOSW_PERMANENT,
1037
};
1038
 
1039
 
1040
void __init udpv6_init(void)
1041
{
1042
        inet6_add_protocol(&udpv6_protocol);
1043
        inet6_register_protosw(&udpv6_protosw);
1044
}

powered by: WebSVN 2.1.0

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