1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * This file contains routines responsible for getting the system's
31 * name and boot params. Most of it comes from the SVR4 diskless boot
32 * code (dlboot_inet), modified to work in a non socket environment.
33 */
34
35 #include <sys/types.h>
36 #include <rpc/types.h>
37 #include <sys/errno.h>
38 #include <rpc/auth.h>
39 #include <rpc/xdr.h>
40 #include <rpc/rpc_msg.h>
41 #include <sys/t_lock.h>
42 #include "clnt.h"
43 #include <rpc/rpc.h>
44 #include <sys/utsname.h>
45 #include <netinet/in.h>
46 #include <sys/socket.h>
47 #include <net/if.h>
48 #include <netinet/if_ether.h>
49 #include <netinet/in.h>
50 #include <sys/promif.h>
51 #include <rpcsvc/bootparam.h>
52 #include "pmap.h"
53 #include "brpc.h"
54 #include "socket_inet.h"
55 #include "ipv4.h"
56 #include <sys/salib.h>
57 #include <sys/bootdebug.h>
58
59 extern int errno;
60 static struct bp_whoami_res bp;
61 static char bp_hostname[SYS_NMLN+1];
62 static char bp_domainname[SYS_NMLN+1];
63 static struct in_addr responder; /* network order */
64
65 static const char *noserver =
66 "No bootparam (%s) server responding; still trying...\n";
67
68 #define GETFILE_BTIMEO 1
69 #define GETFILE_BRETRIES 2
70
71 #define dprintf if (boothowto & RB_DEBUG) printf
72
73 /*
74 * Returns TRUE if it has set the global structure 'bp' to our boot
75 * parameters, FALSE if some failure occurred.
76 */
77 bool_t
whoami(void)78 whoami(void)
79 {
80 struct bp_whoami_arg arg;
81 struct sockaddr_in to, from;
82 struct in_addr ipaddr;
83 enum clnt_stat stat;
84 bool_t retval = TRUE;
85 int rexmit; /* retransmission interval */
86 int resp_wait; /* secs to wait for resp */
87 int namelen;
88 int printed_waiting_msg;
89
90 /*
91 * Set our destination IP address to the limited broadcast address
92 * (INADDR_BROADCAST).
93 */
94 to.sin_family = AF_INET;
95 to.sin_addr.s_addr = htonl(INADDR_BROADCAST);
96 to.sin_port = htons(0);
97
98 /*
99 * Set up the arguments expected by bootparamd.
100 */
101 arg.client_address.address_type = IP_ADDR_TYPE;
102 ipv4_getipaddr(&ipaddr);
103 ipaddr.s_addr = htonl(ipaddr.s_addr);
104 bcopy((caddr_t)&ipaddr,
105 (caddr_t)&arg.client_address.bp_address_u.ip_addr,
106 sizeof (ipaddr));
107
108 /*
109 * Retransmit/wait for up to resp_wait secs.
110 */
111 rexmit = 0; /* start at default retransmission interval. */
112 resp_wait = 16;
113
114 bp.client_name = &bp_hostname[0];
115 bp.domain_name = &bp_domainname[0];
116
117 /*
118 * Do a broadcast call to find a bootparam daemon that
119 * will tell us our hostname, domainname and any
120 * router that we have to use to talk to our NFS server.
121 */
122 printed_waiting_msg = 0;
123 do {
124 /*
125 * First try the SunOS portmapper and if no reply is
126 * received will then try the SVR4 rpcbind.
127 * Either way, `bootpaddr' will be set to the
128 * correct address for the bootparamd that responds.
129 */
130 stat = bpmap_rmtcall((rpcprog_t)BOOTPARAMPROG,
131 (rpcvers_t)BOOTPARAMVERS, (rpcproc_t)BOOTPARAMPROC_WHOAMI,
132 xdr_bp_whoami_arg, (caddr_t)&arg,
133 xdr_bp_whoami_res, (caddr_t)&bp, rexmit, resp_wait,
134 &to, &from, AUTH_NONE);
135 if (stat == RPC_TIMEDOUT && !printed_waiting_msg) {
136 dprintf(noserver, "whoami");
137 printed_waiting_msg = 1;
138 }
139 /*
140 * Retransmission interval for second and subsequent tries.
141 * We expect first bpmap_rmtcall to retransmit and backoff to
142 * at least this value.
143 */
144 rexmit = resp_wait;
145 resp_wait = 0; /* go to default wait now. */
146 } while (stat == RPC_TIMEDOUT);
147
148 if (stat != RPC_SUCCESS) {
149 dprintf("whoami RPC call failed with rpc status: %d\n", stat);
150 retval = FALSE;
151 goto done;
152 } else {
153 if (printed_waiting_msg && (boothowto & RB_VERBOSE))
154 printf("Bootparam response received\n");
155
156 /* Cache responder... We'll send our getfile here... */
157 responder.s_addr = from.sin_addr.s_addr;
158 }
159
160 namelen = strlen(bp.client_name);
161 if (namelen > SYS_NMLN) {
162 dprintf("whoami: hostname too long");
163 retval = FALSE;
164 goto done;
165 }
166 if (namelen > 0) {
167 if (boothowto & RB_VERBOSE)
168 printf("hostname: %s\n", bp.client_name);
169 sethostname(bp.client_name, namelen);
170 } else {
171 dprintf("whoami: no host name\n");
172 retval = FALSE;
173 goto done;
174 }
175
176 namelen = strlen(bp.domain_name);
177 if (namelen > SYS_NMLN) {
178 dprintf("whoami: domainname too long");
179 retval = FALSE;
180 goto done;
181 }
182 if (namelen > 0)
183 if (boothowto & RB_VERBOSE)
184 printf("domainname: %s\n", bp.domain_name);
185 else
186 dprintf("whoami: no domain name\n");
187
188 if (bp.router_address.address_type == IP_ADDR_TYPE) {
189 bcopy((caddr_t)&bp.router_address.bp_address_u.ip_addr,
190 (caddr_t)&ipaddr, sizeof (ipaddr));
191 if (ntohl(ipaddr.s_addr) != INADDR_ANY) {
192 dprintf("whoami: Router ip is: %s\n",
193 inet_ntoa(ipaddr));
194 /* ipv4_route expects IP addresses in network order */
195 (void) ipv4_route(IPV4_ADD_ROUTE, RT_DEFAULT, NULL,
196 &ipaddr);
197 }
198 } else
199 dprintf("whoami: unknown gateway addr family %d\n",
200 bp.router_address.address_type);
201 done:
202 return (retval);
203 }
204
205 /*
206 * Returns:
207 * 1) The ascii form of our root servers name in `server_name'.
208 * 2) Pathname of our root on the server in `server_path'.
209 *
210 * NOTE: it's ok for getfile() to do dynamic allocation - it's only
211 * used locally, then freed. If the server address returned from the
212 * getfile call is different from our current destination address,
213 * reset destination IP address to the new value.
214 */
215 bool_t
getfile(char * fileid,char * server_name,struct in_addr * server_ip,char * server_path)216 getfile(char *fileid, char *server_name, struct in_addr *server_ip,
217 char *server_path)
218 {
219 struct bp_getfile_arg arg;
220 struct bp_getfile_res res;
221 enum clnt_stat stat;
222 struct sockaddr_in to, from;
223 int rexmit;
224 int wait;
225 uint_t max_retries = 0xFFFFFFFF;
226 int def_rexmit = 0;
227 int def_wait = 32;
228 int printed_waiting_msg;
229
230 /*
231 * For non-root requests, set a smaller timeout
232 */
233 if (strcmp(fileid, "root") != 0) {
234 /*
235 * Only send one request per call
236 */
237 def_wait = GETFILE_BTIMEO;
238 def_rexmit = GETFILE_BTIMEO;
239 max_retries = GETFILE_BRETRIES;
240 }
241
242 arg.client_name = bp.client_name;
243 arg.file_id = fileid;
244
245 res.server_name = (bp_machine_name_t)bkmem_zalloc(SYS_NMLN + 1);
246 res.server_path = (bp_path_t)bkmem_zalloc(SYS_NMLN + 1);
247
248 if (res.server_name == NULL || res.server_path == NULL) {
249 dprintf("getfile: rpc_call failed: No memory\n");
250 errno = ENOMEM;
251 if (res.server_name != NULL)
252 bkmem_free(res.server_name, SYS_NMLN + 1);
253 if (res.server_path != NULL)
254 bkmem_free(res.server_path, SYS_NMLN + 1);
255 return (FALSE);
256 }
257
258 to.sin_family = AF_INET;
259 to.sin_addr.s_addr = responder.s_addr;
260 to.sin_port = htons(0);
261
262 /*
263 * Our addressing information was filled in by the call to
264 * whoami(), so now send an rpc message to the
265 * bootparam daemon requesting our server information.
266 *
267 * Wait only 32 secs for rpc_call to succeed.
268 */
269 rexmit = def_rexmit;
270 wait = def_wait;
271
272 stat = brpc_call((rpcprog_t)BOOTPARAMPROG, (rpcvers_t)BOOTPARAMVERS,
273 (rpcproc_t)BOOTPARAMPROC_GETFILE, xdr_bp_getfile_arg, (caddr_t)&arg,
274 xdr_bp_getfile_res, (caddr_t)&res, rexmit, wait,
275 &to, &from, AUTH_NONE);
276
277 if (stat == RPC_TIMEDOUT) {
278 /*
279 * The server that answered the whoami doesn't
280 * answer our getfile. Broadcast the call to all. Keep
281 * trying forever. Set up for limited broadcast.
282 */
283 to.sin_addr.s_addr = htonl(INADDR_BROADCAST);
284 to.sin_port = htons(0);
285
286 rexmit = def_rexmit; /* use default rexmit interval */
287 wait = def_wait;
288 printed_waiting_msg = 0;
289 do {
290 /*
291 * Limit the number of retries
292 */
293 if (max_retries-- == 0)
294 break;
295
296 stat = bpmap_rmtcall((rpcprog_t)BOOTPARAMPROG,
297 (rpcvers_t)BOOTPARAMVERS,
298 (rpcproc_t)BOOTPARAMPROC_GETFILE,
299 xdr_bp_getfile_arg, (caddr_t)&arg,
300 xdr_bp_getfile_res, (caddr_t)&res, rexmit,
301 wait, &to, &from, AUTH_NONE);
302
303 if (stat == RPC_SUCCESS) {
304 /*
305 * set our destination addresses to
306 * those of the server that responded.
307 * It's probably our server, and we
308 * can thus save arping for no reason later.
309 */
310 responder.s_addr = from.sin_addr.s_addr;
311 if (printed_waiting_msg &&
312 (boothowto & RB_VERBOSE)) {
313 printf(
314 "Bootparam response received.\n");
315 }
316 break;
317 }
318 if (stat == RPC_TIMEDOUT && !printed_waiting_msg) {
319 dprintf(noserver, "getfile");
320 printed_waiting_msg = 1;
321 }
322 /*
323 * Retransmission interval for second and
324 * subsequent tries. We expect first bpmap_rmtcall
325 * to retransmit and backoff to at least this
326 * value.
327 */
328 rexmit = wait;
329 wait = def_wait;
330 } while (stat == RPC_TIMEDOUT);
331 }
332
333 if (stat == RPC_SUCCESS) {
334 /* got the goods */
335 bcopy(res.server_name, server_name, strlen(res.server_name));
336 bcopy(res.server_path, server_path, strlen(res.server_path));
337 switch (res.server_address.address_type) {
338 case IP_ADDR_TYPE:
339 /*
340 * server_address is where we will get our root
341 * from. Replace destination entries in address if
342 * necessary.
343 */
344 bcopy((caddr_t)&res.server_address.bp_address_u.ip_addr,
345 (caddr_t)server_ip, sizeof (struct in_addr));
346 break;
347 default:
348 dprintf("getfile: unknown address type %d\n",
349 res.server_address.address_type);
350 server_ip->s_addr = htonl(INADDR_ANY);
351 bkmem_free(res.server_name, SYS_NMLN + 1);
352 bkmem_free(res.server_path, SYS_NMLN + 1);
353 return (FALSE);
354 }
355 } else {
356 dprintf("getfile: rpc_call failed.\n");
357 bkmem_free(res.server_name, SYS_NMLN + 1);
358 bkmem_free(res.server_path, SYS_NMLN + 1);
359 return (FALSE);
360 }
361
362 bkmem_free(res.server_name, SYS_NMLN + 1);
363 bkmem_free(res.server_path, SYS_NMLN + 1);
364
365 return (TRUE);
366 }
367