PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

lib/libc/net/rthdr.c

http://www.minix3.org/
C | 462 lines | 335 code | 80 blank | 47 comment | 59 complexity | 9787648b8c0ec0ae8b1101b46c762120 MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /* $NetBSD: rthdr.c,v 1.17 2009/02/05 23:22:39 lukem Exp $ */
  2. /*
  3. * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the project nor the names of its contributors
  15. * may be used to endorse or promote products derived from this software
  16. * without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
  22. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  24. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. */
  30. #include <sys/cdefs.h>
  31. #if defined(LIBC_SCCS) && !defined(lint)
  32. __RCSID("$NetBSD: rthdr.c,v 1.17 2009/02/05 23:22:39 lukem Exp $");
  33. #endif /* LIBC_SCCS and not lint */
  34. #include "namespace.h"
  35. #include <sys/param.h>
  36. #include <sys/types.h>
  37. #include <sys/socket.h>
  38. #include <netinet/in.h>
  39. #include <netinet/ip6.h>
  40. #include <assert.h>
  41. #include <string.h>
  42. #include <stdio.h>
  43. #ifdef __weak_alias
  44. __weak_alias(inet6_rthdr_add,_inet6_rthdr_add)
  45. __weak_alias(inet6_rthdr_getaddr,_inet6_rthdr_getaddr)
  46. __weak_alias(inet6_rthdr_getflags,_inet6_rthdr_getflags)
  47. __weak_alias(inet6_rthdr_init,_inet6_rthdr_init)
  48. __weak_alias(inet6_rthdr_lasthop,_inet6_rthdr_lasthop)
  49. __weak_alias(inet6_rthdr_segments,_inet6_rthdr_segments)
  50. __weak_alias(inet6_rthdr_space,_inet6_rthdr_space)
  51. __weak_alias(inet6_rth_space, _inet6_rth_space)
  52. __weak_alias(inet6_rth_init, _inet6_rth_init)
  53. __weak_alias(inet6_rth_add, _inet6_rth_add)
  54. __weak_alias(inet6_rth_reverse, _inet6_rth_reverse)
  55. __weak_alias(inet6_rth_segments, _inet6_rth_segments)
  56. __weak_alias(inet6_rth_getaddr, _inet6_rth_getaddr)
  57. #endif
  58. /*
  59. * RFC2292 API
  60. */
  61. size_t
  62. inet6_rthdr_space(type, seg)
  63. int type, seg;
  64. {
  65. switch (type) {
  66. case IPV6_RTHDR_TYPE_0:
  67. if (seg < 1 || seg > 23)
  68. return (0);
  69. return (CMSG_SPACE(sizeof(struct in6_addr) * seg +
  70. sizeof(struct ip6_rthdr0)));
  71. default:
  72. return (0);
  73. }
  74. }
  75. struct cmsghdr *
  76. inet6_rthdr_init(bp, type)
  77. void *bp;
  78. int type;
  79. {
  80. struct cmsghdr *ch;
  81. struct ip6_rthdr *rthdr;
  82. _DIAGASSERT(bp != NULL);
  83. ch = (struct cmsghdr *)bp;
  84. rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(ch);
  85. ch->cmsg_level = IPPROTO_IPV6;
  86. ch->cmsg_type = IPV6_RTHDR;
  87. switch (type) {
  88. case IPV6_RTHDR_TYPE_0:
  89. #ifdef COMPAT_RFC2292
  90. ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) -
  91. sizeof(struct in6_addr));
  92. #else
  93. ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0));
  94. #endif
  95. (void)memset(rthdr, 0, sizeof(struct ip6_rthdr0));
  96. rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
  97. return (ch);
  98. default:
  99. return (NULL);
  100. }
  101. }
  102. int
  103. inet6_rthdr_add(cmsg, addr, flags)
  104. struct cmsghdr *cmsg;
  105. const struct in6_addr *addr;
  106. u_int flags;
  107. {
  108. struct ip6_rthdr *rthdr;
  109. _DIAGASSERT(cmsg != NULL);
  110. _DIAGASSERT(addr != NULL);
  111. rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
  112. switch (rthdr->ip6r_type) {
  113. case IPV6_RTHDR_TYPE_0:
  114. {
  115. struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
  116. if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
  117. return (-1);
  118. if (rt0->ip6r0_segleft == 23)
  119. return (-1);
  120. if (flags != IPV6_RTHDR_LOOSE)
  121. return (-1);
  122. rt0->ip6r0_segleft++;
  123. (void)memcpy(((caddr_t)(void *)rt0) +
  124. ((rt0->ip6r0_len + 1) << 3), addr, sizeof(struct in6_addr));
  125. rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
  126. cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
  127. break;
  128. }
  129. default:
  130. return (-1);
  131. }
  132. return (0);
  133. }
  134. int
  135. inet6_rthdr_lasthop(cmsg, flags)
  136. struct cmsghdr *cmsg;
  137. unsigned int flags;
  138. {
  139. struct ip6_rthdr *rthdr;
  140. _DIAGASSERT(cmsg != NULL);
  141. rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
  142. switch (rthdr->ip6r_type) {
  143. case IPV6_RTHDR_TYPE_0:
  144. {
  145. struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
  146. if (rt0->ip6r0_segleft > 23)
  147. return (-1);
  148. if (flags != IPV6_RTHDR_LOOSE)
  149. return (-1);
  150. break;
  151. }
  152. default:
  153. return (-1);
  154. }
  155. return (0);
  156. }
  157. #if 0
  158. int
  159. inet6_rthdr_reverse(in, out)
  160. const struct cmsghdr *in;
  161. struct cmsghdr *out;
  162. {
  163. return (-1);
  164. }
  165. #endif
  166. int
  167. inet6_rthdr_segments(cmsg)
  168. const struct cmsghdr *cmsg;
  169. {
  170. const struct ip6_rthdr *rthdr;
  171. _DIAGASSERT(cmsg != NULL);
  172. rthdr = __UNCONST(CCMSG_DATA(cmsg));
  173. switch (rthdr->ip6r_type) {
  174. case IPV6_RTHDR_TYPE_0:
  175. {
  176. const struct ip6_rthdr0 *rt0 =
  177. (const struct ip6_rthdr0 *)(const void *)rthdr;
  178. if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
  179. return (-1);
  180. return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
  181. }
  182. default:
  183. return (-1);
  184. }
  185. }
  186. struct in6_addr *
  187. inet6_rthdr_getaddr(cmsg, idx)
  188. struct cmsghdr *cmsg;
  189. int idx;
  190. {
  191. struct ip6_rthdr *rthdr;
  192. _DIAGASSERT(cmsg != NULL);
  193. rthdr = (struct ip6_rthdr *)(void *)CMSG_DATA(cmsg);
  194. switch (rthdr->ip6r_type) {
  195. case IPV6_RTHDR_TYPE_0:
  196. {
  197. struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)(void *)rthdr;
  198. int naddr;
  199. if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
  200. return NULL;
  201. naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
  202. if (idx <= 0 || naddr < idx)
  203. return NULL;
  204. #ifdef COMPAT_RFC2292
  205. return ((struct in6_addr *)(void *)(rt0 + 1)) + idx - 1;
  206. #else
  207. return ((struct in6_addr *)(void *)(rt0 + 1)) + idx;
  208. #endif
  209. }
  210. default:
  211. return NULL;
  212. }
  213. }
  214. int
  215. inet6_rthdr_getflags(cmsg, idx)
  216. const struct cmsghdr *cmsg;
  217. int idx;
  218. {
  219. const struct ip6_rthdr *rthdr;
  220. _DIAGASSERT(cmsg != NULL);
  221. rthdr = __UNCONST(CCMSG_DATA(cmsg));
  222. switch (rthdr->ip6r_type) {
  223. case IPV6_RTHDR_TYPE_0:
  224. {
  225. const struct ip6_rthdr0 *rt0 = (const struct ip6_rthdr0 *)
  226. (const void *)rthdr;
  227. int naddr;
  228. if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
  229. return (-1);
  230. naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
  231. if (idx < 0 || naddr < idx)
  232. return (-1);
  233. return IPV6_RTHDR_LOOSE;
  234. }
  235. default:
  236. return (-1);
  237. }
  238. }
  239. /*
  240. * RFC3542 (2292bis) API
  241. */
  242. socklen_t
  243. inet6_rth_space(int type, int segments)
  244. {
  245. switch (type) {
  246. case IPV6_RTHDR_TYPE_0:
  247. return (((segments * 2) + 1) << 3);
  248. default:
  249. return (0); /* type not suppported */
  250. }
  251. }
  252. void *
  253. inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments)
  254. {
  255. struct ip6_rthdr *rth;
  256. struct ip6_rthdr0 *rth0;
  257. _DIAGASSERT(bp != NULL);
  258. rth = (struct ip6_rthdr *)bp;
  259. switch (type) {
  260. case IPV6_RTHDR_TYPE_0:
  261. /* length validation */
  262. if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments))
  263. return (NULL);
  264. memset(bp, 0, bp_len);
  265. rth0 = (struct ip6_rthdr0 *)(void *)rth;
  266. rth0->ip6r0_len = segments * 2;
  267. rth0->ip6r0_type = IPV6_RTHDR_TYPE_0;
  268. rth0->ip6r0_segleft = 0;
  269. rth0->ip6r0_reserved = 0;
  270. break;
  271. default:
  272. return (NULL); /* type not supported */
  273. }
  274. return (bp);
  275. }
  276. int
  277. inet6_rth_add(void *bp, const struct in6_addr *addr)
  278. {
  279. struct ip6_rthdr *rth;
  280. struct ip6_rthdr0 *rth0;
  281. struct in6_addr *nextaddr;
  282. _DIAGASSERT(bp != NULL);
  283. rth = (struct ip6_rthdr *)bp;
  284. switch (rth->ip6r_type) {
  285. case IPV6_RTHDR_TYPE_0:
  286. rth0 = (struct ip6_rthdr0 *)(void *)rth;
  287. nextaddr = (struct in6_addr *)(void *)(rth0 + 1)
  288. + rth0->ip6r0_segleft;
  289. *nextaddr = *addr;
  290. rth0->ip6r0_segleft++;
  291. break;
  292. default:
  293. return (-1); /* type not supported */
  294. }
  295. return (0);
  296. }
  297. int
  298. inet6_rth_reverse(const void *in, void *out)
  299. {
  300. const struct ip6_rthdr *rth_in;
  301. const struct ip6_rthdr0 *rth0_in;
  302. struct ip6_rthdr0 *rth0_out;
  303. int i, segments;
  304. _DIAGASSERT(in != NULL);
  305. _DIAGASSERT(out != NULL);
  306. rth_in = (const struct ip6_rthdr *)in;
  307. switch (rth_in->ip6r_type) {
  308. case IPV6_RTHDR_TYPE_0:
  309. rth0_in = (const struct ip6_rthdr0 *)in;
  310. rth0_out = (struct ip6_rthdr0 *)out;
  311. /* parameter validation XXX too paranoid? */
  312. if (rth0_in->ip6r0_len % 2)
  313. return (-1);
  314. segments = rth0_in->ip6r0_len / 2;
  315. /* we can't use memcpy here, since in and out may overlap */
  316. memmove((void *)rth0_out, (const void *)rth0_in,
  317. (unsigned int)(((rth0_in->ip6r0_len) + 1) << 3));
  318. rth0_out->ip6r0_segleft = segments;
  319. /* reverse the addresses */
  320. for (i = 0; i < segments / 2; i++) {
  321. struct in6_addr addr_tmp, *addr1, *addr2;
  322. addr1 = (struct in6_addr *)(void *)(rth0_out + 1) + i;
  323. addr2 = (struct in6_addr *)(void *)(rth0_out + 1) +
  324. (segments - i - 1);
  325. addr_tmp = *addr1;
  326. *addr1 = *addr2;
  327. *addr2 = addr_tmp;
  328. }
  329. break;
  330. default:
  331. return (-1); /* type not supported */
  332. }
  333. return (0);
  334. }
  335. int
  336. inet6_rth_segments(const void *bp)
  337. {
  338. const struct ip6_rthdr *rh;
  339. const struct ip6_rthdr0 *rh0;
  340. unsigned int addrs;
  341. _DIAGASSERT(bp != NULL);
  342. rh = (const struct ip6_rthdr *)bp;
  343. switch (rh->ip6r_type) {
  344. case IPV6_RTHDR_TYPE_0:
  345. rh0 = (const struct ip6_rthdr0 *)bp;
  346. /*
  347. * Validation for a type-0 routing header.
  348. * Is this too strict?
  349. */
  350. if ((rh0->ip6r0_len % 2) != 0 ||
  351. (addrs = (rh0->ip6r0_len / 2)) < rh0->ip6r0_segleft)
  352. return (-1);
  353. return (addrs);
  354. default:
  355. return (-1); /* unknown type */
  356. }
  357. }
  358. struct in6_addr *
  359. inet6_rth_getaddr(const void *bp, int idx)
  360. {
  361. const struct ip6_rthdr *rh;
  362. const struct ip6_rthdr0 *rh0;
  363. unsigned int addrs;
  364. _DIAGASSERT(bp != NULL);
  365. rh = (const struct ip6_rthdr *)bp;
  366. switch (rh->ip6r_type) {
  367. case IPV6_RTHDR_TYPE_0:
  368. rh0 = (const struct ip6_rthdr0 *)bp;
  369. /*
  370. * Validation for a type-0 routing header.
  371. * Is this too strict?
  372. */
  373. if ((rh0->ip6r0_len % 2) != 0 ||
  374. (addrs = (rh0->ip6r0_len / 2)) < rh0->ip6r0_segleft)
  375. return (NULL);
  376. if (idx < 0 || addrs <= (unsigned int)idx)
  377. return (NULL);
  378. return (((struct in6_addr *)(void *)__UNCONST(rh0 + 1)) + idx);
  379. default:
  380. return (NULL); /* unknown type */
  381. }
  382. }