PageRenderTime 81ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

sys/lib/libsa/bootparam.c

http://www.minix3.org/
C | 439 lines | 256 code | 66 blank | 117 comment | 17 complexity | c684d695ce7ed911c10db023b1caf1fa MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /* $NetBSD: bootparam.c,v 1.19 2009/10/21 23:12:10 snj Exp $ */
  2. /*
  3. * Copyright (c) 1995 Gordon W. Ross
  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. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. /*
  27. * RPC/bootparams
  28. */
  29. #include <sys/param.h>
  30. #include <sys/socket.h>
  31. #include <net/if.h>
  32. #include <netinet/in.h>
  33. #include <netinet/in_systm.h>
  34. #ifdef _STANDALONE
  35. #include <lib/libkern/libkern.h>
  36. #else
  37. #include <string.h>
  38. #endif
  39. #include "rpcv2.h"
  40. #include "stand.h"
  41. #include "net.h"
  42. #include "rpc.h"
  43. #include "bootparam.h"
  44. #ifdef DEBUG_RPC
  45. #define RPC_PRINTF(a) printf a
  46. #else
  47. #define RPC_PRINTF(a)
  48. #endif
  49. struct in_addr bp_server_addr; /* net order */
  50. n_short bp_server_port; /* net order */
  51. int hostnamelen;
  52. char domainname[FNAME_SIZE]; /* our DNS domain */
  53. int domainnamelen;
  54. /*
  55. * RPC definitions for bootparamd
  56. */
  57. #define BOOTPARAM_PROG 100026
  58. #define BOOTPARAM_VERS 1
  59. #define BOOTPARAM_WHOAMI 1
  60. #define BOOTPARAM_GETFILE 2
  61. /*
  62. * Inet address in RPC messages
  63. * (Note, really four ints, NOT chars. Blech.)
  64. */
  65. struct xdr_inaddr {
  66. u_int32_t atype;
  67. int32_t addr[4];
  68. };
  69. int xdr_inaddr_encode(char **, struct in_addr);
  70. int xdr_inaddr_decode(char **, struct in_addr *);
  71. int xdr_string_encode(char **, char *, int);
  72. int xdr_string_decode(char **, char *, int *);
  73. /*
  74. * RPC: bootparam/whoami
  75. * Given client IP address, get:
  76. * client name (hostname)
  77. * domain name (domainname)
  78. * gateway address
  79. *
  80. * The hostname and domainname are set here for convenience.
  81. *
  82. * Note - bpsin is initialized to the broadcast address,
  83. * and will be replaced with the bootparam server address
  84. * after this call is complete. Have to use PMAP_PROC_CALL
  85. * to make sure we get responses only from a servers that
  86. * know about us (don't want to broadcast a getport call).
  87. */
  88. int
  89. bp_whoami(int sockfd)
  90. {
  91. /* RPC structures for PMAPPROC_CALLIT */
  92. struct args {
  93. u_int32_t prog;
  94. u_int32_t vers;
  95. u_int32_t proc;
  96. u_int32_t arglen;
  97. struct xdr_inaddr xina;
  98. } *args;
  99. struct repl {
  100. u_int16_t _pad;
  101. u_int16_t port;
  102. u_int32_t encap_len;
  103. /* encapsulated data here */
  104. n_long capsule[64];
  105. } *repl;
  106. struct {
  107. n_long h[RPC_HEADER_WORDS];
  108. struct args d;
  109. } sdata;
  110. struct {
  111. n_long h[RPC_HEADER_WORDS];
  112. struct repl d;
  113. } rdata;
  114. char *send_tail, *recv_head;
  115. struct iodesc *d;
  116. int len, x;
  117. RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip)));
  118. if (!(d = socktodesc(sockfd))) {
  119. RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd));
  120. return -1;
  121. }
  122. args = &sdata.d;
  123. repl = &rdata.d;
  124. /*
  125. * Build request args for PMAPPROC_CALLIT.
  126. */
  127. args->prog = htonl(BOOTPARAM_PROG);
  128. args->vers = htonl(BOOTPARAM_VERS);
  129. args->proc = htonl(BOOTPARAM_WHOAMI);
  130. args->arglen = htonl(sizeof(struct xdr_inaddr));
  131. send_tail = (char *)&args->xina;
  132. /*
  133. * append encapsulated data (client IP address)
  134. */
  135. if (xdr_inaddr_encode(&send_tail, myip))
  136. return -1;
  137. /* RPC: portmap/callit */
  138. d->myport = htons(--rpc_port);
  139. d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */
  140. /* rpc_call will set d->destport */
  141. len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
  142. args, send_tail - (char *)args,
  143. repl, sizeof(*repl));
  144. if (len < 8) {
  145. printf("bootparamd: 'whoami' call failed\n");
  146. return -1;
  147. }
  148. /* Save bootparam server address (from IP header). */
  149. rpc_fromaddr(repl, &bp_server_addr, &bp_server_port);
  150. /*
  151. * Note that bp_server_port is now 111 due to the
  152. * indirect call (using PMAPPROC_CALLIT), so get the
  153. * actual port number from the reply data.
  154. */
  155. bp_server_port = repl->port;
  156. RPC_PRINTF(("bp_whoami: server at %s:%d\n",
  157. inet_ntoa(bp_server_addr), ntohs(bp_server_port)));
  158. /* We have just done a portmap call, so cache the portnum. */
  159. rpc_pmap_putcache(bp_server_addr,
  160. BOOTPARAM_PROG,
  161. BOOTPARAM_VERS,
  162. (int)ntohs(bp_server_port));
  163. /*
  164. * Parse the encapsulated results from bootparam/whoami
  165. */
  166. x = ntohl(repl->encap_len);
  167. if (len < x) {
  168. printf("bp_whoami: short reply, %d < %d\n", len, x);
  169. return -1;
  170. }
  171. recv_head = (char *)repl->capsule;
  172. /* client name */
  173. hostnamelen = MAXHOSTNAMELEN-1;
  174. if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
  175. RPC_PRINTF(("bp_whoami: bad hostname\n"));
  176. return -1;
  177. }
  178. /* domain name */
  179. domainnamelen = MAXHOSTNAMELEN-1;
  180. if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
  181. RPC_PRINTF(("bp_whoami: bad domainname\n"));
  182. return -1;
  183. }
  184. /* gateway address */
  185. if (xdr_inaddr_decode(&recv_head, &gateip)) {
  186. RPC_PRINTF(("bp_whoami: bad gateway\n"));
  187. return -1;
  188. }
  189. /* success */
  190. return 0;
  191. }
  192. /*
  193. * RPC: bootparam/getfile
  194. * Given client name and file "key", get:
  195. * server name
  196. * server IP address
  197. * server pathname
  198. */
  199. int
  200. bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname)
  201. {
  202. struct {
  203. n_long h[RPC_HEADER_WORDS];
  204. n_long d[64];
  205. } sdata;
  206. struct {
  207. n_long h[RPC_HEADER_WORDS];
  208. n_long d[128];
  209. } rdata;
  210. char serv_name[FNAME_SIZE];
  211. char *send_tail, *recv_head;
  212. /* misc... */
  213. struct iodesc *d;
  214. int sn_len, path_len, rlen;
  215. if (!(d = socktodesc(sockfd))) {
  216. RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd));
  217. return -1;
  218. }
  219. send_tail = (char *)sdata.d;
  220. recv_head = (char *)rdata.d;
  221. /*
  222. * Build request message.
  223. */
  224. /* client name (hostname) */
  225. if (xdr_string_encode(&send_tail, hostname, hostnamelen)) {
  226. RPC_PRINTF(("bp_getfile: bad client\n"));
  227. return -1;
  228. }
  229. /* key name (root or swap) */
  230. if (xdr_string_encode(&send_tail, key, strlen(key))) {
  231. RPC_PRINTF(("bp_getfile: bad key\n"));
  232. return -1;
  233. }
  234. /* RPC: bootparam/getfile */
  235. d->myport = htons(--rpc_port);
  236. d->destip = bp_server_addr;
  237. /* rpc_call will set d->destport */
  238. rlen = rpc_call(d,
  239. BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
  240. sdata.d, send_tail - (char *)sdata.d,
  241. rdata.d, sizeof(rdata.d));
  242. if (rlen < 4) {
  243. RPC_PRINTF(("bp_getfile: short reply\n"));
  244. errno = EBADRPC;
  245. return -1;
  246. }
  247. recv_head = (char *)rdata.d;
  248. /*
  249. * Parse result message.
  250. */
  251. /* server name */
  252. sn_len = FNAME_SIZE-1;
  253. if (xdr_string_decode(&recv_head, serv_name, &sn_len)) {
  254. RPC_PRINTF(("bp_getfile: bad server name\n"));
  255. return -1;
  256. }
  257. /* server IP address (mountd/NFS) */
  258. if (xdr_inaddr_decode(&recv_head, serv_addr)) {
  259. RPC_PRINTF(("bp_getfile: bad server addr\n"));
  260. return -1;
  261. }
  262. /* server pathname */
  263. path_len = MAXPATHLEN - 1;
  264. if (xdr_string_decode(&recv_head, pathname, &path_len)) {
  265. RPC_PRINTF(("bp_getfile: bad server path\n"));
  266. return -1;
  267. }
  268. /* success */
  269. return 0;
  270. }
  271. /*
  272. * eXternal Data Representation routines.
  273. * (but with non-standard args...)
  274. */
  275. int
  276. xdr_string_encode(char **pkt, char *str, int len)
  277. {
  278. u_int32_t *lenp;
  279. char *datap;
  280. int padlen = (len + 3) & ~3; /* padded length */
  281. /* The data will be int aligned. */
  282. lenp = (u_int32_t *)*pkt;
  283. *pkt += sizeof(*lenp);
  284. *lenp = htonl(len);
  285. datap = *pkt;
  286. *pkt += padlen;
  287. (void)memcpy(datap, str, len);
  288. return 0;
  289. }
  290. /* len_p: bufsize - 1 */
  291. int
  292. xdr_string_decode(char **pkt, char *str, int *len_p)
  293. {
  294. u_int32_t *lenp;
  295. char *datap;
  296. int slen; /* string length */
  297. int plen; /* padded length */
  298. /* The data will be int aligned. */
  299. lenp = (u_int32_t *)*pkt;
  300. *pkt += sizeof(*lenp);
  301. slen = ntohl(*lenp);
  302. plen = (slen + 3) & ~3;
  303. if (slen > *len_p)
  304. slen = *len_p;
  305. datap = *pkt;
  306. *pkt += plen;
  307. (void)memcpy(str, datap, slen);
  308. str[slen] = '\0';
  309. *len_p = slen;
  310. return 0;
  311. }
  312. /* ia: network order */
  313. int
  314. xdr_inaddr_encode(char **pkt, struct in_addr ia)
  315. {
  316. struct xdr_inaddr *xi;
  317. u_char *cp;
  318. int32_t *ip;
  319. union {
  320. n_long l; /* network order */
  321. u_char c[4];
  322. } uia;
  323. /* The data will be int aligned. */
  324. xi = (struct xdr_inaddr *)*pkt;
  325. *pkt += sizeof(*xi);
  326. xi->atype = htonl(1);
  327. uia.l = ia.s_addr;
  328. cp = uia.c;
  329. ip = xi->addr;
  330. /*
  331. * Note: the htonl() calls below DO NOT
  332. * imply that uia.l is in host order.
  333. * In fact this needs it in net order.
  334. */
  335. *ip++ = htonl((unsigned int)*cp++);
  336. *ip++ = htonl((unsigned int)*cp++);
  337. *ip++ = htonl((unsigned int)*cp++);
  338. *ip++ = htonl((unsigned int)*cp++);
  339. return 0;
  340. }
  341. /* ia: network order */
  342. int
  343. xdr_inaddr_decode(char **pkt, struct in_addr *ia)
  344. {
  345. struct xdr_inaddr *xi;
  346. u_char *cp;
  347. int32_t *ip;
  348. union {
  349. n_long l; /* network order */
  350. u_char c[4];
  351. } uia;
  352. /* The data will be int aligned. */
  353. xi = (struct xdr_inaddr *)*pkt;
  354. *pkt += sizeof(*xi);
  355. if (xi->atype != htonl(1)) {
  356. RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n",
  357. ntohl(xi->atype)));
  358. return -1;
  359. }
  360. cp = uia.c;
  361. ip = xi->addr;
  362. /*
  363. * Note: the ntohl() calls below DO NOT
  364. * imply that uia.l is in host order.
  365. * In fact this needs it in net order.
  366. */
  367. *cp++ = ntohl(*ip++);
  368. *cp++ = ntohl(*ip++);
  369. *cp++ = ntohl(*ip++);
  370. *cp++ = ntohl(*ip++);
  371. ia->s_addr = uia.l;
  372. return 0;
  373. }