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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * DECnet       An implementation of the DECnet protocol suite for the LINUX
  3.  *              operating system.  DECnet is implemented using the  BSD Socket
  4.  *              interface as the means of communication with the user level.
  5.  *
  6.  *              DECnet Routing Forwarding Information Base (Rules)
  7.  *
  8.  * Author:      Steve Whitehouse <SteveW@ACM.org>
  9.  *              Mostly copied from Alexey Kuznetsov's ipv4/fib_rules.c
  10.  *
  11.  *
  12.  * Changes:
  13.  *
  14.  */
  15. #include <linux/config.h>
  16. #include <linux/string.h>
  17. #include <linux/net.h>
  18. #include <linux/socket.h>
  19. #include <linux/sockios.h>
  20. #include <linux/init.h>
  21. #include <linux/skbuff.h>
  22. #include <linux/netlink.h>
  23. #include <linux/rtnetlink.h>
  24. #include <linux/proc_fs.h>
  25. #include <linux/netdevice.h>
  26. #include <linux/timer.h>
  27. #include <linux/spinlock.h>
  28. #include <asm/atomic.h>
  29. #include <asm/uaccess.h>
  30. #include <net/neighbour.h>
  31. #include <net/dst.h>
  32. #include <net/dn.h>
  33. #include <net/dn_fib.h>
  34. #include <net/dn_neigh.h>
  35. #include <net/dn_dev.h>
  36. struct dn_fib_rule
  37. {
  38. struct dn_fib_rule *r_next;
  39. atomic_t r_clntref;
  40. u32 r_preference;
  41. unsigned char r_table;
  42. unsigned char r_action;
  43. unsigned char r_dst_len;
  44. unsigned char r_src_len;
  45. dn_address r_src;
  46. dn_address r_srcmask;
  47. dn_address r_dst;
  48. dn_address r_dstmask;
  49. u8 r_flags;
  50. #ifdef CONFIG_DECNET_ROUTE_FWMARK
  51. u32 r_fwmark;
  52. #endif
  53. int r_ifindex;
  54. char r_ifname[IFNAMSIZ];
  55. int r_dead;
  56. };
  57. static struct dn_fib_rule default_rule = {
  58. r_clntref: ATOMIC_INIT(2),
  59. r_preference: 0x7fff,
  60. r_table: DN_DEFAULT_TABLE,
  61. r_action: RTN_UNICAST
  62. };
  63. static struct dn_fib_rule *dn_fib_rules = &default_rule;
  64. static rwlock_t dn_fib_rules_lock = RW_LOCK_UNLOCKED;
  65. int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
  66. {
  67. struct rtattr **rta = arg;
  68. struct rtmsg *rtm = NLMSG_DATA(nlh);
  69. struct dn_fib_rule *r, **rp;
  70. int err = -ESRCH;
  71. for(rp=&dn_fib_rules; (r=*rp) != NULL; rp = &r->r_next) {
  72. if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 2) == 0) &&
  73. rtm->rtm_src_len == r->r_src_len &&
  74. rtm->rtm_dst_len == r->r_dst_len &&
  75. (!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 2) == 0) &&
  76. #ifdef CONFIG_DECNET_ROUTE_FWMARK
  77. (!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) &&
  78. #endif
  79. (!rtm->rtm_type || rtm->rtm_type == r->r_action) &&
  80. (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) &&
  81. (!rta[RTA_IIF-1] || strcmp(RTA_DATA(rta[RTA_IIF-1]), r->r_ifname) == 0) &&
  82. (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) {
  83. err = -EPERM;
  84. if (r == &default_rule)
  85. break;
  86. write_lock_bh(&dn_fib_rules_lock);
  87. *rp = r->r_next;
  88. r->r_dead = 1;
  89. write_unlock_bh(&dn_fib_rules_lock);
  90. dn_fib_rule_put(r);
  91. err = 0;
  92. break;
  93. }
  94. }
  95. return err;
  96. }
  97. void dn_fib_rule_put(struct dn_fib_rule *r)
  98. {
  99. if (atomic_dec_and_test(&r->r_clntref)) {
  100. if (r->r_dead)
  101. kfree(r);
  102. else
  103. printk(KERN_DEBUG "Attempt to free alive dn_fib_rulen");
  104. }
  105. }
  106. int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
  107. {
  108. struct rtattr **rta = arg;
  109. struct rtmsg *rtm = NLMSG_DATA(nlh);
  110. struct dn_fib_rule *r, *new_r, **rp;
  111. unsigned char table_id;
  112. if (rtm->rtm_src_len > 16 || rtm->rtm_dst_len > 16)
  113. return -EINVAL;
  114. if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ)
  115. return -EINVAL;
  116. if (rtm->rtm_type == RTN_NAT)
  117. return -EINVAL;
  118. table_id = rtm->rtm_table;
  119. if (table_id == RT_TABLE_UNSPEC) {
  120. struct dn_fib_table *tb;
  121. if (rtm->rtm_type == RTN_UNICAST) {
  122. if ((tb = dn_fib_empty_table()) == NULL)
  123. return -ENOBUFS;
  124. table_id = tb->n;
  125. }
  126. }
  127. new_r = kmalloc(sizeof(*new_r), GFP_KERNEL);
  128. if (!new_r)
  129. return -ENOMEM;
  130. memset(new_r, 0, sizeof(*new_r));
  131. if (rta[RTA_SRC-1])
  132. memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2);
  133. if (rta[RTA_DST-1])
  134. memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 2);
  135. new_r->r_src_len = rtm->rtm_src_len;
  136. new_r->r_dst_len = rtm->rtm_dst_len;
  137. new_r->r_srcmask = dnet_make_mask(rtm->rtm_src_len);
  138. new_r->r_dstmask = dnet_make_mask(rtm->rtm_dst_len);
  139. #ifdef CONFIG_DECNET_ROUTE_FWMARK
  140. if (rta[RTA_PROTOINFO-1])
  141. memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4);
  142. #endif
  143. new_r->r_action = rtm->rtm_type;
  144. new_r->r_flags = rtm->rtm_flags;
  145. if (rta[RTA_PRIORITY-1])
  146. memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4);
  147. new_r->r_table = table_id;
  148. if (rta[RTA_IIF-1]) {
  149. struct net_device *dev;
  150. memcpy(new_r->r_ifname, RTA_DATA(rta[RTA_IIF-1]), IFNAMSIZ);
  151. new_r->r_ifname[IFNAMSIZ-1] = 0;
  152. new_r->r_ifindex = -1;
  153. dev = __dev_get_by_name(new_r->r_ifname);
  154. if (dev)
  155. new_r->r_ifindex = dev->ifindex;
  156. }
  157. rp = &dn_fib_rules;
  158. if (!new_r->r_preference) {
  159. r = dn_fib_rules;
  160. if (r && (r = r->r_next) != NULL) {
  161. rp = &dn_fib_rules->r_next;
  162. if (r->r_preference)
  163. new_r->r_preference = r->r_preference - 1;
  164. }
  165. }
  166. while((r=*rp) != NULL) {
  167. if (r->r_preference > new_r->r_preference)
  168. break;
  169. rp = &r->r_next;
  170. }
  171. new_r->r_next = r;
  172. atomic_inc(&new_r->r_clntref);
  173. write_lock_bh(&dn_fib_rules_lock);
  174. *rp = new_r;
  175. write_unlock_bh(&dn_fib_rules_lock);
  176. return 0;
  177. }
  178. int dn_fib_lookup(struct dn_fib_key *key, struct dn_fib_res *res)
  179. {
  180. struct dn_fib_rule *r, *policy;
  181. struct dn_fib_table *tb;
  182. dn_address saddr = key->src;
  183. dn_address daddr = key->dst;
  184. int err;
  185. read_lock(&dn_fib_rules_lock);
  186. for(r = dn_fib_rules; r; r = r->r_next) {
  187. if (((saddr^r->r_src) & r->r_srcmask) ||
  188.     ((daddr^r->r_dst) & r->r_dstmask) ||
  189. #ifdef CONFIG_DECNET_ROUTE_FWMARK
  190.     (r->r_fwmark && r->r_fwmark != key->fwmark) ||
  191. #endif
  192.     (r->r_ifindex && r->r_ifindex != key->iif))
  193. continue;
  194. switch(r->r_action) {
  195. case RTN_UNICAST:
  196. policy = r;
  197. break;
  198. case RTN_UNREACHABLE:
  199. read_unlock(&dn_fib_rules_lock);
  200. return -ENETUNREACH;
  201. default:
  202. case RTN_BLACKHOLE:
  203. read_unlock(&dn_fib_rules_lock);
  204. return -EINVAL;
  205. case RTN_PROHIBIT:
  206. read_unlock(&dn_fib_rules_lock);
  207. return -EACCES;
  208. }
  209. if ((tb = dn_fib_get_table(r->r_table, 0)) == NULL)
  210. continue;
  211. err = tb->lookup(tb, key, res);
  212. if (err == 0) {
  213. res->r = policy;
  214. if (policy)
  215. atomic_inc(&policy->r_clntref);
  216. read_unlock(&dn_fib_rules_lock);
  217. return 0;
  218. }
  219. if (err < 0 && err != -EAGAIN) {
  220. read_unlock(&dn_fib_rules_lock);
  221. return err;
  222. }
  223. }
  224. read_unlock(&dn_fib_rules_lock);
  225. return -ESRCH;
  226. }
  227. static void dn_fib_rules_detach(struct net_device *dev)
  228. {
  229. struct dn_fib_rule *r;
  230. for(r = dn_fib_rules; r; r = r->r_next) {
  231. if (r->r_ifindex == dev->ifindex) {
  232. write_lock_bh(&dn_fib_rules_lock);
  233. r->r_ifindex = -1;
  234. write_unlock_bh(&dn_fib_rules_lock);
  235. }
  236. }
  237. }
  238. static void dn_fib_rules_attach(struct net_device *dev)
  239. {
  240. struct dn_fib_rule *r;
  241. for(r = dn_fib_rules; r; r = r->r_next) {
  242. if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) {
  243. write_lock_bh(&dn_fib_rules_lock);
  244. r->r_ifindex = dev->ifindex;
  245. write_unlock_bh(&dn_fib_rules_lock);
  246. }
  247. }
  248. }
  249. static int dn_fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr)
  250. {
  251. struct net_device *dev = ptr;
  252. switch(event) {
  253. case NETDEV_UNREGISTER:
  254. dn_fib_rules_detach(dev);
  255. dn_fib_sync_down(0, dev, 1);
  256. case NETDEV_REGISTER:
  257. dn_fib_rules_attach(dev);
  258. dn_fib_sync_up(dev);
  259. }
  260. return NOTIFY_DONE;
  261. }
  262. static struct notifier_block dn_fib_rules_notifier = {
  263. notifier_call: dn_fib_rules_event,
  264. };
  265. static int dn_fib_fill_rule(struct sk_buff *skb, struct dn_fib_rule *r, struct netlink_callback *cb)
  266. {
  267. struct rtmsg *rtm;
  268. struct nlmsghdr *nlh;
  269. unsigned char *b = skb->tail;
  270. nlh = NLMSG_PUT(skb, NETLINK_CREDS(cb->skb)->pid, cb->nlh->nlmsg_seq, RTM_NEWRULE, sizeof(*rtm));
  271. rtm = NLMSG_DATA(nlh);
  272. rtm->rtm_family = AF_DECnet;
  273. rtm->rtm_dst_len = r->r_dst_len;
  274. rtm->rtm_src_len = r->r_src_len;
  275. rtm->rtm_tos = 0;
  276. #ifdef CONFIG_DECNET_ROUTE_FWMARK
  277. if (r->r_fwmark)
  278. RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark);
  279. #endif
  280. rtm->rtm_table = r->r_table;
  281. rtm->rtm_protocol = 0;
  282. rtm->rtm_scope = 0;
  283. rtm->rtm_type = r->r_action;
  284. rtm->rtm_flags = r->r_flags;
  285. if (r->r_dst_len)
  286. RTA_PUT(skb, RTA_DST, 2, &r->r_dst);
  287. if (r->r_src_len)
  288. RTA_PUT(skb, RTA_SRC, 2, &r->r_src);
  289. if (r->r_ifname[0])
  290. RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname);
  291. if (r->r_preference)
  292. RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference);
  293. nlh->nlmsg_len = skb->tail - b;
  294. return skb->len;
  295. nlmsg_failure:
  296. rtattr_failure:
  297. skb_put(skb, b - skb->tail);
  298. return -1;
  299. }
  300. int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
  301. {
  302. int idx;
  303. int s_idx = cb->args[0];
  304. struct dn_fib_rule *r;
  305. read_lock(&dn_fib_rules_lock);
  306. for(r = dn_fib_rules, idx = 0; r; r = r->r_next, idx++) {
  307. if (idx < s_idx)
  308. continue;
  309. if (dn_fib_fill_rule(skb, r, cb) < 0)
  310. break;
  311. }
  312. read_unlock(&dn_fib_rules_lock);
  313. cb->args[0] = idx;
  314. return skb->len;
  315. }
  316. void __init dn_fib_rules_init(void)
  317. {
  318. register_netdevice_notifier(&dn_fib_rules_notifier);
  319. }
  320. void __exit dn_fib_rules_cleanup(void)
  321. {
  322. unregister_netdevice_notifier(&dn_fib_rules_notifier);
  323. }