File: /usr/src/linux/net/ipv6/raw.c
1 /*
2 * RAW sockets for IPv6
3 * Linux INET6 implementation
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 *
8 * Adapted from linux/net/ipv4/raw.c
9 *
10 * $Id: raw.c,v 1.50 2001/09/18 22:29:10 davem Exp $
11 *
12 * Fixes:
13 * Hideaki YOSHIFUJI : sin6_scope_id support
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version
18 * 2 of the License, or (at your option) any later version.
19 */
20
21 #include <linux/errno.h>
22 #include <linux/types.h>
23 #include <linux/socket.h>
24 #include <linux/sockios.h>
25 #include <linux/sched.h>
26 #include <linux/net.h>
27 #include <linux/in6.h>
28 #include <linux/netdevice.h>
29 #include <linux/if_arp.h>
30 #include <linux/icmpv6.h>
31 #include <asm/uaccess.h>
32 #include <asm/ioctls.h>
33
34 #include <net/sock.h>
35 #include <net/snmp.h>
36
37 #include <net/ipv6.h>
38 #include <net/ndisc.h>
39 #include <net/protocol.h>
40 #include <net/ip6_route.h>
41 #include <net/addrconf.h>
42 #include <net/transp_v6.h>
43 #include <net/udp.h>
44 #include <net/inet_common.h>
45
46 #include <net/rawv6.h>
47
48 struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE];
49 rwlock_t raw_v6_lock = RW_LOCK_UNLOCKED;
50
51 static void raw_v6_hash(struct sock *sk)
52 {
53 struct sock **skp = &raw_v6_htable[sk->num & (RAWV6_HTABLE_SIZE - 1)];
54
55 write_lock_bh(&raw_v6_lock);
56 if ((sk->next = *skp) != NULL)
57 (*skp)->pprev = &sk->next;
58 *skp = sk;
59 sk->pprev = skp;
60 sock_prot_inc_use(sk->prot);
61 sock_hold(sk);
62 write_unlock_bh(&raw_v6_lock);
63 }
64
65 static void raw_v6_unhash(struct sock *sk)
66 {
67 write_lock_bh(&raw_v6_lock);
68 if (sk->pprev) {
69 if (sk->next)
70 sk->next->pprev = sk->pprev;
71 *sk->pprev = sk->next;
72 sk->pprev = NULL;
73 sock_prot_dec_use(sk->prot);
74 __sock_put(sk);
75 }
76 write_unlock_bh(&raw_v6_lock);
77 }
78
79
80 /* Grumble... icmp and ip_input want to get at this... */
81 struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
82 struct in6_addr *loc_addr, struct in6_addr *rmt_addr)
83 {
84 struct sock *s = sk;
85 int addr_type = ipv6_addr_type(loc_addr);
86
87 for(s = sk; s; s = s->next) {
88 if(s->num == num) {
89 struct ipv6_pinfo *np = &s->net_pinfo.af_inet6;
90
91 if (!ipv6_addr_any(&np->daddr) &&
92 ipv6_addr_cmp(&np->daddr, rmt_addr))
93 continue;
94
95 if (!ipv6_addr_any(&np->rcv_saddr)) {
96 if (ipv6_addr_cmp(&np->rcv_saddr, loc_addr) == 0)
97 break;
98 if ((addr_type & IPV6_ADDR_MULTICAST) &&
99 inet6_mc_check(s, loc_addr))
100 break;
101 continue;
102 }
103 break;
104 }
105 }
106 return s;
107 }
108
109 /*
110 * 0 - deliver
111 * 1 - block
112 */
113 static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
114 {
115 struct icmp6hdr *icmph;
116 struct raw6_opt *opt;
117
118 opt = &sk->tp_pinfo.tp_raw;
119 if (pskb_may_pull(skb, sizeof(struct icmp6hdr))) {
120 __u32 *data = &opt->filter.data[0];
121 int bit_nr;
122
123 icmph = (struct icmp6hdr *) skb->data;
124 bit_nr = icmph->icmp6_type;
125
126 return (data[bit_nr >> 5] & (1 << (bit_nr & 31))) != 0;
127 }
128 return 0;
129 }
130
131 /*
132 * demultiplex raw sockets.
133 * (should consider queueing the skb in the sock receive_queue
134 * without calling rawv6.c)
135 */
136 struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
137 {
138 struct in6_addr *saddr;
139 struct in6_addr *daddr;
140 struct sock *sk, *sk2;
141 __u8 hash;
142
143 saddr = &skb->nh.ipv6h->saddr;
144 daddr = saddr + 1;
145
146 hash = nexthdr & (MAX_INET_PROTOS - 1);
147
148 read_lock(&raw_v6_lock);
149 sk = raw_v6_htable[hash];
150
151 /*
152 * The first socket found will be delivered after
153 * delivery to transport protocols.
154 */
155
156 if (sk == NULL)
157 goto out;
158
159 sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr);
160
161 if (sk) {
162 sk2 = sk;
163
164 while ((sk2 = __raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) {
165 struct sk_buff *buff;
166
167 if (nexthdr == IPPROTO_ICMPV6 &&
168 icmpv6_filter(sk2, skb))
169 continue;
170
171 buff = skb_clone(skb, GFP_ATOMIC);
172 if (buff)
173 rawv6_rcv(sk2, buff);
174 }
175 }
176
177 if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb))
178 sk = NULL;
179
180 out:
181 if (sk)
182 sock_hold(sk);
183 read_unlock(&raw_v6_lock);
184 return sk;
185 }
186
187 /* This cleans up af_inet6 a bit. -DaveM */
188 static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
189 {
190 struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr;
191 __u32 v4addr = 0;
192 int addr_type;
193 int err;
194
195 if (addr_len < SIN6_LEN_RFC2133)
196 return -EINVAL;
197 addr_type = ipv6_addr_type(&addr->sin6_addr);
198
199 /* Raw sockets are IPv6 only */
200 if (addr_type == IPV6_ADDR_MAPPED)
201 return(-EADDRNOTAVAIL);
202
203 lock_sock(sk);
204
205 err = -EINVAL;
206 if (sk->state != TCP_CLOSE)
207 goto out;
208
209 if (addr_type & IPV6_ADDR_LINKLOCAL) {
210 if (addr_len >= sizeof(struct sockaddr_in6) &&
211 addr->sin6_scope_id) {
212 /* Override any existing binding, if another one
213 * is supplied by user.
214 */
215 sk->bound_dev_if = addr->sin6_scope_id;
216 }
217
218 /* Binding to link-local address requires an interface */
219 if (sk->bound_dev_if == 0)
220 goto out;
221 }
222
223 /* Check if the address belongs to the host. */
224 if (addr_type != IPV6_ADDR_ANY) {
225 /* ipv4 addr of the socket is invalid. Only the
226 * unpecified and mapped address have a v4 equivalent.
227 */
228 v4addr = LOOPBACK4_IPV6;
229 if (!(addr_type & IPV6_ADDR_MULTICAST)) {
230 err = -EADDRNOTAVAIL;
231 if (!ipv6_chk_addr(&addr->sin6_addr, NULL))
232 goto out;
233 }
234 }
235
236 sk->rcv_saddr = v4addr;
237 sk->saddr = v4addr;
238 ipv6_addr_copy(&sk->net_pinfo.af_inet6.rcv_saddr, &addr->sin6_addr);
239 if (!(addr_type & IPV6_ADDR_MULTICAST))
240 ipv6_addr_copy(&sk->net_pinfo.af_inet6.saddr, &addr->sin6_addr);
241 err = 0;
242 out:
243 release_sock(sk);
244 return err;
245 }
246
247 void rawv6_err(struct sock *sk, struct sk_buff *skb,
248 struct inet6_skb_parm *opt,
249 int type, int code, int offset, u32 info)
250 {
251 int err;
252 int harderr;
253
254 /* Report error on raw socket, if:
255 1. User requested recverr.
256 2. Socket is connected (otherwise the error indication
257 is useless without recverr and error is hard.
258 */
259 if (!sk->net_pinfo.af_inet6.recverr && sk->state != TCP_ESTABLISHED)
260 return;
261
262 harderr = icmpv6_err_convert(type, code, &err);
263 if (type == ICMPV6_PKT_TOOBIG)
264 harderr = (sk->net_pinfo.af_inet6.pmtudisc == IPV6_PMTUDISC_DO);
265
266 if (sk->net_pinfo.af_inet6.recverr) {
267 u8 *payload = skb->data;
268 if (!sk->protinfo.af_inet.hdrincl)
269 payload += offset;
270 ipv6_icmp_error(sk, skb, err, 0, ntohl(info), payload);
271 }
272
273 if (sk->net_pinfo.af_inet6.recverr || harderr) {
274 sk->err = err;
275 sk->error_report(sk);
276 }
277 }
278
279 static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
280 {
281 /* Charge it to the socket. */
282 if (sock_queue_rcv_skb(sk,skb)<0) {
283 IP6_INC_STATS_BH(Ip6InDiscards);
284 kfree_skb(skb);
285 return 0;
286 }
287
288 IP6_INC_STATS_BH(Ip6InDelivers);
289 return 0;
290 }
291
292 /*
293 * This is next to useless...
294 * if we demultiplex in network layer we don't need the extra call
295 * just to queue the skb...
296 * maybe we could have the network decide uppon a hint if it
297 * should call raw_rcv for demultiplexing
298 */
299 int rawv6_rcv(struct sock *sk, struct sk_buff *skb)
300 {
301 if (sk->protinfo.af_inet.hdrincl) {
302 __skb_push(skb, skb->nh.raw - skb->data);
303 skb->h.raw = skb->nh.raw;
304 }
305
306 rawv6_rcv_skb(sk, skb);
307 return 0;
308 }
309
310
311 /*
312 * This should be easy, if there is something there
313 * we return it, otherwise we block.
314 */
315
316 int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
317 int noblock, int flags, int *addr_len)
318 {
319 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)msg->msg_name;
320 struct sk_buff *skb;
321 int copied, err;
322
323 if (flags & MSG_OOB)
324 return -EOPNOTSUPP;
325
326 if (addr_len)
327 *addr_len=sizeof(*sin6);
328
329 if (flags & MSG_ERRQUEUE)
330 return ipv6_recv_error(sk, msg, len);
331
332 skb = skb_recv_datagram(sk, flags, noblock, &err);
333 if (!skb)
334 goto out;
335
336 copied = skb->len;
337 if (copied > len) {
338 copied = len;
339 msg->msg_flags |= MSG_TRUNC;
340 }
341
342 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
343 if (err)
344 goto out_free;
345
346 /* Copy the address. */
347 if (sin6) {
348 sin6->sin6_family = AF_INET6;
349 memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
350 sizeof(struct in6_addr));
351 sin6->sin6_flowinfo = 0;
352 sin6->sin6_scope_id = 0;
353 if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
354 struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
355 sin6->sin6_scope_id = opt->iif;
356 }
357 }
358
359 sock_recv_timestamp(msg, sk, skb);
360
361 if (sk->net_pinfo.af_inet6.rxopt.all)
362 datagram_recv_ctl(sk, msg, skb);
363 err = copied;
364
365 out_free:
366 skb_free_datagram(sk, skb);
367 out:
368 return err;
369 }
370
371 /*
372 * Sending...
373 */
374
375 struct rawv6_fakehdr {
376 struct iovec *iov;
377 struct sock *sk;
378 __u32 len;
379 __u32 cksum;
380 __u32 proto;
381 struct in6_addr *daddr;
382 };
383
384 static int rawv6_getfrag(const void *data, struct in6_addr *saddr,
385 char *buff, unsigned int offset, unsigned int len)
386 {
387 struct iovec *iov = (struct iovec *) data;
388
389 return memcpy_fromiovecend(buff, iov, offset, len);
390 }
391
392 static int rawv6_frag_cksum(const void *data, struct in6_addr *addr,
393 char *buff, unsigned int offset,
394 unsigned int len)
395 {
396 struct rawv6_fakehdr *hdr = (struct rawv6_fakehdr *) data;
397
398 if (csum_partial_copy_fromiovecend(buff, hdr->iov, offset,
399 len, &hdr->cksum))
400 return -EFAULT;
401
402 if (offset == 0) {
403 struct sock *sk;
404 struct raw6_opt *opt;
405 struct in6_addr *daddr;
406
407 sk = hdr->sk;
408 opt = &sk->tp_pinfo.tp_raw;
409
410 if (hdr->daddr)
411 daddr = hdr->daddr;
412 else
413 daddr = addr + 1;
414
415 hdr->cksum = csum_ipv6_magic(addr, daddr, hdr->len,
416 hdr->proto, hdr->cksum);
417
418 if (opt->offset < len) {
419 __u16 *csum;
420
421 csum = (__u16 *) (buff + opt->offset);
422 *csum = hdr->cksum;
423 } else {
424 if (net_ratelimit())
425 printk(KERN_DEBUG "icmp: cksum offset too big\n");
426 return -EINVAL;
427 }
428 }
429 return 0;
430 }
431
432
433 static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
434 {
435 struct ipv6_txoptions opt_space;
436 struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
437 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
438 struct ipv6_txoptions *opt = NULL;
439 struct ip6_flowlabel *flowlabel = NULL;
440 struct flowi fl;
441 int addr_len = msg->msg_namelen;
442 struct in6_addr *daddr;
443 struct raw6_opt *raw_opt;
444 int hlimit = -1;
445 u16 proto;
446 int err;
447
448 /* Rough check on arithmetic overflow,
449 better check is made in ip6_build_xmit
450 */
451 if (len < 0)
452 return -EMSGSIZE;
453
454 /* Mirror BSD error message compatibility */
455 if (msg->msg_flags & MSG_OOB)
456 return -EOPNOTSUPP;
457
458 /*
459 * Get and verify the address.
460 */
461
462 fl.fl6_flowlabel = 0;
463 fl.oif = 0;
464
465 if (sin6) {
466 if (addr_len < SIN6_LEN_RFC2133)
467 return -EINVAL;
468
469 if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
470 return(-EINVAL);
471
472 /* port is the proto value [0..255] carried in nexthdr */
473 proto = ntohs(sin6->sin6_port);
474
475 if (!proto)
476 proto = sk->num;
477
478 if (proto > 255)
479 return(-EINVAL);
480
481 daddr = &sin6->sin6_addr;
482 if (np->sndflow) {
483 fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
484 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
485 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
486 if (flowlabel == NULL)
487 return -EINVAL;
488 daddr = &flowlabel->dst;
489 }
490 }
491
492 /* Otherwise it will be difficult to maintain sk->dst_cache. */
493 if (sk->state == TCP_ESTABLISHED &&
494 !ipv6_addr_cmp(daddr, &sk->net_pinfo.af_inet6.daddr))
495 daddr = &sk->net_pinfo.af_inet6.daddr;
496
497 if (addr_len >= sizeof(struct sockaddr_in6) &&
498 sin6->sin6_scope_id &&
499 ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
500 fl.oif = sin6->sin6_scope_id;
501 } else {
502 if (sk->state != TCP_ESTABLISHED)
503 return(-EINVAL);
504
505 proto = sk->num;
506 daddr = &(sk->net_pinfo.af_inet6.daddr);
507 fl.fl6_flowlabel = np->flow_label;
508 }
509
510 if (ipv6_addr_any(daddr)) {
511 /*
512 * unspecfied destination address
513 * treated as error... is this correct ?
514 */
515 return(-EINVAL);
516 }
517
518 if (fl.oif == 0)
519 fl.oif = sk->bound_dev_if;
520 fl.fl6_src = NULL;
521
522 if (msg->msg_controllen) {
523 opt = &opt_space;
524 memset(opt, 0, sizeof(struct ipv6_txoptions));
525
526 err = datagram_send_ctl(msg, &fl, opt, &hlimit);
527 if (err < 0) {
528 fl6_sock_release(flowlabel);
529 return err;
530 }
531 if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
532 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
533 if (flowlabel == NULL)
534 return -EINVAL;
535 }
536 if (!(opt->opt_nflen|opt->opt_flen))
537 opt = NULL;
538 }
539 if (opt == NULL)
540 opt = np->opt;
541 if (flowlabel)
542 opt = fl6_merge_options(&opt_space, flowlabel, opt);
543
544 raw_opt = &sk->tp_pinfo.tp_raw;
545
546 fl.proto = proto;
547 fl.fl6_dst = daddr;
548 if (fl.fl6_src == NULL && !ipv6_addr_any(&np->saddr))
549 fl.fl6_src = &np->saddr;
550 fl.uli_u.icmpt.type = 0;
551 fl.uli_u.icmpt.code = 0;
552
553 if (raw_opt->checksum) {
554 struct rawv6_fakehdr hdr;
555
556 hdr.iov = msg->msg_iov;
557 hdr.sk = sk;
558 hdr.len = len;
559 hdr.cksum = 0;
560 hdr.proto = proto;
561
562 if (opt && opt->srcrt)
563 hdr.daddr = daddr;
564 else
565 hdr.daddr = NULL;
566
567 err = ip6_build_xmit(sk, rawv6_frag_cksum, &hdr, &fl, len,
568 opt, hlimit, msg->msg_flags);
569 } else {
570 err = ip6_build_xmit(sk, rawv6_getfrag, msg->msg_iov, &fl, len,
571 opt, hlimit, msg->msg_flags);
572 }
573
574 fl6_sock_release(flowlabel);
575
576 return err<0?err:len;
577 }
578
579 static int rawv6_seticmpfilter(struct sock *sk, int level, int optname,
580 char *optval, int optlen)
581 {
582 switch (optname) {
583 case ICMPV6_FILTER:
584 if (optlen > sizeof(struct icmp6_filter))
585 optlen = sizeof(struct icmp6_filter);
586 if (copy_from_user(&sk->tp_pinfo.tp_raw.filter, optval, optlen))
587 return -EFAULT;
588 return 0;
589 default:
590 return -ENOPROTOOPT;
591 };
592
593 return 0;
594 }
595
596 static int rawv6_geticmpfilter(struct sock *sk, int level, int optname,
597 char *optval, int *optlen)
598 {
599 int len;
600
601 switch (optname) {
602 case ICMPV6_FILTER:
603 if (get_user(len, optlen))
604 return -EFAULT;
605 if (len < 0)
606 return -EINVAL;
607 if (len > sizeof(struct icmp6_filter))
608 len = sizeof(struct icmp6_filter);
609 if (put_user(len, optlen))
610 return -EFAULT;
611 if (copy_to_user(optval, &sk->tp_pinfo.tp_raw.filter, len))
612 return -EFAULT;
613 return 0;
614 default:
615 return -ENOPROTOOPT;
616 };
617
618 return 0;
619 }
620
621
622 static int rawv6_setsockopt(struct sock *sk, int level, int optname,
623 char *optval, int optlen)
624 {
625 struct raw6_opt *opt = &sk->tp_pinfo.tp_raw;
626 int val;
627
628 switch(level) {
629 case SOL_RAW:
630 break;
631
632 case SOL_ICMPV6:
633 if (sk->num != IPPROTO_ICMPV6)
634 return -EOPNOTSUPP;
635 return rawv6_seticmpfilter(sk, level, optname, optval,
636 optlen);
637 case SOL_IPV6:
638 if (optname == IPV6_CHECKSUM)
639 break;
640 default:
641 return ipv6_setsockopt(sk, level, optname, optval,
642 optlen);
643 };
644
645 if (get_user(val, (int *)optval))
646 return -EFAULT;
647
648 switch (optname) {
649 case IPV6_CHECKSUM:
650 if (val < 0) {
651 opt->checksum = 0;
652 } else {
653 opt->checksum = 1;
654 opt->offset = val;
655 }
656
657 return 0;
658 break;
659
660 default:
661 return(-ENOPROTOOPT);
662 }
663 }
664
665 static int rawv6_getsockopt(struct sock *sk, int level, int optname,
666 char *optval, int *optlen)
667 {
668 struct raw6_opt *opt = &sk->tp_pinfo.tp_raw;
669 int val, len;
670
671 switch(level) {
672 case SOL_RAW:
673 break;
674
675 case SOL_ICMPV6:
676 if (sk->num != IPPROTO_ICMPV6)
677 return -EOPNOTSUPP;
678 return rawv6_geticmpfilter(sk, level, optname, optval,
679 optlen);
680 case SOL_IPV6:
681 if (optname == IPV6_CHECKSUM)
682 break;
683 default:
684 return ipv6_getsockopt(sk, level, optname, optval,
685 optlen);
686 };
687
688 if (get_user(len,optlen))
689 return -EFAULT;
690
691 switch (optname) {
692 case IPV6_CHECKSUM:
693 if (opt->checksum == 0)
694 val = -1;
695 else
696 val = opt->offset;
697
698 default:
699 return -ENOPROTOOPT;
700 }
701
702 len = min_t(unsigned int, sizeof(int), len);
703
704 if (put_user(len, optlen))
705 return -EFAULT;
706 if (copy_to_user(optval,&val,len))
707 return -EFAULT;
708 return 0;
709 }
710
711 static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
712 {
713 switch(cmd) {
714 case SIOCOUTQ:
715 {
716 int amount = atomic_read(&sk->wmem_alloc);
717 return put_user(amount, (int *)arg);
718 }
719 case SIOCINQ:
720 {
721 struct sk_buff *skb;
722 int amount = 0;
723
724 spin_lock_irq(&sk->receive_queue.lock);
725 skb = skb_peek(&sk->receive_queue);
726 if (skb != NULL)
727 amount = skb->tail - skb->h.raw;
728 spin_unlock_irq(&sk->receive_queue.lock);
729 return put_user(amount, (int *)arg);
730 }
731
732 default:
733 return -ENOIOCTLCMD;
734 }
735 }
736
737 static void rawv6_close(struct sock *sk, long timeout)
738 {
739 if (sk->num == IPPROTO_RAW)
740 ip6_ra_control(sk, -1, NULL);
741
742 inet_sock_release(sk);
743 }
744
745 static int rawv6_init_sk(struct sock *sk)
746 {
747 return(0);
748 }
749
750 #define LINE_LEN 190
751 #define LINE_FMT "%-190s\n"
752
753 static void get_raw6_sock(struct sock *sp, char *tmpbuf, int i)
754 {
755 struct in6_addr *dest, *src;
756 __u16 destp, srcp;
757
758 dest = &sp->net_pinfo.af_inet6.daddr;
759 src = &sp->net_pinfo.af_inet6.rcv_saddr;
760 destp = 0;
761 srcp = sp->num;
762 sprintf(tmpbuf,
763 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
764 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p",
765 i,
766 src->s6_addr32[0], src->s6_addr32[1],
767 src->s6_addr32[2], src->s6_addr32[3], srcp,
768 dest->s6_addr32[0], dest->s6_addr32[1],
769 dest->s6_addr32[2], dest->s6_addr32[3], destp,
770 sp->state,
771 atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
772 0, 0L, 0,
773 sock_i_uid(sp), 0,
774 sock_i_ino(sp),
775 atomic_read(&sp->refcnt), sp);
776 }
777
778 int raw6_get_info(char *buffer, char **start, off_t offset, int length)
779 {
780 int len = 0, num = 0, i;
781 off_t pos = 0;
782 off_t begin;
783 char tmpbuf[LINE_LEN+2];
784
785 if (offset < LINE_LEN+1)
786 len += sprintf(buffer, LINE_FMT,
787 " sl " /* 6 */
788 "local_address " /* 38 */
789 "remote_address " /* 38 */
790 "st tx_queue rx_queue tr tm->when retrnsmt" /* 41 */
791 " uid timeout inode"); /* 21 */
792 /*----*/
793 /*144 */
794 pos = LINE_LEN+1;
795 read_lock(&raw_v6_lock);
796 for (i = 0; i < RAWV6_HTABLE_SIZE; i++) {
797 struct sock *sk;
798
799 for (sk = raw_v6_htable[i]; sk; sk = sk->next, num++) {
800 if (sk->family != PF_INET6)
801 continue;
802 pos += LINE_LEN+1;
803 if (pos <= offset)
804 continue;
805 get_raw6_sock(sk, tmpbuf, i);
806 len += sprintf(buffer+len, LINE_FMT, tmpbuf);
807 if(len >= length)
808 goto out;
809 }
810 }
811 out:
812 read_unlock(&raw_v6_lock);
813 begin = len - (pos - offset);
814 *start = buffer + begin;
815 len -= begin;
816 if(len > length)
817 len = length;
818 if (len < 0)
819 len = 0;
820 return len;
821 }
822
823 struct proto rawv6_prot = {
824 name: "RAW",
825 close: rawv6_close,
826 connect: udpv6_connect,
827 disconnect: udp_disconnect,
828 ioctl: rawv6_ioctl,
829 init: rawv6_init_sk,
830 destroy: inet6_destroy_sock,
831 setsockopt: rawv6_setsockopt,
832 getsockopt: rawv6_getsockopt,
833 sendmsg: rawv6_sendmsg,
834 recvmsg: rawv6_recvmsg,
835 bind: rawv6_bind,
836 backlog_rcv: rawv6_rcv_skb,
837 hash: raw_v6_hash,
838 unhash: raw_v6_unhash,
839 };
840