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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * AX.25 release 037
  3.  *
  4.  * This code REQUIRES 2.1.15 or higher/ NET3.038
  5.  *
  6.  * This module:
  7.  * This module is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU General Public License
  9.  * as published by the Free Software Foundation; either version
  10.  * 2 of the License, or (at your option) any later version.
  11.  *
  12.  * Other kernels modules in this kit are generally BSD derived. See the copyright headers.
  13.  *
  14.  *
  15.  * History
  16.  * AX.25 020 Jonathan(G4KLX) First go.
  17.  * AX.25 022 Jonathan(G4KLX) Added the actual meat to this - we now have a nice heard list.
  18.  * AX.25 025 Alan(GW4PTS) First cut at autobinding by route scan.
  19.  * AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the
  20.  * sock structure. Device removal now
  21.  * removes the heard structure.
  22.  * AX.25 029 Steven(GW7RRM) Added /proc information for uid/callsign mapping.
  23.  * Jonathan(G4KLX) Handling of IP mode in the routing list and /proc entry.
  24.  * AX.25 030 Jonathan(G4KLX) Added digi-peaters to routing table, and
  25.  * ioctls to manipulate them. Added port
  26.  * configuration.
  27.  * AX.25 031 Jonathan(G4KLX) Added concept of default route.
  28.  * Joerg(DL1BKE) ax25_rt_build_path() find digipeater list and device by 
  29.  * destination call. Needed for IP routing via digipeater
  30.  * Jonathan(G4KLX) Added routing for IP datagram packets.
  31.  * Joerg(DL1BKE) Changed routing for IP datagram and VC to use a default
  32.  * route if available. Does not overwrite default routes
  33.  * on route-table overflow anymore.
  34.  * Joerg(DL1BKE) Fixed AX.25 routing of IP datagram and VC, new ioctl()
  35.  * "SIOCAX25OPTRT" to set IP mode and a 'permanent' flag
  36.  * on routes.
  37.  * AX.25 033 Jonathan(G4KLX) Remove auto-router.
  38.  * Joerg(DL1BKE) Moved BPQ Ethernet driver to separate device.
  39.  * AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
  40.  * Jonathan(G4KLX) Support for packet forwarding.
  41.  * Arnaldo C. Melo s/suser/capable/
  42.  */
  43. #include <linux/errno.h>
  44. #include <linux/types.h>
  45. #include <linux/socket.h>
  46. #include <linux/in.h>
  47. #include <linux/kernel.h>
  48. #include <linux/sched.h>
  49. #include <linux/timer.h>
  50. #include <linux/string.h>
  51. #include <linux/sockios.h>
  52. #include <linux/net.h>
  53. #include <net/ax25.h>
  54. #include <linux/inet.h>
  55. #include <linux/netdevice.h>
  56. #include <linux/if_arp.h>
  57. #include <linux/skbuff.h>
  58. #include <net/sock.h>
  59. #include <asm/uaccess.h>
  60. #include <asm/system.h>
  61. #include <linux/fcntl.h>
  62. #include <linux/mm.h>
  63. #include <linux/interrupt.h>
  64. #include <linux/init.h>
  65. static ax25_route *ax25_route_list;
  66. static ax25_route *ax25_find_route(ax25_address *, struct net_device *);
  67. /*
  68.  * small macro to drop non-digipeated digipeaters and reverse path
  69.  */
  70. static inline void ax25_route_invert(ax25_digi *in, ax25_digi *out)
  71. {
  72. int k;
  73. for (k = 0; k < in->ndigi; k++)
  74. if (!in->repeated[k])
  75. break;
  76. in->ndigi = k;
  77. ax25_digi_invert(in, out);
  78. }
  79. void ax25_rt_device_down(struct net_device *dev)
  80. {
  81. ax25_route *s, *t, *ax25_rt = ax25_route_list;
  82. while (ax25_rt != NULL) {
  83. s       = ax25_rt;
  84. ax25_rt = ax25_rt->next;
  85. if (s->dev == dev) {
  86. if (ax25_route_list == s) {
  87. ax25_route_list = s->next;
  88. if (s->digipeat != NULL)
  89. kfree(s->digipeat);
  90. kfree(s);
  91. } else {
  92. for (t = ax25_route_list; t != NULL; t = t->next) {
  93. if (t->next == s) {
  94. t->next = s->next;
  95. if (s->digipeat != NULL)
  96. kfree(s->digipeat);
  97. kfree(s);
  98. break;
  99. }
  100. }
  101. }
  102. }
  103. }
  104. }
  105. int ax25_rt_ioctl(unsigned int cmd, void *arg)
  106. {
  107. unsigned long flags;
  108. ax25_route *s, *t, *ax25_rt;
  109. struct ax25_routes_struct route;
  110. struct ax25_route_opt_struct rt_option;
  111. ax25_dev *ax25_dev;
  112. int i;
  113. switch (cmd) {
  114. case SIOCADDRT:
  115. if (copy_from_user(&route, arg, sizeof(route)))
  116. return -EFAULT;
  117. if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
  118. return -EINVAL;
  119. if (route.digi_count > AX25_MAX_DIGIS)
  120. return -EINVAL;
  121. for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
  122. if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == ax25_dev->dev) {
  123. if (ax25_rt->digipeat != NULL) {
  124. kfree(ax25_rt->digipeat);
  125. ax25_rt->digipeat = NULL;
  126. }
  127. if (route.digi_count != 0) {
  128. if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
  129. return -ENOMEM;
  130. ax25_rt->digipeat->lastrepeat = -1;
  131. ax25_rt->digipeat->ndigi      = route.digi_count;
  132. for (i = 0; i < route.digi_count; i++) {
  133. ax25_rt->digipeat->repeated[i] = 0;
  134. ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
  135. }
  136. }
  137. return 0;
  138. }
  139. }
  140. if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL)
  141. return -ENOMEM;
  142. ax25_rt->callsign     = route.dest_addr;
  143. ax25_rt->dev          = ax25_dev->dev;
  144. ax25_rt->digipeat     = NULL;
  145. ax25_rt->ip_mode      = ' ';
  146. if (route.digi_count != 0) {
  147. if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
  148. kfree(ax25_rt);
  149. return -ENOMEM;
  150. }
  151. ax25_rt->digipeat->lastrepeat = -1;
  152. ax25_rt->digipeat->ndigi      = route.digi_count;
  153. for (i = 0; i < route.digi_count; i++) {
  154. ax25_rt->digipeat->repeated[i] = 0;
  155. ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
  156. }
  157. }
  158. save_flags(flags); cli();
  159. ax25_rt->next   = ax25_route_list;
  160. ax25_route_list = ax25_rt;
  161. restore_flags(flags);
  162. break;
  163. case SIOCDELRT:
  164. if (copy_from_user(&route, arg, sizeof(route)))
  165. return -EFAULT;
  166. if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
  167. return -EINVAL;
  168. ax25_rt = ax25_route_list;
  169. while (ax25_rt != NULL) {
  170. s       = ax25_rt;
  171. ax25_rt = ax25_rt->next;
  172. if (s->dev == ax25_dev->dev && ax25cmp(&route.dest_addr, &s->callsign) == 0) {
  173. if (ax25_route_list == s) {
  174. ax25_route_list = s->next;
  175. if (s->digipeat != NULL)
  176. kfree(s->digipeat);
  177. kfree(s);
  178. } else {
  179. for (t = ax25_route_list; t != NULL; t = t->next) {
  180. if (t->next == s) {
  181. t->next = s->next;
  182. if (s->digipeat != NULL)
  183. kfree(s->digipeat);
  184. kfree(s);
  185. break;
  186. }
  187. }
  188. }
  189. }
  190. }
  191. break;
  192. case SIOCAX25OPTRT:
  193. if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
  194. return -EFAULT;
  195. if ((ax25_dev = ax25_addr_ax25dev(&rt_option.port_addr)) == NULL)
  196. return -EINVAL;
  197. for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
  198. if (ax25_rt->dev == ax25_dev->dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) {
  199. switch (rt_option.cmd) {
  200. case AX25_SET_RT_IPMODE:
  201. switch (rt_option.arg) {
  202. case ' ':
  203. case 'D':
  204. case 'V':
  205. ax25_rt->ip_mode = rt_option.arg;
  206. break;
  207. default:
  208. return -EINVAL;
  209. }
  210. break;
  211. default:
  212. return -EINVAL;
  213. }
  214. }
  215. }
  216. break;
  217. default:
  218. return -EINVAL;
  219. }
  220. return 0;
  221. }
  222. int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
  223. {
  224. ax25_route *ax25_rt;
  225. int len     = 0;
  226. off_t pos   = 0;
  227. off_t begin = 0;
  228. char *callsign;
  229. int i;
  230.   
  231. cli();
  232. len += sprintf(buffer, "callsign  dev  mode digipeatersn");
  233. for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
  234. if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0)
  235. callsign = "default";
  236. else
  237. callsign = ax2asc(&ax25_rt->callsign);
  238. len += sprintf(buffer + len, "%-9s %-4s",
  239. callsign,
  240. ax25_rt->dev ? ax25_rt->dev->name : "???");
  241. switch (ax25_rt->ip_mode) {
  242. case 'V':
  243. len += sprintf(buffer + len, "   vc");
  244. break;
  245. case 'D':
  246. len += sprintf(buffer + len, "   dg");
  247. break;
  248. default:
  249. len += sprintf(buffer + len, "    *");
  250. break;
  251. }
  252. if (ax25_rt->digipeat != NULL)
  253. for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
  254. len += sprintf(buffer + len, " %s", ax2asc(&ax25_rt->digipeat->calls[i]));
  255. len += sprintf(buffer + len, "n");
  256. pos = begin + len;
  257. if (pos < offset) {
  258. len   = 0;
  259. begin = pos;
  260. }
  261. if (pos > offset + length)
  262. break;
  263. }
  264. sti();
  265. *start = buffer + (offset - begin);
  266. len   -= (offset - begin);
  267. if (len > length) len = length;
  268. return len;
  269. /*
  270.  * Find AX.25 route
  271.  */
  272. static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev)
  273. {
  274. ax25_route *ax25_spe_rt = NULL;
  275. ax25_route *ax25_def_rt = NULL;
  276. ax25_route *ax25_rt;
  277. /*
  278.  * Bind to the physical interface we heard them on, or the default
  279.  * route if none is found;
  280.  */
  281. for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
  282. if (dev == NULL) {
  283. if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL)
  284. ax25_spe_rt = ax25_rt;
  285. if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL)
  286. ax25_def_rt = ax25_rt;
  287. } else {
  288. if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev)
  289. ax25_spe_rt = ax25_rt;
  290. if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev == dev)
  291. ax25_def_rt = ax25_rt;
  292. }
  293. }
  294. if (ax25_spe_rt != NULL)
  295. return ax25_spe_rt;
  296. return ax25_def_rt;
  297. }
  298. /*
  299.  * Adjust path: If you specify a default route and want to connect
  300.  *      a target on the digipeater path but w/o having a special route
  301.  * set before, the path has to be truncated from your target on.
  302.  */
  303. static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
  304. {
  305. int k;
  306. for (k = 0; k < digipeat->ndigi; k++) {
  307. if (ax25cmp(addr, &digipeat->calls[k]) == 0)
  308. break;
  309. }
  310. digipeat->ndigi = k;
  311. }
  312.  
  313. /*
  314.  * Find which interface to use.
  315.  */
  316. int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
  317. {
  318. ax25_route *ax25_rt;
  319. ax25_address *call;
  320. if ((ax25_rt = ax25_find_route(addr, NULL)) == NULL)
  321. return -EHOSTUNREACH;
  322. if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL)
  323. return -EHOSTUNREACH;
  324. if ((call = ax25_findbyuid(current->euid)) == NULL) {
  325. if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE))
  326. return -EPERM;
  327. call = (ax25_address *)ax25->ax25_dev->dev->dev_addr;
  328. }
  329. ax25->source_addr = *call;
  330. if (ax25_rt->digipeat != NULL) {
  331. if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
  332. return -ENOMEM;
  333. memcpy(ax25->digipeat, ax25_rt->digipeat, sizeof(ax25_digi));
  334. ax25_adjust_path(addr, ax25->digipeat);
  335. }
  336. if (ax25->sk != NULL)
  337. ax25->sk->zapped = 0;
  338. return 0;
  339. }
  340. /*
  341.  * dl1bke 960117: build digipeater path
  342.  * dl1bke 960301: use the default route if it exists
  343.  */
  344. ax25_route *ax25_rt_find_route(ax25_address *addr, struct net_device *dev)
  345. {
  346. static ax25_route route;
  347. ax25_route *ax25_rt;
  348. if ((ax25_rt = ax25_find_route(addr, dev)) == NULL) {
  349. route.next     = NULL;
  350. route.callsign = *addr;
  351. route.dev      = dev;
  352. route.digipeat = NULL;
  353. route.ip_mode  = ' ';
  354. return &route;
  355. }
  356. return ax25_rt;
  357. }
  358. struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, ax25_address *dest, ax25_digi *digi)
  359. {
  360. struct sk_buff *skbn;
  361. unsigned char *bp;
  362. int len;
  363. len = digi->ndigi * AX25_ADDR_LEN;
  364. if (skb_headroom(skb) < len) {
  365. if ((skbn = skb_realloc_headroom(skb, len)) == NULL) {
  366. printk(KERN_CRIT "AX.25: ax25_dg_build_path - out of memoryn");
  367. return NULL;
  368. }
  369. if (skb->sk != NULL)
  370. skb_set_owner_w(skbn, skb->sk);
  371. kfree_skb(skb);
  372. skb = skbn;
  373. }
  374. bp = skb_push(skb, len);
  375. ax25_addr_build(bp, src, dest, digi, AX25_COMMAND, AX25_MODULUS);
  376. return skb;
  377. }
  378. /*
  379.  * Free all memory associated with routing structures.
  380.  */
  381. void __exit ax25_rt_free(void)
  382. {
  383. ax25_route *s, *ax25_rt = ax25_route_list;
  384. while (ax25_rt != NULL) {
  385. s       = ax25_rt;
  386. ax25_rt = ax25_rt->next;
  387. if (s->digipeat != NULL)
  388. kfree(s->digipeat);
  389. kfree(s);
  390. }
  391. }