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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * ip6_flowlabel.c IPv6 flowlabel manager.
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  *      modify it under the terms of the GNU General Public License
  6.  *      as published by the Free Software Foundation; either version
  7.  *      2 of the License, or (at your option) any later version.
  8.  *
  9.  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  10.  */
  11. #include <linux/config.h>
  12. #include <linux/errno.h>
  13. #include <linux/types.h>
  14. #include <linux/socket.h>
  15. #include <linux/net.h>
  16. #include <linux/netdevice.h>
  17. #include <linux/if_arp.h>
  18. #include <linux/in6.h>
  19. #include <linux/route.h>
  20. #include <linux/proc_fs.h>
  21. #include <net/sock.h>
  22. #include <net/ipv6.h>
  23. #include <net/ndisc.h>
  24. #include <net/protocol.h>
  25. #include <net/ip6_route.h>
  26. #include <net/addrconf.h>
  27. #include <net/rawv6.h>
  28. #include <net/icmp.h>
  29. #include <net/transp_v6.h>
  30. #include <asm/uaccess.h>
  31. #define FL_MIN_LINGER 6 /* Minimal linger. It is set to 6sec specified
  32.    in old IPv6 RFC. Well, it was reasonable value.
  33.  */
  34. #define FL_MAX_LINGER 60 /* Maximal linger timeout */
  35. /* FL hash table */
  36. #define FL_MAX_PER_SOCK 32
  37. #define FL_MAX_SIZE 4096
  38. #define FL_HASH_MASK 255
  39. #define FL_HASH(l) (ntohl(l)&FL_HASH_MASK)
  40. static atomic_t fl_size = ATOMIC_INIT(0);
  41. static struct ip6_flowlabel *fl_ht[FL_HASH_MASK+1];
  42. static struct timer_list ip6_fl_gc_timer;
  43. /* FL hash table lock: it protects only of GC */
  44. static rwlock_t ip6_fl_lock = RW_LOCK_UNLOCKED;
  45. /* Big socket sock */
  46. static rwlock_t ip6_sk_fl_lock = RW_LOCK_UNLOCKED;
  47. static __inline__ struct ip6_flowlabel * __fl_lookup(u32 label)
  48. {
  49. struct ip6_flowlabel *fl;
  50. for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) {
  51. if (fl->label == label)
  52. return fl;
  53. }
  54. return NULL;
  55. }
  56. static struct ip6_flowlabel * fl_lookup(u32 label)
  57. {
  58. struct ip6_flowlabel *fl;
  59. read_lock_bh(&ip6_fl_lock);
  60. fl = __fl_lookup(label);
  61. if (fl)
  62. atomic_inc(&fl->users);
  63. read_unlock_bh(&ip6_fl_lock);
  64. return fl;
  65. }
  66. static void fl_free(struct ip6_flowlabel *fl)
  67. {
  68. if (fl->opt)
  69. kfree(fl->opt);
  70. kfree(fl);
  71. }
  72. static void fl_release(struct ip6_flowlabel *fl)
  73. {
  74. fl->lastuse = jiffies;
  75. if (atomic_dec_and_test(&fl->users)) {
  76. unsigned long ttd = fl->lastuse + fl->linger;
  77. if ((long)(ttd - fl->expires) > 0)
  78. fl->expires = ttd;
  79. ttd = fl->expires;
  80. if (fl->opt && fl->share == IPV6_FL_S_EXCL) {
  81. struct ipv6_txoptions *opt = fl->opt;
  82. fl->opt = NULL;
  83. kfree(opt);
  84. }
  85. if (!del_timer(&ip6_fl_gc_timer) ||
  86.     (long)(ip6_fl_gc_timer.expires - ttd) > 0)
  87. ip6_fl_gc_timer.expires = ttd;
  88. add_timer(&ip6_fl_gc_timer);
  89. }
  90. }
  91. static void ip6_fl_gc(unsigned long dummy)
  92. {
  93. int i;
  94. unsigned long now = jiffies;
  95. unsigned long sched = 0;
  96. write_lock(&ip6_fl_lock);
  97. for (i=0; i<=FL_HASH_MASK; i++) {
  98. struct ip6_flowlabel *fl, **flp;
  99. flp = &fl_ht[i];
  100. while ((fl=*flp) != NULL) {
  101. if (atomic_read(&fl->users) == 0) {
  102. unsigned long ttd = fl->lastuse + fl->linger;
  103. if ((long)(ttd - fl->expires) > 0)
  104. fl->expires = ttd;
  105. ttd = fl->expires;
  106. if ((long)(now - ttd) >= 0) {
  107. *flp = fl->next;
  108. fl_free(fl);
  109. atomic_dec(&fl_size);
  110. continue;
  111. }
  112. if (!sched || (long)(ttd - sched) < 0)
  113. sched = ttd;
  114. }
  115. flp = &fl->next;
  116. }
  117. }
  118. if (!sched && atomic_read(&fl_size))
  119. sched = now + FL_MAX_LINGER;
  120. if (sched) {
  121. ip6_fl_gc_timer.expires = sched;
  122. add_timer(&ip6_fl_gc_timer);
  123. }
  124. write_unlock(&ip6_fl_lock);
  125. }
  126. static int fl_intern(struct ip6_flowlabel *fl, __u32 label)
  127. {
  128. fl->label = label & IPV6_FLOWLABEL_MASK;
  129. write_lock_bh(&ip6_fl_lock);
  130. if (label == 0) {
  131. for (;;) {
  132. fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK;
  133. if (fl->label) {
  134. struct ip6_flowlabel *lfl;
  135. lfl = __fl_lookup(fl->label);
  136. if (lfl == NULL)
  137. break;
  138. }
  139. }
  140. }
  141. fl->lastuse = jiffies;
  142. fl->next = fl_ht[FL_HASH(fl->label)];
  143. fl_ht[FL_HASH(fl->label)] = fl;
  144. atomic_inc(&fl_size);
  145. write_unlock_bh(&ip6_fl_lock);
  146. return 0;
  147. }
  148. /* Socket flowlabel lists */
  149. struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, u32 label)
  150. {
  151. struct ipv6_fl_socklist *sfl;
  152. struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
  153. label &= IPV6_FLOWLABEL_MASK;
  154. for (sfl=np->ipv6_fl_list; sfl; sfl = sfl->next) {
  155. struct ip6_flowlabel *fl = sfl->fl;
  156. if (fl->label == label) {
  157. fl->lastuse = jiffies;
  158. atomic_inc(&fl->users);
  159. return fl;
  160. }
  161. }
  162. return NULL;
  163. }
  164. void fl6_free_socklist(struct sock *sk)
  165. {
  166. struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
  167. struct ipv6_fl_socklist *sfl;
  168. while ((sfl = np->ipv6_fl_list) != NULL) {
  169. np->ipv6_fl_list = sfl->next;
  170. fl_release(sfl->fl);
  171. kfree(sfl);
  172. }
  173. }
  174. /* Service routines */
  175. /*
  176.    It is the only difficult place. flowlabel enforces equal headers
  177.    before and including routing header, however user may supply options
  178.    following rthdr.
  179.  */
  180. struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
  181.  struct ip6_flowlabel * fl,
  182.  struct ipv6_txoptions * fopt)
  183. {
  184. struct ipv6_txoptions * fl_opt = fl->opt;
  185. if (fopt == NULL || fopt->opt_flen == 0)
  186. return fl_opt;
  187. if (fl_opt != NULL) {
  188. opt_space->hopopt = fl_opt->hopopt;
  189. opt_space->dst0opt = fl_opt->dst0opt;
  190. opt_space->srcrt = fl_opt->srcrt;
  191. opt_space->opt_nflen = fl_opt->opt_nflen;
  192. } else {
  193. if (fopt->opt_nflen == 0)
  194. return fopt;
  195. opt_space->hopopt = NULL;
  196. opt_space->dst0opt = NULL;
  197. opt_space->srcrt = NULL;
  198. opt_space->opt_nflen = 0;
  199. }
  200. opt_space->dst1opt = fopt->dst1opt;
  201. opt_space->auth = fopt->auth;
  202. opt_space->opt_flen = fopt->opt_flen;
  203. return opt_space;
  204. }
  205. static __u32 check_linger(__u16 ttl)
  206. {
  207. if (ttl < FL_MIN_LINGER)
  208. return FL_MIN_LINGER*HZ;
  209. if (ttl > FL_MAX_LINGER && !capable(CAP_NET_ADMIN))
  210. return 0;
  211. return ttl*HZ;
  212. }
  213. static int fl6_renew(struct ip6_flowlabel *fl, unsigned linger, unsigned expires)
  214. {
  215. linger = check_linger(linger);
  216. if (!linger)
  217. return -EPERM;
  218. expires = check_linger(expires);
  219. if (!expires)
  220. return -EPERM;
  221. fl->lastuse = jiffies;
  222. if (fl->linger < linger)
  223. fl->linger = linger;
  224. if (expires < fl->linger)
  225. expires = fl->linger;
  226. if ((long)(fl->expires - (fl->lastuse+expires)) < 0)
  227. fl->expires = fl->lastuse + expires;
  228. return 0;
  229. }
  230. static struct ip6_flowlabel *
  231. fl_create(struct in6_flowlabel_req *freq, char *optval, int optlen, int *err_p)
  232. {
  233. struct ip6_flowlabel *fl;
  234. int olen;
  235. int addr_type;
  236. int err;
  237. err = -ENOMEM;
  238. fl = kmalloc(sizeof(*fl), GFP_KERNEL);
  239. if (fl == NULL)
  240. goto done;
  241. memset(fl, 0, sizeof(*fl));
  242. olen = optlen - CMSG_ALIGN(sizeof(*freq));
  243. if (olen > 0) {
  244. struct msghdr msg;
  245. struct flowi flowi;
  246. int junk;
  247. err = -ENOMEM;
  248. fl->opt = kmalloc(sizeof(*fl->opt) + olen, GFP_KERNEL);
  249. if (fl->opt == NULL)
  250. goto done;
  251. memset(fl->opt, 0, sizeof(*fl->opt));
  252. fl->opt->tot_len = sizeof(*fl->opt) + olen;
  253. err = -EFAULT;
  254. if (copy_from_user(fl->opt+1, optval+CMSG_ALIGN(sizeof(*freq)), olen))
  255. goto done;
  256. msg.msg_controllen = olen;
  257. msg.msg_control = (void*)(fl->opt+1);
  258. flowi.oif = 0;
  259. err = datagram_send_ctl(&msg, &flowi, fl->opt, &junk);
  260. if (err)
  261. goto done;
  262. err = -EINVAL;
  263. if (fl->opt->opt_flen)
  264. goto done;
  265. if (fl->opt->opt_nflen == 0) {
  266. kfree(fl->opt);
  267. fl->opt = NULL;
  268. }
  269. }
  270. fl->expires = jiffies;
  271. err = fl6_renew(fl, freq->flr_linger, freq->flr_expires);
  272. if (err)
  273. goto done;
  274. fl->share = freq->flr_share;
  275. addr_type = ipv6_addr_type(&freq->flr_dst);
  276. if ((addr_type&IPV6_ADDR_MAPPED)
  277.     || addr_type == IPV6_ADDR_ANY)
  278. goto done;
  279. ipv6_addr_copy(&fl->dst, &freq->flr_dst);
  280. atomic_set(&fl->users, 1);
  281. switch (fl->share) {
  282. case IPV6_FL_S_EXCL:
  283. case IPV6_FL_S_ANY:
  284. break;
  285. case IPV6_FL_S_PROCESS:
  286. fl->owner = current->pid;
  287. break;
  288. case IPV6_FL_S_USER:
  289. fl->owner = current->euid;
  290. break;
  291. default:
  292. err = -EINVAL;
  293. goto done;
  294. }
  295. return fl;
  296. done:
  297. if (fl)
  298. fl_free(fl);
  299. *err_p = err;
  300. return NULL;
  301. }
  302. static int mem_check(struct sock *sk)
  303. {
  304. struct ipv6_fl_socklist *sfl;
  305. int room = FL_MAX_SIZE - atomic_read(&fl_size);
  306. int count = 0;
  307. if (room > FL_MAX_SIZE - FL_MAX_PER_SOCK)
  308. return 0;
  309. for (sfl = sk->net_pinfo.af_inet6.ipv6_fl_list; sfl; sfl = sfl->next)
  310. count++;
  311. if (room <= 0 ||
  312.     ((count >= FL_MAX_PER_SOCK ||
  313.      (count > 0 && room < FL_MAX_SIZE/2) || room < FL_MAX_SIZE/4)
  314.      && !capable(CAP_NET_ADMIN)))
  315. return -ENOBUFS;
  316. return 0;
  317. }
  318. static int ipv6_hdr_cmp(struct ipv6_opt_hdr *h1, struct ipv6_opt_hdr *h2)
  319. {
  320. if (h1 == h2)
  321. return 0;
  322. if (h1 == NULL || h2 == NULL)
  323. return 1;
  324. if (h1->hdrlen != h2->hdrlen)
  325. return 1;
  326. return memcmp(h1+1, h2+1, ((h1->hdrlen+1)<<3) - sizeof(*h1));
  327. }
  328. static int ipv6_opt_cmp(struct ipv6_txoptions *o1, struct ipv6_txoptions *o2)
  329. {
  330. if (o1 == o2)
  331. return 0;
  332. if (o1 == NULL || o2 == NULL)
  333. return 1;
  334. if (o1->opt_nflen != o2->opt_nflen)
  335. return 1;
  336. if (ipv6_hdr_cmp(o1->hopopt, o2->hopopt))
  337. return 1;
  338. if (ipv6_hdr_cmp(o1->dst0opt, o2->dst0opt))
  339. return 1;
  340. if (ipv6_hdr_cmp((struct ipv6_opt_hdr *)o1->srcrt, (struct ipv6_opt_hdr *)o2->srcrt))
  341. return 1;
  342. return 0;
  343. }
  344. int ipv6_flowlabel_opt(struct sock *sk, char *optval, int optlen)
  345. {
  346. int err;
  347. struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
  348. struct in6_flowlabel_req freq;
  349. struct ipv6_fl_socklist *sfl1=NULL;
  350. struct ipv6_fl_socklist *sfl, **sflp;
  351. struct ip6_flowlabel *fl;
  352. if (optlen < sizeof(freq))
  353. return -EINVAL;
  354. if (copy_from_user(&freq, optval, sizeof(freq)))
  355. return -EFAULT;
  356. switch (freq.flr_action) {
  357. case IPV6_FL_A_PUT:
  358. write_lock_bh(&ip6_sk_fl_lock);
  359. for (sflp = &np->ipv6_fl_list; (sfl=*sflp)!=NULL; sflp = &sfl->next) {
  360. if (sfl->fl->label == freq.flr_label) {
  361. if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK))
  362. np->flow_label &= ~IPV6_FLOWLABEL_MASK;
  363. *sflp = sfl->next;
  364. write_unlock_bh(&ip6_sk_fl_lock);
  365. fl_release(sfl->fl);
  366. kfree(sfl);
  367. return 0;
  368. }
  369. }
  370. write_unlock_bh(&ip6_sk_fl_lock);
  371. return -ESRCH;
  372. case IPV6_FL_A_RENEW:
  373. read_lock_bh(&ip6_sk_fl_lock);
  374. for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) {
  375. if (sfl->fl->label == freq.flr_label) {
  376. err = fl6_renew(sfl->fl, freq.flr_linger, freq.flr_expires);
  377. read_unlock_bh(&ip6_sk_fl_lock);
  378. return err;
  379. }
  380. }
  381. read_unlock_bh(&ip6_sk_fl_lock);
  382. if (freq.flr_share == IPV6_FL_S_NONE && capable(CAP_NET_ADMIN)) {
  383. fl = fl_lookup(freq.flr_label);
  384. if (fl) {
  385. err = fl6_renew(fl, freq.flr_linger, freq.flr_expires);
  386. fl_release(fl);
  387. return err;
  388. }
  389. }
  390. return -ESRCH;
  391. case IPV6_FL_A_GET:
  392. if (freq.flr_label & ~IPV6_FLOWLABEL_MASK)
  393. return -EINVAL;
  394. fl = fl_create(&freq, optval, optlen, &err);
  395. if (fl == NULL)
  396. return err;
  397. sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL);
  398. if (freq.flr_label) {
  399. struct ip6_flowlabel *fl1 = NULL;
  400. err = -EEXIST;
  401. read_lock_bh(&ip6_sk_fl_lock);
  402. for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) {
  403. if (sfl->fl->label == freq.flr_label) {
  404. if (freq.flr_flags&IPV6_FL_F_EXCL) {
  405. read_unlock_bh(&ip6_sk_fl_lock);
  406. goto done;
  407. }
  408. fl1 = sfl->fl;
  409. atomic_inc(&fl->users);
  410. break;
  411. }
  412. }
  413. read_unlock_bh(&ip6_sk_fl_lock);
  414. if (fl1 == NULL)
  415. fl1 = fl_lookup(freq.flr_label);
  416. if (fl1) {
  417. err = -EEXIST;
  418. if (freq.flr_flags&IPV6_FL_F_EXCL)
  419. goto release;
  420. err = -EPERM;
  421. if (fl1->share == IPV6_FL_S_EXCL ||
  422.     fl1->share != fl->share ||
  423.     fl1->owner != fl->owner)
  424. goto release;
  425. err = -EINVAL;
  426. if (ipv6_addr_cmp(&fl1->dst, &fl->dst) ||
  427.     ipv6_opt_cmp(fl1->opt, fl->opt))
  428. goto release;
  429. err = -ENOMEM;
  430. if (sfl1 == NULL)
  431. goto release;
  432. if (fl->linger > fl1->linger)
  433. fl1->linger = fl->linger;
  434. if ((long)(fl->expires - fl1->expires) > 0)
  435. fl1->expires = fl->expires;
  436. write_lock_bh(&ip6_sk_fl_lock);
  437. sfl1->fl = fl1;
  438. sfl1->next = np->ipv6_fl_list;
  439. np->ipv6_fl_list = sfl1;
  440. write_unlock_bh(&ip6_sk_fl_lock);
  441. fl_free(fl);
  442. return 0;
  443. release:
  444. fl_release(fl1);
  445. goto done;
  446. }
  447. }
  448. err = -ENOENT;
  449. if (!(freq.flr_flags&IPV6_FL_F_CREATE))
  450. goto done;
  451. err = -ENOMEM;
  452. if (sfl1 == NULL || (err = mem_check(sk)) != 0)
  453. goto done;
  454. err = fl_intern(fl, freq.flr_label);
  455. if (err)
  456. goto done;
  457. /* Do not check for fault */
  458. if (!freq.flr_label)
  459. copy_to_user(optval + ((u8*)&freq.flr_label - (u8*)&freq), &fl->label, sizeof(fl->label));
  460. sfl1->fl = fl;
  461. sfl1->next = np->ipv6_fl_list;
  462. np->ipv6_fl_list = sfl1;
  463. return 0;
  464. default:
  465. return -EINVAL;
  466. }
  467. done:
  468. if (fl)
  469. fl_free(fl);
  470. if (sfl1)
  471. kfree(sfl1);
  472. return err;
  473. }
  474. #ifdef CONFIG_PROC_FS
  475. static int ip6_fl_read_proc(char *buffer, char **start, off_t offset,
  476.     int length, int *eof, void *data)
  477. {
  478. off_t pos=0;
  479. off_t begin=0;
  480. int len=0;
  481. int i, k;
  482. struct ip6_flowlabel *fl;
  483. len+= sprintf(buffer,"Label S Owner  Users  Linger Expires  "
  484.       "Dst                              Optn");
  485. read_lock_bh(&ip6_fl_lock);
  486. for (i=0; i<=FL_HASH_MASK; i++) {
  487. for (fl = fl_ht[i]; fl; fl = fl->next) {
  488. len+=sprintf(buffer+len,"%05X %-1d %-6d %-6d %-6d %-8ld ",
  489.      (unsigned)ntohl(fl->label),
  490.      fl->share,
  491.      (unsigned)fl->owner,
  492.      atomic_read(&fl->users),
  493.      fl->linger/HZ,
  494.      (long)(fl->expires - jiffies)/HZ);
  495. for (k=0; k<16; k++)
  496. len+=sprintf(buffer+len, "%02x", fl->dst.s6_addr[k]);
  497. buffer[len++]=' ';
  498. len+=sprintf(buffer+len, "%-4d", fl->opt ? fl->opt->opt_nflen : 0);
  499. buffer[len++]='n';
  500. pos=begin+len;
  501. if(pos<offset) {
  502. len=0;
  503. begin=pos;
  504. }
  505. if(pos>offset+length)
  506. goto done;
  507. }
  508. }
  509. *eof = 1;
  510. done:
  511. read_unlock_bh(&ip6_fl_lock);
  512. *start=buffer+(offset-begin);
  513. len-=(offset-begin);
  514. if(len>length)
  515. len=length;
  516. if(len<0)
  517. len=0;
  518. return len;
  519. }
  520. #endif
  521. void ip6_flowlabel_init()
  522. {
  523. init_timer(&ip6_fl_gc_timer);
  524. ip6_fl_gc_timer.function = ip6_fl_gc;
  525. #ifdef CONFIG_PROC_FS
  526. create_proc_read_entry("net/ip6_flowlabel", 0, 0, ip6_fl_read_proc, NULL);
  527. #endif
  528. }
  529. void ip6_flowlabel_cleanup()
  530. {
  531. del_timer(&ip6_fl_gc_timer);
  532. #ifdef CONFIG_PROC_FS
  533. remove_proc_entry("net/ip6_flowlabel", 0);
  534. #endif
  535. }