raw.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:18k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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