raw.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:20k
源码类别:

Linux/Unix编程

开发平台:

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