~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/ipv6/raw.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.