Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/nfs/nfs_dlinet.c
+++ new/usr/src/uts/common/fs/nfs/nfs_dlinet.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 -#pragma ident "%Z%%M% %I% %E% SMI"
27 -
28 26 #include <sys/param.h>
29 27 #include <sys/types.h>
30 28 #include <sys/systm.h>
31 29 #include <sys/cred.h>
32 30 #include <sys/user.h>
33 31 #include <sys/file.h>
34 32 #include <sys/stream.h>
35 33 #include <sys/strsubr.h>
36 34 #include <sys/stropts.h>
37 35 #include <sys/strsun.h>
38 36 #include <sys/debug.h>
39 37 #include <sys/tiuser.h>
40 38 #include <sys/sockio.h>
41 39 #include <sys/socket.h>
42 40 #include <sys/t_kuser.h>
43 41 #include <sys/utsname.h>
44 42 #include <sys/systeminfo.h>
45 43 #include <sys/netconfig.h>
46 44 #include <sys/ethernet.h>
47 45 #include <sys/dlpi.h>
48 46 #include <sys/vfs.h>
49 47 #include <sys/sysmacros.h>
50 48 #include <sys/bootconf.h>
51 49 #include <sys/bootprops.h>
52 50 #include <sys/cmn_err.h>
53 51 #include <sys/promif.h>
54 52 #include <sys/mount.h>
55 53
56 54 #include <net/if.h>
57 55 #include <net/route.h>
58 56
59 57 #include <netinet/in.h>
60 58 #include <netinet/arp.h>
61 59 #include <netinet/dhcp.h>
62 60 #include <netinet/inetutil.h>
63 61 #include <dhcp_impl.h>
64 62 #include <sys/sunos_dhcp_class.h>
65 63
66 64 #include <rpc/types.h>
67 65 #include <rpc/rpc.h>
68 66 #include <rpc/xdr.h>
69 67 #include <rpc/auth.h>
70 68 #include <rpc/clnt.h>
71 69 #include <rpc/pmap_clnt.h>
72 70 #include <rpc/pmap_rmt.h>
73 71 #include <rpc/pmap_prot.h>
74 72 #include <rpc/bootparam.h>
75 73 #include <rpc/rpcb_prot.h>
76 74
77 75 #include <nfs/nfs.h>
78 76 #include <nfs/nfs4.h>
79 77 #include <nfs/nfs_clnt.h>
80 78 #include <nfs/mount.h>
81 79 #include <sys/mntent.h>
82 80
83 81 #include <sys/kstr.h>
84 82 #include <sys/sunddi.h>
85 83 #include <sys/sunldi.h>
86 84 #include <sys/esunddi.h>
87 85
88 86 #include <sys/errno.h>
89 87 #include <sys/modctl.h>
90 88
91 89 /*
92 90 * RPC timers and retries
93 91 */
94 92 #define PMAP_RETRIES 5
95 93 #define DEFAULT_RETRIES 3
96 94 #define GETFILE_RETRIES 2
97 95
98 96 #define DEFAULT_TIMEO 3
99 97 #define WHOAMI_TIMEO 20
100 98 #define REVARP_TIMEO 5
101 99 #define GETFILE_TIMEO 1
102 100
103 101 /*
104 102 * These are from the rpcgen'd version of mount.h XXX
105 103 */
106 104 #define MOUNTPROG 100005
107 105 #define MOUNTPROC_MNT 1
108 106 #define MOUNTVERS 1
109 107 #define MOUNTVERS_POSIX 2
110 108 #define MOUNTVERS3 3
111 109
112 110 struct fhstatus {
113 111 int fhs_status;
114 112 fhandle_t fhs_fh;
115 113 };
116 114
117 115 #define FHSIZE3 64
118 116
119 117 struct fhandle3 {
120 118 uint_t fhandle3_len;
121 119 char *fhandle3_val;
122 120 };
123 121
124 122 enum mountstat3 {
125 123 MNT_OK = 0,
126 124 MNT3ERR_PERM = 1,
127 125 MNT3ERR_NOENT = 2,
128 126 MNT3ERR_IO = 5,
129 127 MNT3ERR_ACCES = 13,
130 128 MNT3ERR_NOTDIR = 20,
131 129 MNT3ERR_INVAL = 22,
132 130 MNT3ERR_NAMETOOLONG = 63,
133 131 MNT3ERR_NOTSUPP = 10004,
134 132 MNT3ERR_SERVERFAULT = 10006
135 133 };
136 134
137 135 struct mountres3_ok {
138 136 struct fhandle3 fhandle;
139 137 struct {
140 138 uint_t auth_flavors_len;
141 139 int *auth_flavors_val;
142 140 } auth_flavors;
143 141 };
144 142
145 143 struct mountres3 {
146 144 enum mountstat3 fhs_status;
147 145 union {
148 146 struct mountres3_ok mountinfo;
149 147 } mountres3_u;
150 148 };
151 149
152 150 /*
153 151 * DLPI address format.
154 152 */
↓ open down ↓ |
117 lines elided |
↑ open up ↑ |
155 153 struct dladdr {
156 154 uchar_t dl_phys[6];
157 155 ushort_t dl_sap;
158 156 };
159 157
160 158 static struct modlmisc modlmisc = {
161 159 &mod_miscops, "Boot diskless"
162 160 };
163 161
164 162 static struct modlinkage modlinkage = {
165 - MODREV_1, (void *)&modlmisc, NULL
163 + MODREV_1, { (void *)&modlmisc, NULL }
166 164 };
167 165
168 166 static int dldebug;
169 167
170 168 int
171 169 _init(void)
172 170 {
173 171 return (mod_install(&modlinkage));
174 172 }
175 173
176 174 int
177 175 _fini(void)
178 176 {
179 177 return (mod_remove(&modlinkage));
180 178 }
181 179
182 180 int
183 181 _info(struct modinfo *modinfop)
184 182 {
185 183 return (mod_info(&modlinkage, modinfop));
186 184 }
187 185
188 186
189 187 static enum clnt_stat pmap_rmt_call(struct knetconfig *, struct netbuf *,
190 188 bool_t, rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t,
191 189 caddr_t, xdrproc_t, caddr_t, struct timeval,
192 190 struct netbuf *);
193 191 static bool_t myxdr_rmtcall_args(XDR *, struct rmtcallargs *);
194 192 static bool_t myxdr_rmtcallres(XDR *, struct rmtcallres *);
195 193 static bool_t myxdr_pmap(XDR *, struct pmap *);
196 194 static bool_t myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp);
197 195 static bool_t myxdr_fhandle(XDR *xdrs, fhandle_t *fh);
198 196 static bool_t myxdr_mountres3(XDR *xdrs, struct mountres3 *objp);
199 197 static bool_t myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp);
200 198 static bool_t myxdr_mountres3_ok(XDR *xdrs,
201 199 struct mountres3_ok *objp);
202 200 static bool_t myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp);
203 201 static enum clnt_stat pmap_kgetport(struct knetconfig *, struct netbuf *,
204 202 rpcprog_t, rpcvers_t, rpcprot_t);
205 203 static enum clnt_stat mycallrpc(struct knetconfig *, struct netbuf *,
206 204 rpcprog_t, rpcvers_t, rpcproc_t, xdrproc_t,
207 205 char *, xdrproc_t, char *, int, int);
208 206 static int ifioctl(TIUSER *, int, struct netbuf *);
209 207 static int getfile(char *, char *, struct netbuf *, char *);
210 208 static int ping_prog(struct netbuf *, uint_t prog, uint_t vers,
211 209 int proto, enum clnt_stat *);
212 210 static int mountnfs(struct netbuf *, char *, char *,
213 211 fhandle_t *, int *);
214 212 static int mountnfs3(struct netbuf *, char *, char *,
215 213 nfs_fh3 *, int *);
216 214 static int init_mountopts(struct nfs_args *, int,
217 215 struct knetconfig **, int *);
218 216 static int revarp_myaddr(TIUSER *);
219 217 static void revarp_start(ldi_handle_t, struct netbuf *);
220 218 static void revarpinput(ldi_handle_t, struct netbuf *);
221 219 static void init_netbuf(struct netbuf *);
222 220 static void free_netbuf(struct netbuf *);
223 221 static int rtioctl(TIUSER *, int, struct rtentry *);
224 222 static void init_config(void);
225 223
226 224 static void cacheinit(void);
227 225 static int cacheinfo(char *, int, struct netbuf *, char *, int);
228 226 static int dlifconfig(TIUSER *, struct in_addr *, struct in_addr *,
229 227 struct in_addr *, uint_t);
230 228 static int setifflags(TIUSER *, uint_t);
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
231 229
232 230 static char *inet_ntoa(struct in_addr);
233 231 static int inet_aton(char *, uchar_t *);
234 232 static int isdigit(int);
235 233
236 234 /*
237 235 * Should be in some common
238 236 * ethernet source file.
239 237 */
240 238 static struct ether_addr etherbroadcastaddr = {
241 - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
239 + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
242 240 };
243 241
244 242 static struct ether_addr myether;
245 243
246 244 /*
247 245 * "ifname" is the interface name/unit as read from the boot
248 246 * arguments.
249 247 * "ndev" is the major device number of the network interface
250 248 * used to boot from.
251 249 * "ifunit" it the physical point of attachment for the network
252 250 * interface used to boot from.
253 251 *
254 252 * Both of these are initialized in "init_config()".
255 253 */
256 254
257 255 static char ifname[IFNAMSIZ];
258 256 static char ndev_path[MAXPATHLEN];
259 257 static int ifunit;
260 258
261 259 /*
262 260 * XXX these should be shared
263 261 */
264 262 static struct knetconfig dl_udp_netconf = {
265 263 NC_TPI_CLTS, /* semantics */
266 264 NC_INET, /* family */
267 265 NC_UDP, /* protocol */
268 266 0, /* device */
269 267 };
270 268
271 269 static struct knetconfig dl_tcp_netconf = {
272 270 NC_TPI_COTS, /* semantics */
273 271 NC_INET, /* family */
274 272 NC_TCP, /* protocol */
275 273 0, /* device */
276 274 };
277 275
278 276 /* parameters from DHCP or bootparamd */
279 277 static PKT_LIST *pl = NULL;
280 278 static uchar_t server_ip[4];
281 279 static uchar_t dhcp_server_ip[4];
282 280 static char *server_name_c, *server_path_c;
283 281 static char rootopts[256];
284 282
285 283 /*
286 284 * XXX Until we get the nfsmapid deadlocks all fixed, don't allow
287 285 * XXX a v4 root mount.
288 286 */
289 287 int nfs4_no_diskless_root_support = 1;
290 288
291 289 int
292 290 mount_root(char *name, char *path, int version, struct nfs_args *args,
293 291 int *vfsflags)
294 292 {
295 293 int rc;
296 294 int proto;
297 295 struct knetconfig *dl_cf;
298 296 static int init_done = 0;
299 297 enum clnt_stat stat;
300 298
301 299 if (dldebug)
302 300 printf("mount_root: name=%s\n", name);
303 301
304 302 if (init_done == 0) {
305 303 init_config();
306 304 init_done = 1;
307 305 }
308 306
309 307 init_netbuf(args->addr);
310 308
311 309 do {
312 310 rc = getfile(name, args->hostname, args->addr, path);
313 311 } while (rc == ETIMEDOUT);
314 312
315 313 if (rc) {
316 314 free_netbuf(args->addr);
317 315 return (rc);
318 316 }
319 317
320 318 ASSERT(args->knconf->knc_protofmly != NULL);
321 319 ASSERT(args->knconf->knc_proto != NULL);
322 320
323 321 switch (version) {
324 322 case NFS_VERSION:
325 323 rc = mountnfs(args->addr, args->hostname, path,
326 324 (fhandle_t *)args->fh, &proto);
327 325 break;
328 326 case NFS_V3:
329 327 rc = mountnfs3(args->addr, args->hostname, path,
330 328 (nfs_fh3 *)args->fh, &proto);
331 329 break;
332 330 case NFS_V4:
333 331 ((struct sockaddr_in *)args->addr->buf)->sin_port =
334 332 htons(NFS_PORT);
335 333 if (ping_prog(args->addr, NFS_PROGRAM, NFS_V4, IPPROTO_TCP,
336 334 &stat)) {
337 335 proto = IPPROTO_TCP;
338 336 rc = 0;
339 337 } else {
340 338 switch (stat) {
341 339 case RPC_PROGVERSMISMATCH:
342 340 case RPC_XPRTFAILED:
343 341 /*
344 342 * Common failures if v4 unsupported or no TCP
345 343 */
346 344 rc = EPROTONOSUPPORT;
347 345 break;
348 346 default:
349 347 rc = ENXIO;
350 348 }
351 349 }
352 350 if (nfs4_no_diskless_root_support)
353 351 rc = EPROTONOSUPPORT;
354 352 break;
355 353 default:
356 354 rc = EPROTONOSUPPORT;
357 355 break;
358 356 }
359 357
360 358 if (rc)
361 359 goto errout;
362 360
363 361 switch (proto) {
364 362 case IPPROTO_TCP:
365 363 dl_cf = &dl_tcp_netconf;
366 364 break;
367 365 case IPPROTO_UDP:
368 366 default:
369 367 dl_cf = &dl_udp_netconf;
370 368 break;
371 369 }
372 370
373 371 rc = init_mountopts(args, version, &dl_cf, vfsflags);
374 372
375 373 /*
376 374 * Copy knetconfig information from the template, note that the
377 375 * rdev field has been set by init_config above.
378 376 */
379 377 args->knconf->knc_semantics = dl_cf->knc_semantics;
380 378 args->knconf->knc_rdev = dl_cf->knc_rdev;
381 379 (void) strcpy(args->knconf->knc_protofmly, dl_cf->knc_protofmly);
382 380 (void) strcpy(args->knconf->knc_proto, dl_cf->knc_proto);
383 381
384 382 errout:
385 383 if (dldebug) {
386 384 if (rc)
387 385 nfs_perror(rc, "mount_root: mount %s:%s failed: %m\n",
388 386 args->hostname, path);
389 387 else
390 388 printf("mount_root: leaving\n");
391 389 }
392 390
393 391 return (rc);
394 392 }
395 393
396 394 /*
397 395 * Call mount daemon on server `sa' to mount path.
398 396 * `port' is set to nfs port and fh is the fhandle
399 397 * returned from the server.
400 398 */
401 399 static int
402 400 mountnfs(struct netbuf *sa, char *server,
403 401 char *path, fhandle_t *fh, int *proto)
404 402 {
405 403 struct fhstatus fhs;
406 404 enum clnt_stat stat;
407 405
408 406 if (dldebug)
409 407 printf("mountnfs: entered\n");
410 408
411 409 /*
412 410 * Get the port number for the mount program.
413 411 * pmap_kgetport first tries a SunOS portmapper
414 412 * and, if no reply is received, will try a
415 413 * SVR4 rpcbind. Either way, `sa' is set to
416 414 * the correct address.
417 415 */
418 416 do {
419 417 stat = pmap_kgetport(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
420 418 (rpcvers_t)MOUNTVERS, (rpcprot_t)IPPROTO_UDP);
421 419
422 420 if (stat == RPC_TIMEDOUT) {
423 421 cmn_err(CE_WARN,
424 422 "mountnfs: %s:%s portmap not responding",
425 423 server, path);
426 424 } else if (stat != RPC_SUCCESS) {
427 425 cmn_err(CE_WARN,
428 426 "mountnfs: pmap_kgetport RPC error %d (%s).",
429 427 stat, clnt_sperrno(stat));
430 428 return (ENXIO); /* XXX */
431 429 }
432 430 } while (stat == RPC_TIMEDOUT);
433 431
434 432 /*
435 433 * The correct port number has been
436 434 * put into `sa' by pmap_kgetport().
437 435 */
438 436 do {
439 437 stat = mycallrpc(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
440 438 (rpcvers_t)MOUNTVERS, (rpcproc_t)MOUNTPROC_MNT,
441 439 xdr_bp_path_t, (char *)&path,
442 440 myxdr_fhstatus, (char *)&fhs,
443 441 DEFAULT_TIMEO, DEFAULT_RETRIES);
444 442 if (stat == RPC_TIMEDOUT) {
445 443 cmn_err(CE_WARN,
446 444 "mountnfs: %s:%s mount server not responding",
447 445 server, path);
448 446 }
449 447 } while (stat == RPC_TIMEDOUT);
450 448
451 449 if (stat != RPC_SUCCESS) {
452 450 cmn_err(CE_WARN, "mountnfs: RPC failed: error %d (%s).",
453 451 stat, clnt_sperrno(stat));
454 452 return (ENXIO); /* XXX */
455 453 }
456 454
457 455 ((struct sockaddr_in *)sa->buf)->sin_port = htons(NFS_PORT);
458 456
459 457 *fh = fhs.fhs_fh;
460 458 if (fhs.fhs_status != 0) {
461 459 if (dldebug)
462 460 printf("mountnfs: fhs_status %d\n", fhs.fhs_status);
463 461 return (ENXIO); /* XXX */
464 462 }
465 463
466 464 *proto = IPPROTO_UDP;
467 465
468 466 if (ping_prog(sa, NFS_PROGRAM, NFS_VERSION, IPPROTO_TCP, NULL))
469 467 *proto = IPPROTO_TCP;
470 468
471 469 if (dldebug)
472 470 printf("mountnfs: leaving\n");
473 471 return (0);
474 472 }
475 473
476 474 /*
477 475 * Call mount daemon on server `sa' to mount path.
478 476 * `port' is set to nfs port and fh is the fhandle
479 477 * returned from the server.
480 478 */
481 479 static int
482 480 mountnfs3(struct netbuf *sa, char *server,
483 481 char *path, nfs_fh3 *fh, int *proto)
484 482 {
485 483 struct mountres3 mountres3;
486 484 enum clnt_stat stat;
487 485 int ret = 0;
488 486
489 487 if (dldebug)
490 488 printf("mountnfs3: entered\n");
491 489
492 490 /*
493 491 * Get the port number for the mount program.
494 492 * pmap_kgetport first tries a SunOS portmapper
495 493 * and, if no reply is received, will try a
496 494 * SVR4 rpcbind. Either way, `sa' is set to
497 495 * the correct address.
498 496 */
499 497 do {
500 498 stat = pmap_kgetport(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
501 499 (rpcvers_t)MOUNTVERS3, (rpcprot_t)IPPROTO_UDP);
502 500
503 501 if (stat == RPC_PROGVERSMISMATCH) {
504 502 if (dldebug)
505 503 printf("mountnfs3: program/version mismatch\n");
506 504 return (EPROTONOSUPPORT); /* XXX */
507 505 } else if (stat == RPC_TIMEDOUT) {
508 506 cmn_err(CE_WARN,
509 507 "mountnfs3: %s:%s portmap not responding",
510 508 server, path);
511 509 } else if (stat != RPC_SUCCESS) {
512 510 cmn_err(CE_WARN,
513 511 "mountnfs3: pmap_kgetport RPC error %d (%s).",
514 512 stat, clnt_sperrno(stat));
515 513 return (ENXIO); /* XXX */
516 514 }
517 515 } while (stat == RPC_TIMEDOUT);
518 516
519 517 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = NULL;
520 518 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = NULL;
521 519
522 520 /*
523 521 * The correct port number has been
524 522 * put into `sa' by pmap_kgetport().
525 523 */
526 524 do {
527 525 stat = mycallrpc(&dl_udp_netconf, sa, (rpcprog_t)MOUNTPROG,
528 526 (rpcvers_t)MOUNTVERS3, (rpcproc_t)MOUNTPROC_MNT,
529 527 xdr_bp_path_t, (char *)&path,
530 528 myxdr_mountres3, (char *)&mountres3,
531 529 DEFAULT_TIMEO, DEFAULT_RETRIES);
532 530 if (stat == RPC_TIMEDOUT) {
533 531 cmn_err(CE_WARN,
534 532 "mountnfs3: %s:%s mount server not responding",
535 533 server, path);
536 534 }
537 535 } while (stat == RPC_TIMEDOUT);
538 536
539 537 if (stat == RPC_PROGVERSMISMATCH) {
540 538 if (dldebug)
541 539 printf("mountnfs3: program/version mismatch\n");
542 540 ret = EPROTONOSUPPORT;
543 541 goto out;
544 542 }
545 543 if (stat != RPC_SUCCESS) {
546 544 cmn_err(CE_WARN, "mountnfs3: RPC failed: error %d (%s).",
547 545 stat, clnt_sperrno(stat));
548 546 ret = ENXIO; /* XXX */
549 547 goto out;
550 548 }
551 549
552 550 if (mountres3.fhs_status != MNT_OK) {
553 551 if (dldebug)
554 552 printf("mountnfs3: fhs_status %d\n",
555 553 mountres3.fhs_status);
556 554 ret = ENXIO; /* XXX */
557 555 goto out;
558 556 }
559 557
560 558 ((struct sockaddr_in *)sa->buf)->sin_port = htons(NFS_PORT);
561 559
562 560 *proto = IPPROTO_UDP;
563 561
564 562 if (ping_prog(sa, NFS_PROGRAM, NFS_V3, IPPROTO_TCP, NULL)) {
565 563 *proto = IPPROTO_TCP;
566 564 }
567 565
568 566 fh->fh3_length = mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
569 567 bcopy(mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
570 568 fh->fh3_u.data, fh->fh3_length);
571 569
572 570 out:
573 571 xdr_free(myxdr_mountres3, (caddr_t)&mountres3);
574 572
575 573 if (dldebug)
576 574 printf("mountnfs3: leaving\n");
577 575 return (ret);
578 576 }
579 577
580 578 static int
581 579 ping_prog(struct netbuf *call_addr, uint_t prog, uint_t vers, int proto,
582 580 enum clnt_stat *statp)
583 581 {
584 582 struct knetconfig *knconf;
585 583 enum clnt_stat stat;
586 584 int retries = DEFAULT_RETRIES;
587 585
588 586 switch (proto) {
589 587 case IPPROTO_TCP:
590 588 knconf = &dl_tcp_netconf;
591 589 break;
592 590 case IPPROTO_UDP:
593 591 knconf = &dl_udp_netconf;
594 592 break;
595 593 default:
596 594 return (0);
597 595 }
598 596
599 597 do {
600 598 stat = mycallrpc(knconf, call_addr, prog, vers, NULLPROC,
601 599 xdr_void, NULL, xdr_void, NULL,
602 600 DEFAULT_TIMEO, DEFAULT_RETRIES);
603 601
604 602 if (dldebug)
605 603 printf("ping_prog: %d return %d (%s)\n", proto, stat,
606 604 clnt_sperrno(stat));
607 605 /*
608 606 * Special case for TCP, it may "timeout" because it failed
609 607 * to establish an initial connection but it doesn't
610 608 * actually retry, so we do the retry.
611 609 * Persistence pays in diskless.
612 610 */
613 611 } while (stat == RPC_TIMEDOUT && proto == IPPROTO_TCP && retries--);
614 612
615 613 if (statp != NULL)
616 614 *statp = stat;
617 615
618 616 if (stat != RPC_SUCCESS)
619 617 return (0);
620 618 return (1);
621 619 }
622 620
623 621 static struct netbuf bootparam_addr;
624 622
625 623 /*
626 624 * Returns after filling in the following global variables:
627 625 * bootparam_addr,
628 626 * utsname.nodename,
629 627 * srpc_domain.
630 628 */
631 629 static int
632 630 whoami(void)
633 631 {
634 632 TIUSER *tiptr;
635 633 struct netbuf sa;
636 634 struct netbuf req;
637 635 struct bp_whoami_arg arg;
638 636 struct bp_whoami_res res;
639 637 struct timeval tv;
640 638 enum clnt_stat stat;
641 639 int rc;
642 640 size_t namelen;
643 641 int printed_waiting_msg;
644 642
645 643 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
646 644 FREAD|FWRITE, &tiptr, CRED())) != 0) {
647 645 nfs_perror(rc, "whoami: t_kopen udp failed: %m.\n");
648 646 }
649 647
650 648 /*
651 649 * Find out our local (IP) address.
652 650 */
653 651 if (rc = revarp_myaddr(tiptr)) {
654 652 nfs_perror(rc, "whoami: revarp_myaddr failed: %m.\n");
655 653 (void) t_kclose(tiptr, 0);
656 654 return (rc);
657 655 }
658 656
659 657 /* explicitly use the limited broadcast address */
660 658 init_netbuf(&sa);
661 659 ((struct sockaddr_in *)sa.buf)->sin_family = AF_INET;
662 660 ((struct sockaddr_in *)sa.buf)->sin_addr.s_addr =
663 661 htonl(INADDR_BROADCAST);
664 662 sa.len = sizeof (struct sockaddr_in);
665 663
666 664 /*
667 665 * Pick up our local (IP) address.
668 666 */
669 667 init_netbuf(&req);
670 668 if (rc = ifioctl(tiptr, SIOCGIFADDR, &req)) {
671 669 nfs_perror(rc,
672 670 "whoami: couldn't get my IP address: %m.\n");
673 671 free_netbuf(&sa);
674 672 free_netbuf(&req);
675 673 (void) t_kclose(tiptr, 0);
676 674 return (rc);
677 675 }
678 676
679 677 /*
680 678 * Set up the arguments expected by bootparamd.
681 679 */
682 680 arg.client_address.address_type = IP_ADDR_TYPE;
683 681 bcopy(&((struct sockaddr_in *)req.buf)->sin_addr,
684 682 &arg.client_address.bp_address.ip_addr, sizeof (struct in_addr));
685 683
686 684 free_netbuf(&req);
687 685
688 686 init_netbuf(&bootparam_addr);
689 687
690 688 /*
691 689 * Initial retransmission interval
692 690 */
693 691 tv.tv_sec = DEFAULT_TIMEO;
694 692 tv.tv_usec = 0;
695 693 res.client_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
696 694 res.domain_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
697 695
698 696 /*
699 697 * Do a broadcast call to find a bootparam daemon that
700 698 * will tell us our hostname, domainname and any
701 699 * router that we have to use to talk to our NFS server.
702 700 */
703 701 printed_waiting_msg = 0;
704 702 do {
705 703 /*
706 704 * pmap_rmt_call will first try the SunOS portmapper
707 705 * and if no reply is received will then try the SVR4
708 706 * rpcbind.
709 707 * Either way, `bootparam_addr' will be set to the
710 708 * correct address for the bootparamd that responds.
711 709 */
712 710 stat = pmap_rmt_call(&dl_udp_netconf, &sa, TRUE, BOOTPARAMPROG,
713 711 BOOTPARAMVERS, BOOTPARAMPROC_WHOAMI,
714 712 xdr_bp_whoami_arg, (caddr_t)&arg,
715 713 xdr_bp_whoami_res, (caddr_t)&res,
716 714 tv, &bootparam_addr);
717 715 if (stat == RPC_TIMEDOUT && !printed_waiting_msg) {
718 716 cmn_err(CE_WARN,
719 717 "No bootparam server responding; still trying");
720 718 printed_waiting_msg = 1;
721 719 }
722 720 /*
723 721 * Retransmission interval for second and subsequent tries.
724 722 * We expect first pmap_rmt_call to retransmit and backoff to
725 723 * at least this value.
726 724 */
727 725 tv.tv_sec = WHOAMI_TIMEO;
728 726 tv.tv_usec = 0;
729 727 } while (stat == RPC_TIMEDOUT);
730 728
731 729 if (printed_waiting_msg)
732 730 printf("Bootparam response received\n");
733 731
734 732 if (stat != RPC_SUCCESS) {
735 733 /* XXX should get real error here */
736 734 rc = ENXIO;
737 735 cmn_err(CE_WARN,
738 736 "whoami: bootparam RPC failed: error %d (%s).",
739 737 stat, clnt_sperrno(stat));
740 738 goto done;
741 739 }
742 740
743 741 namelen = strlen(res.client_name);
744 742 if (namelen > sizeof (utsname.nodename)) {
745 743 printf("whoami: hostname too long");
746 744 rc = ENAMETOOLONG;
747 745 goto done;
748 746 }
749 747 if (namelen != 0) {
750 748 bcopy(res.client_name, &utsname.nodename, namelen);
751 749 cmn_err(CE_CONT, "?hostname: %s\n", utsname.nodename);
752 750 } else {
753 751 printf("whoami: no host name\n");
754 752 rc = ENXIO;
755 753 goto done;
756 754 }
757 755
758 756 namelen = strlen(res.domain_name);
759 757 if (namelen != 0) {
760 758 if (namelen > SYS_NMLN) {
761 759 printf("whoami: domainname too long");
762 760 rc = ENAMETOOLONG;
763 761 goto done;
764 762 }
765 763 bcopy(res.domain_name, &srpc_domain, namelen);
766 764 cmn_err(CE_CONT, "?domainname: %s\n", srpc_domain);
767 765 } else {
768 766 printf("whoami: no domain name\n");
769 767 }
770 768
771 769 if (res.router_address.address_type == IP_ADDR_TYPE) {
772 770 struct rtentry rtentry;
773 771 struct sockaddr_in *sin;
774 772 struct in_addr ipaddr;
775 773
776 774 bcopy(&res.router_address.bp_address.ip_addr, &ipaddr,
777 775 sizeof (struct in_addr));
778 776
779 777 if (ipaddr.s_addr != (uint32_t)0) {
780 778 sin = (struct sockaddr_in *)&rtentry.rt_dst;
781 779 bzero(sin, sizeof (*sin));
782 780 sin->sin_family = AF_INET;
783 781
784 782 sin = (struct sockaddr_in *)&rtentry.rt_gateway;
785 783 bzero(sin, sizeof (*sin));
786 784 sin->sin_family = AF_INET;
787 785 sin->sin_addr.s_addr = ipaddr.s_addr;
788 786
789 787 rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
790 788
791 789 if (rc = rtioctl(tiptr, SIOCADDRT, &rtentry)) {
792 790 nfs_perror(rc,
793 791 "whoami: couldn't add route: %m.\n");
794 792 goto done;
795 793 }
796 794 }
797 795 } else {
798 796 printf("whoami: unknown gateway addr family %d\n",
799 797 res.router_address.address_type);
800 798 }
801 799 done:
802 800 kmem_free(res.client_name, MAX_MACHINE_NAME + 1);
803 801 kmem_free(res.domain_name, MAX_MACHINE_NAME + 1);
804 802 free_netbuf(&sa);
805 803 (void) t_kclose(tiptr, 0);
806 804 return (rc);
807 805 }
808 806
809 807 /*
810 808 * Returns:
811 809 * 1) The ascii form of our root servers name in `server_name'.
812 810 * 2) Actual network address of our root server in `server_address'.
813 811 * 3) Whatever BOOTPARAMPROC_GETFILE returns for the fileid key, in
814 812 * `server_path'. If fileid is "root", it is the pathname of our
815 813 * root on the server.
816 814 */
817 815 static int
818 816 getfile(char *fileid,
819 817 char *server_name, struct netbuf *server_address, char *server_path)
820 818 {
821 819 struct bp_getfile_arg arg;
822 820 struct bp_getfile_res res;
823 821 enum clnt_stat stat;
824 822 int root = FALSE;
825 823 static int using_cache = FALSE;
826 824 struct in_addr ipaddr;
827 825 int timeo = DEFAULT_TIMEO;
828 826 int retries = DEFAULT_RETRIES;
829 827
830 828 if (dldebug)
831 829 printf("getfile: entered\n");
832 830
833 831 /*
834 832 * Call cacheinfo() to see whether we can satisfy this request by using
835 833 * the information cached in memory by the boot program's DHCP
836 834 * implementation or boot properties rather than consult BOOTPARAMS,
837 835 * but while preserving the semantics of getfile(). We know that
838 836 * the server name is SYS_NMLN in length, and server_path is
839 837 * MAXPATHLEN (pn_alloc).
840 838 */
841 839 if (strcmp(fileid, "root") == 0) {
842 840 if (cacheinfo(server_name, SYS_NMLN, server_address,
843 841 server_path, MAXPATHLEN) == 0) {
844 842 using_cache = TRUE;
845 843 return (0);
846 844 }
847 845 root = TRUE;
848 846 }
849 847
850 848 /*
851 849 * If using cache, rootopts is already available.
852 850 */
853 851 if (strcmp(fileid, "rootopts") == 0 && using_cache == TRUE) {
854 852 return (rootopts[0] != 0 ? 0 : ENXIO);
855 853 }
856 854
857 855 if (bootparam_addr.len == 0) {
858 856 return (ENXIO);
859 857 }
860 858 arg.client_name = (caddr_t)&utsname.nodename;
861 859 arg.file_id = fileid;
862 860
863 861 bzero(&res, sizeof (res));
864 862 res.server_name = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
865 863 res.server_path = kmem_alloc(MAX_MACHINE_NAME + 1, KM_SLEEP);
866 864
867 865 /*
868 866 * If we are not looking up the root file, we are looking
869 867 * up a non-critical option that should timeout quickly.
870 868 */
871 869 if (!root) {
872 870 timeo = GETFILE_TIMEO;
873 871 retries = GETFILE_RETRIES;
874 872 }
875 873
876 874 /*
877 875 * bootparam_addr was filled in by the call to
878 876 * whoami(), so now send an rpc message to the
879 877 * bootparam daemon requesting our server information.
880 878 * Use UDP to talk to bootparms.
881 879 */
882 880 stat = mycallrpc(&dl_udp_netconf, &bootparam_addr,
883 881 (rpcprog_t)BOOTPARAMPROG, (rpcvers_t)BOOTPARAMVERS,
884 882 (rpcproc_t)BOOTPARAMPROC_GETFILE,
885 883 xdr_bp_getfile_arg, (caddr_t)&arg,
886 884 xdr_bp_getfile_res, (caddr_t)&res,
887 885 timeo, retries);
888 886
889 887 if (stat == RPC_SUCCESS) {
890 888 (void) strcpy(server_name, res.server_name);
891 889 (void) strcpy(server_path, res.server_path);
892 890 }
893 891
894 892 kmem_free(res.server_name, MAX_MACHINE_NAME + 1);
895 893 kmem_free(res.server_path, MAX_MACHINE_NAME + 1);
896 894
897 895 if (stat != RPC_SUCCESS) {
898 896 if (root)
899 897 cmn_err(CE_WARN, "getfile: RPC failed: error %d (%s).",
900 898 stat, clnt_sperrno(stat));
901 899 return ((stat == RPC_TIMEDOUT) ? ETIMEDOUT : ENXIO); /* XXX */
902 900 }
903 901
904 902 if (*server_path == '\0')
905 903 return (EINVAL);
906 904
907 905 /*
908 906 * If the fileid is "root", we must get back a server name, for
909 907 * other parameters a server name is not required
910 908 */
911 909 if (!root) {
912 910 if (dldebug)
913 911 printf("getfile: leaving: non-root\n");
914 912 return (0);
915 913 }
916 914
917 915 if (*server_name == '\0')
918 916 return (EINVAL);
919 917
920 918 switch (res.server_address.address_type) {
921 919 case IP_ADDR_TYPE:
922 920 /*
923 921 * server_address is where we will get our root
924 922 * from.
925 923 */
926 924 ((struct sockaddr_in *)server_address->buf)->sin_family =
927 925 AF_INET;
928 926 bcopy(&res.server_address.bp_address.ip_addr,
929 927 &ipaddr, sizeof (ipaddr));
930 928 if (ipaddr.s_addr == 0)
931 929 return (EINVAL);
932 930
933 931 ((struct sockaddr_in *)server_address->buf)->sin_addr.s_addr =
934 932 ipaddr.s_addr;
935 933 server_address->len = sizeof (struct sockaddr_in);
936 934 break;
937 935
938 936 default:
939 937 printf("getfile: unknown address type %d\n",
940 938 res.server_address.address_type);
941 939 return (EPROTONOSUPPORT);
942 940 }
943 941 if (dldebug)
944 942 printf("getfile: leaving\n");
945 943 return (0);
946 944 }
947 945
948 946 /*
949 947 * If the boot property "bootp-response" exists, then OBP performed a
950 948 * successful DHCP lease acquisition for us and left the resultant ACK packet
951 949 * encoded at that location.
952 950 *
953 951 * If no such property exists (or the information is incomplete or garbled),
954 952 * the function returns -1.
955 953 */
956 954 int
957 955 dhcpinit(void)
958 956 {
959 957 int rc, i;
960 958 char *p;
961 959 struct in_addr braddr;
962 960 struct in_addr subnet;
963 961 DHCP_OPT *doptp;
964 962 TIUSER *tiptr;
965 963 struct sockaddr_in *sin;
966 964 static int once_only = 0;
967 965
968 966 if (once_only == 1) {
969 967 return (0);
970 968 }
971 969 once_only = 1;
972 970
973 971 if (dhcack == NULL) {
974 972 return (-1);
975 973 }
976 974
977 975 if (dldebug) {
978 976 printf("dhcp: dhcack %p, len %d\n", (void *)dhcack,
979 977 dhcacklen);
980 978 }
981 979
982 980 pl = kmem_alloc(sizeof (PKT_LIST), KM_SLEEP);
983 981 pl->len = dhcacklen;
984 982 pl->pkt = kmem_alloc(pl->len, KM_SLEEP);
985 983 bcopy(dhcack, pl->pkt, dhcacklen);
986 984
987 985 /*
988 986 * For x86, ifname is not initialized
989 987 * in the netinstall case and dhcack interface name is
990 988 * set in strplumb(). So we only copy the name if ifname
991 989 * is set properly.
992 990 */
993 991 if (ifname[0])
994 992 (void) strlcpy(dhcifname, ifname, sizeof (dhcifname));
995 993
996 994 /* remember the server_ip in dhcack */
997 995 bcopy((uchar_t *)pl->pkt + 20, dhcp_server_ip, 4);
998 996 bzero(pl->opts, (DHCP_LAST_OPT + 1) * sizeof (DHCP_OPT *));
999 997 bzero(pl->vs, (VS_OPTION_END - VS_OPTION_START + 1) *
1000 998 sizeof (DHCP_OPT *));
1001 999
1002 1000 if (dhcp_options_scan(pl, B_TRUE) != 0) {
1003 1001 /* garbled packet */
1004 1002 cmn_err(CE_WARN, "dhcp: DHCP packet parsing failed");
1005 1003 kmem_free(pl->pkt, pl->len);
1006 1004 kmem_free(pl, sizeof (PKT_LIST));
1007 1005 pl = NULL;
1008 1006 return (-1);
1009 1007 }
1010 1008
1011 1009 /* set node name */
1012 1010 if (pl->opts[CD_HOSTNAME] != NULL) {
1013 1011 doptp = pl->opts[CD_HOSTNAME];
1014 1012 i = doptp->len;
1015 1013 if (i >= SYS_NMLN) {
1016 1014 cmn_err(CE_WARN, "dhcp: Hostname is too long");
1017 1015 } else {
1018 1016 bcopy(doptp->value, utsname.nodename, i);
1019 1017 utsname.nodename[i] = '\0';
1020 1018 if (dldebug) {
1021 1019 printf("hostname is %s\n",
1022 1020 utsname.nodename);
1023 1021 }
1024 1022 }
1025 1023 }
1026 1024
1027 1025 /* Set NIS domain name. */
1028 1026 p = NULL;
1029 1027 if (pl->opts[CD_NIS_DOMAIN] != NULL) {
1030 1028 doptp = pl->opts[CD_NIS_DOMAIN];
1031 1029 i = doptp->len;
1032 1030 p = (caddr_t)doptp->value;
1033 1031 }
1034 1032 if (p != NULL) {
1035 1033 if (i > SYS_NMLN) {
1036 1034 cmn_err(CE_WARN,
1037 1035 "dhcp: NIS domainname too long.");
1038 1036 } else {
1039 1037 bcopy(p, srpc_domain, i);
1040 1038 srpc_domain[i] = '\0';
1041 1039 if (dldebug)
1042 1040 printf("dhcp: NIS domain name is %s\n",
1043 1041 srpc_domain);
1044 1042 }
1045 1043 }
1046 1044
1047 1045 /* fetch netmask */
1048 1046 if (pl->opts[CD_SUBNETMASK] != NULL) {
1049 1047 doptp = pl->opts[CD_SUBNETMASK];
1050 1048 if (doptp->len != sizeof (struct in_addr)) {
1051 1049 pl->opts[CD_SUBNETMASK] = NULL;
1052 1050 cmn_err(CE_WARN, "dhcp: netmask option malformed");
1053 1051 } else {
1054 1052 bcopy(doptp->value, &subnet, sizeof (struct in_addr));
1055 1053 if (dldebug)
1056 1054 printf("dhcp: setting netmask to: %s\n",
1057 1055 inet_ntoa(subnet));
1058 1056 }
1059 1057 } else {
1060 1058 struct in_addr myIPaddr;
1061 1059
1062 1060 myIPaddr.s_addr = pl->pkt->yiaddr.s_addr;
1063 1061 cmn_err(CE_WARN, "dhcp: no subnet mask supplied - inferring");
1064 1062 if (IN_CLASSA(ntohl(myIPaddr.s_addr)))
1065 1063 subnet.s_addr = htonl(IN_CLASSA_NET);
1066 1064 else if (IN_CLASSB(ntohl(myIPaddr.s_addr)))
1067 1065 subnet.s_addr = htonl(IN_CLASSB_NET);
1068 1066 else if (IN_CLASSC(ntohl(myIPaddr.s_addr)))
1069 1067 subnet.s_addr = htonl(IN_CLASSC_NET);
1070 1068 else if (IN_CLASSD(ntohl(myIPaddr.s_addr)))
1071 1069 cmn_err(CE_WARN, "dhcp: bad IP address (%s)",
1072 1070 inet_ntoa(myIPaddr));
1073 1071 else
1074 1072 subnet.s_addr = htonl(IN_CLASSE_NET);
1075 1073 }
1076 1074 /* and broadcast address */
1077 1075 if (pl->opts[CD_BROADCASTADDR] != NULL) {
1078 1076 doptp = pl->opts[CD_BROADCASTADDR];
1079 1077 if (doptp->len != sizeof (struct in_addr)) {
1080 1078 pl->opts[CD_BROADCASTADDR] = NULL;
1081 1079 if (dldebug)
1082 1080 printf("dhcp: broadcast address len %d\n",
1083 1081 doptp->len);
1084 1082 } else {
1085 1083 bcopy(doptp->value, &braddr, sizeof (struct in_addr));
1086 1084 if (dldebug)
1087 1085 printf("dhcp: setting broadcast addr to: %s\n",
1088 1086 inet_ntoa(braddr));
1089 1087 }
1090 1088 } else {
1091 1089 if (dldebug)
1092 1090 printf("dhcp: no broadcast address supplied\n");
1093 1091 braddr.s_addr = htonl(INADDR_BROADCAST);
1094 1092 }
1095 1093 /* and plumb and initialize interface */
1096 1094 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
1097 1095 FREAD|FWRITE, &tiptr, CRED())) == 0) {
1098 1096 if (rc = dlifconfig(tiptr, &pl->pkt->yiaddr, &subnet,
1099 1097 &braddr, IFF_DHCPRUNNING)) {
1100 1098 nfs_perror(rc, "dhcp: dlifconfig failed: %m\n");
1101 1099 kmem_free(pl->pkt, pl->len);
1102 1100 kmem_free(pl, sizeof (PKT_LIST));
1103 1101 pl = NULL;
1104 1102 (void) t_kclose(tiptr, 0);
1105 1103 return (-1);
1106 1104 }
1107 1105
1108 1106 /* add routes */
1109 1107 if (pl->opts[CD_ROUTER] != NULL) {
1110 1108 doptp = pl->opts[CD_ROUTER];
1111 1109 if ((doptp->len % sizeof (struct in_addr)) != 0) {
1112 1110 pl->opts[CD_ROUTER] = NULL;
1113 1111 } else {
1114 1112 int nrouters;
1115 1113 uchar_t *tp;
1116 1114
1117 1115 nrouters = doptp->len / sizeof (struct in_addr);
1118 1116 for (tp = doptp->value, i = 0; i < nrouters;
1119 1117 i++) {
1120 1118 struct in_addr defr;
1121 1119 struct rtentry rtentry;
1122 1120
1123 1121 bcopy(tp, &defr,
1124 1122 sizeof (struct in_addr));
1125 1123 if (defr.s_addr == 0)
1126 1124 continue;
1127 1125
1128 1126 sin = (struct
1129 1127 sockaddr_in *)&rtentry.rt_dst;
1130 1128
1131 1129 bzero(sin, sizeof (*sin));
1132 1130 sin->sin_family = AF_INET;
1133 1131
1134 1132 sin = (struct
1135 1133 sockaddr_in *)&rtentry.rt_gateway;
1136 1134 bzero(sin, sizeof (*sin));
1137 1135 sin->sin_family = AF_INET;
1138 1136 sin->sin_addr = defr;
1139 1137
1140 1138 rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
1141 1139
1142 1140 if (rc = rtioctl(tiptr, SIOCADDRT,
1143 1141 &rtentry)) {
1144 1142 nfs_perror(rc,
1145 1143 "dhcp: couldn't add route "
1146 1144 "to %s: %m.\n",
1147 1145 inet_ntoa(defr));
1148 1146 continue;
1149 1147 }
1150 1148 if (dldebug) {
1151 1149 printf("dhcp: added route %s\n",
1152 1150 inet_ntoa(defr));
1153 1151 }
1154 1152 tp += sizeof (struct in_addr);
1155 1153 }
1156 1154 }
1157 1155 }
1158 1156
1159 1157 (void) t_kclose(tiptr, 0);
1160 1158 }
1161 1159
1162 1160 if (dldebug)
1163 1161 printf("dhcpinit: leaving\n");
1164 1162
1165 1163 return (0);
1166 1164 }
1167 1165
1168 1166 /*
1169 1167 * Initialize nfs mount info from properties and dhcp response.
1170 1168 */
1171 1169 static void
1172 1170 cacheinit(void)
1173 1171 {
1174 1172 char *str;
1175 1173 DHCP_OPT *doptp;
1176 1174
1177 1175 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1178 1176 DDI_PROP_DONTPASS, BP_SERVER_PATH, &server_path_c);
1179 1177 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1180 1178 DDI_PROP_DONTPASS, BP_SERVER_NAME, &server_name_c);
1181 1179 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1182 1180 DDI_PROP_DONTPASS, BP_SERVER_ROOTOPTS, &str) == DDI_SUCCESS) {
1183 1181 (void) strncpy(rootopts, str, 255);
1184 1182 ddi_prop_free(str);
1185 1183 }
1186 1184 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
1187 1185 DDI_PROP_DONTPASS, BP_SERVER_IP, &str) == DDI_SUCCESS) {
1188 1186 if (inet_aton(str, server_ip) != 0)
1189 1187 cmn_err(CE_NOTE, "server_ipaddr %s is invalid\n",
1190 1188 str);
1191 1189 ddi_prop_free(str);
1192 1190 if (dldebug)
1193 1191 printf("server ip is %s\n",
1194 1192 inet_ntoa(*(struct in_addr *)server_ip));
1195 1193 }
1196 1194
1197 1195 if (pl == NULL)
1198 1196 return;
1199 1197
1200 1198 /* extract root path in server_path */
1201 1199 if (server_path_c == NULL) {
1202 1200 doptp = pl->vs[VS_NFSMNT_ROOTPATH];
1203 1201 if (doptp != NULL) {
1204 1202 server_path_c = kmem_alloc(doptp->len + 1, KM_SLEEP);
1205 1203 bcopy(doptp->value, server_path_c, doptp->len);
1206 1204 server_path_c[doptp->len] = '\0';
1207 1205 if (dldebug)
1208 1206 printf("dhcp: root path %s\n", server_path_c);
1209 1207 } else {
1210 1208 cmn_err(CE_WARN, "dhcp: root server path missing");
1211 1209 }
1212 1210 }
1213 1211
1214 1212 /* set server_name */
1215 1213 if (server_name_c == NULL) {
1216 1214 doptp = pl->vs[VS_NFSMNT_ROOTSRVR_NAME];
1217 1215 if (doptp != NULL) {
1218 1216 server_name_c = kmem_alloc(doptp->len + 1, KM_SLEEP);
1219 1217 bcopy(doptp->value, server_name_c, doptp->len);
1220 1218 server_name_c[doptp->len] = '\0';
1221 1219 if (dldebug)
1222 1220 printf("dhcp: root server name %s\n",
1223 1221 server_name_c);
1224 1222 } else {
1225 1223 cmn_err(CE_WARN, "dhcp: root server name missing");
1226 1224 }
1227 1225 }
1228 1226
1229 1227 /* set root server_address */
1230 1228 if ((*(uint_t *)server_ip) == 0) {
1231 1229 doptp = pl->vs[VS_NFSMNT_ROOTSRVR_IP];
1232 1230 if (doptp) {
1233 1231 bcopy(doptp->value, server_ip, sizeof (server_ip));
1234 1232 if (dldebug) {
1235 1233 printf("dhcp: root server IP address %s\n",
1236 1234 inet_ntoa(*(struct in_addr *)server_ip));
1237 1235 }
1238 1236 } else {
1239 1237 if (dldebug)
1240 1238 cmn_err(CE_CONT,
1241 1239 "dhcp: file server ip address missing,"
1242 1240 " fallback to dhcp server as file server");
1243 1241 bcopy(dhcp_server_ip, server_ip, sizeof (server_ip));
1244 1242 }
1245 1243 }
1246 1244
1247 1245 /* set root file system mount options */
1248 1246 if (rootopts[0] == 0) {
1249 1247 doptp = pl->vs[VS_NFSMNT_ROOTOPTS];
1250 1248 if (doptp != NULL && doptp->len < 255) {
1251 1249 bcopy(doptp->value, rootopts, doptp->len);
1252 1250 rootopts[doptp->len] = '\0';
1253 1251 if (dldebug)
1254 1252 printf("dhcp: rootopts %s\n", rootopts);
1255 1253 } else if (dldebug) {
1256 1254 printf("dhcp: no rootopts or too long\n");
1257 1255 /* not an error */
1258 1256 }
1259 1257 }
1260 1258
1261 1259 /* now we are done with pl, just free it */
1262 1260 kmem_free(pl->pkt, pl->len);
1263 1261 kmem_free(pl, sizeof (PKT_LIST));
1264 1262 pl = NULL;
1265 1263 }
1266 1264
1267 1265 static int
1268 1266 cacheinfo(char *name, int namelen,
1269 1267 struct netbuf *server_address, char *rootpath, int pathlen)
1270 1268 {
1271 1269 static int init_done = 0;
1272 1270 struct sockaddr_in *sin;
1273 1271
1274 1272 if (init_done == 0) {
1275 1273 cacheinit();
1276 1274 init_done = 1;
1277 1275 }
1278 1276
1279 1277 /* server_path is a reliable indicator of cache availability */
1280 1278 if (server_path_c == NULL)
1281 1279 return (-1);
1282 1280
1283 1281 (void) strncpy(rootpath, server_path_c, pathlen);
1284 1282 if (server_name_c) {
1285 1283 (void) strncpy(name, server_name_c, namelen);
1286 1284 } else {
1287 1285 (void) strncpy(name, "unknown", namelen);
1288 1286 }
1289 1287
1290 1288 sin = (struct sockaddr_in *)server_address->buf;
1291 1289 sin->sin_family = AF_INET;
1292 1290 server_address->len = sizeof (struct sockaddr_in);
1293 1291 bcopy(server_ip, &sin->sin_addr, sizeof (struct in_addr));
1294 1292 return (0);
1295 1293 }
1296 1294
1297 1295 /*
1298 1296 * Set this interface's IP address and netmask, and bring it up.
1299 1297 */
1300 1298 static int
1301 1299 dlifconfig(TIUSER *tiptr, struct in_addr *myIPaddr, struct in_addr *mymask,
1302 1300 struct in_addr *mybraddr, uint_t flags)
1303 1301 {
1304 1302 int rc;
1305 1303 struct netbuf sbuf;
1306 1304 struct sockaddr_in sin;
1307 1305
1308 1306 if (dldebug) {
1309 1307 printf("dlifconfig: entered\n");
1310 1308 printf("dlifconfig: addr %s\n", inet_ntoa(*myIPaddr));
1311 1309 printf("dlifconfig: mask %s\n", inet_ntoa(*mymask));
1312 1310 printf("dlifconfig: broadcast %s\n", inet_ntoa(*mybraddr));
1313 1311 }
1314 1312
1315 1313 bcopy(myIPaddr, &sin.sin_addr, sizeof (struct in_addr));
1316 1314 sin.sin_family = AF_INET;
1317 1315 sbuf.buf = (caddr_t)&sin;
1318 1316 sbuf.maxlen = sbuf.len = sizeof (sin);
1319 1317 if (rc = ifioctl(tiptr, SIOCSIFADDR, &sbuf)) {
1320 1318 nfs_perror(rc,
1321 1319 "dlifconfig: couldn't set interface net address: %m\n");
1322 1320 return (rc);
1323 1321 }
1324 1322
1325 1323 if (mybraddr->s_addr != INADDR_BROADCAST) {
1326 1324 bcopy(mybraddr, &sin.sin_addr, sizeof (struct in_addr));
1327 1325 sin.sin_family = AF_INET;
1328 1326 sbuf.buf = (caddr_t)&sin;
1329 1327 sbuf.maxlen = sbuf.len = sizeof (sin);
1330 1328 if (rc = ifioctl(tiptr, SIOCSIFBRDADDR, &sbuf)) {
1331 1329 nfs_perror(rc,
1332 1330 "dlifconfig: couldn't set interface broadcast addr: %m\n");
1333 1331 return (rc);
1334 1332 }
1335 1333 }
1336 1334
1337 1335 bcopy(mymask, &sin.sin_addr, sizeof (struct in_addr));
1338 1336 sin.sin_family = AF_INET;
1339 1337 sbuf.buf = (caddr_t)&sin;
1340 1338 sbuf.maxlen = sbuf.len = sizeof (sin);
1341 1339 if (rc = ifioctl(tiptr, SIOCSIFNETMASK, &sbuf)) {
1342 1340 nfs_perror(rc,
1343 1341 "dlifconfig: couldn't set interface net address: %m\n");
1344 1342 return (rc);
1345 1343 }
1346 1344
1347 1345 /*
1348 1346 * Now turn on the interface.
1349 1347 */
1350 1348 if (rc = setifflags(tiptr, IFF_UP | flags)) {
1351 1349 nfs_perror(rc,
1352 1350 "dlifconfig: couldn't enable network interface: %m\n");
1353 1351 return (rc);
1354 1352 }
1355 1353
1356 1354 if (dldebug)
1357 1355 printf("dlifconfig: returned\n");
1358 1356 return (0);
1359 1357 }
1360 1358
1361 1359 static char *
1362 1360 inet_ntoa(struct in_addr in)
1363 1361 {
1364 1362 static char b[18];
1365 1363 unsigned char *p;
1366 1364
1367 1365 p = (unsigned char *)∈
1368 1366 (void) sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
1369 1367 return (b);
1370 1368 }
1371 1369
1372 1370 /* We only deal with a.b.c.d decimal format. ip points to 4 byte storage */
1373 1371 static int
1374 1372 inet_aton(char *ipstr, uchar_t *ip)
1375 1373 {
1376 1374 int i = 0;
1377 1375 uchar_t val[4] = {0};
1378 1376 char c = *ipstr;
1379 1377
1380 1378 for (;;) {
1381 1379 if (!isdigit(c))
1382 1380 return (-1);
1383 1381 for (;;) {
1384 1382 if (!isdigit(c))
1385 1383 break;
1386 1384 val[i] = val[i] * 10 + (c - '0');
1387 1385 c = *++ipstr;
1388 1386 }
1389 1387 i++;
1390 1388 if (i == 4)
1391 1389 break;
1392 1390 if (c != '.')
1393 1391 return (-1);
1394 1392 c = *++ipstr;
1395 1393 }
1396 1394 if (c != 0)
1397 1395 return (-1);
1398 1396 bcopy(val, ip, 4);
1399 1397 return (0);
1400 1398 }
1401 1399
1402 1400 #define MAX_ADDR_SIZE 128
1403 1401
1404 1402 /*
1405 1403 * Initialize a netbuf suitable for
1406 1404 * describing an address for the
1407 1405 * transport defined by `tiptr'.
1408 1406 */
1409 1407 static void
1410 1408 init_netbuf(struct netbuf *nbuf)
1411 1409 {
1412 1410 nbuf->buf = kmem_zalloc(MAX_ADDR_SIZE, KM_SLEEP);
1413 1411 nbuf->maxlen = MAX_ADDR_SIZE;
1414 1412 nbuf->len = 0;
1415 1413 }
1416 1414
1417 1415 static void
1418 1416 free_netbuf(struct netbuf *nbuf)
1419 1417 {
1420 1418 kmem_free(nbuf->buf, nbuf->maxlen);
1421 1419 nbuf->buf = NULL;
1422 1420 nbuf->maxlen = 0;
1423 1421 nbuf->len = 0;
1424 1422 }
1425 1423
1426 1424 static int
1427 1425 rtioctl(TIUSER *tiptr, int cmd, struct rtentry *rtentry)
1428 1426 {
1429 1427 struct strioctl iocb;
1430 1428 int rc;
1431 1429 vnode_t *vp;
1432 1430
1433 1431 iocb.ic_cmd = cmd;
1434 1432 iocb.ic_timout = 0;
1435 1433 iocb.ic_len = sizeof (struct rtentry);
1436 1434 iocb.ic_dp = (caddr_t)rtentry;
1437 1435
1438 1436 vp = tiptr->fp->f_vnode;
1439 1437 rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb);
1440 1438 if (rc)
1441 1439 nfs_perror(rc, "rtioctl: kstr_ioctl failed: %m\n");
1442 1440 return (rc);
1443 1441 }
1444 1442
1445 1443 /*
1446 1444 * Send an ioctl down the stream defined
1447 1445 * by `tiptr'.
1448 1446 *
1449 1447 * We isolate the ifreq dependencies in here. The
1450 1448 * ioctl really ought to take a netbuf and be of
1451 1449 * type TRANSPARENT - one day.
1452 1450 */
1453 1451 static int
1454 1452 ifioctl(TIUSER *tiptr, int cmd, struct netbuf *nbuf)
1455 1453 {
1456 1454 struct strioctl iocb;
1457 1455 int rc;
1458 1456 vnode_t *vp;
1459 1457 struct ifreq ifr;
1460 1458
1461 1459 /*
1462 1460 * Now do the one requested.
1463 1461 */
1464 1462 if (nbuf->len)
1465 1463 ifr.ifr_addr = *(struct sockaddr *)nbuf->buf;
1466 1464 (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1467 1465 iocb.ic_cmd = cmd;
1468 1466 iocb.ic_timout = 0;
1469 1467 iocb.ic_len = sizeof (ifr);
1470 1468 iocb.ic_dp = (caddr_t)𝔦
1471 1469
1472 1470 vp = tiptr->fp->f_vnode;
1473 1471 rc = kstr_ioctl(vp, I_STR, (intptr_t)&iocb);
1474 1472 if (rc) {
1475 1473 nfs_perror(rc, "ifioctl: kstr_ioctl failed: %m\n");
1476 1474 return (rc);
1477 1475 }
1478 1476
1479 1477 /*
1480 1478 * Set reply length.
1481 1479 */
1482 1480 if (nbuf->len == 0) {
1483 1481 /*
1484 1482 * GET type.
1485 1483 */
1486 1484 nbuf->len = sizeof (struct sockaddr);
1487 1485 *(struct sockaddr *)nbuf->buf = ifr.ifr_addr;
1488 1486 }
1489 1487
1490 1488 return (0);
1491 1489 }
1492 1490
1493 1491 static int
1494 1492 setifflags(TIUSER *tiptr, uint_t value)
1495 1493 {
1496 1494 struct ifreq ifr;
1497 1495 int rc;
1498 1496 struct strioctl iocb;
1499 1497
1500 1498 (void) strncpy((caddr_t)&ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1501 1499 iocb.ic_cmd = SIOCGIFFLAGS;
1502 1500 iocb.ic_timout = 0;
1503 1501 iocb.ic_len = sizeof (ifr);
1504 1502 iocb.ic_dp = (caddr_t)𝔦
1505 1503 if (rc = kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb))
1506 1504 return (rc);
1507 1505
1508 1506 ifr.ifr_flags |= value;
1509 1507 iocb.ic_cmd = SIOCSIFFLAGS;
1510 1508 return (kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb));
1511 1509 }
1512 1510
1513 1511 /*
1514 1512 * REVerse Address Resolution Protocol (revarp)
1515 1513 * is used by a diskless client to find out its
1516 1514 * IP address when all it knows is its Ethernet address.
1517 1515 *
1518 1516 * Open the ethernet driver, attach and bind
1519 1517 * (DL_BIND_REQ) it, and then format a broadcast RARP
1520 1518 * message for it to send. We pick up the reply and
1521 1519 * let the caller set the interface address using SIOCSIFADDR.
1522 1520 */
1523 1521 static int
1524 1522 revarp_myaddr(TIUSER *tiptr)
1525 1523 {
1526 1524 int rc;
1527 1525 dl_info_ack_t info;
1528 1526 struct sockaddr_in sin;
1529 1527 struct netbuf sbuf;
1530 1528 ldi_handle_t lh;
1531 1529 ldi_ident_t li;
1532 1530 struct netbuf myaddr = {0, 0, NULL};
1533 1531
1534 1532 if (dldebug)
1535 1533 printf("revarp_myaddr: entered\n");
1536 1534
1537 1535 if (rc = ldi_ident_from_mod(&modlinkage, &li)) {
1538 1536 nfs_perror(rc,
1539 1537 "revarp_myaddr: ldi_ident_from_mod failed: %m\n");
1540 1538 return (rc);
1541 1539 }
1542 1540
1543 1541 rc = ldi_open_by_name(ndev_path, FREAD|FWRITE, CRED(), &lh, li);
1544 1542 ldi_ident_release(li);
1545 1543 if (rc) {
1546 1544 nfs_perror(rc,
1547 1545 "revarp_myaddr: ldi_open_by_name failed: %m\n");
1548 1546 return (rc);
1549 1547 }
1550 1548
1551 1549 if (rc = dl_attach(lh, ifunit, NULL)) {
1552 1550 nfs_perror(rc, "revarp_myaddr: dl_attach failed: %m\n");
1553 1551 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1554 1552 return (rc);
1555 1553 }
1556 1554
1557 1555 if (rc = dl_bind(lh, ETHERTYPE_REVARP, NULL)) {
1558 1556 nfs_perror(rc, "revarp_myaddr: dl_bind failed: %m\n");
1559 1557 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1560 1558 return (rc);
1561 1559 }
1562 1560
1563 1561 if (rc = dl_info(lh, &info, NULL, NULL, NULL)) {
1564 1562 nfs_perror(rc, "revarp_myaddr: dl_info failed: %m\n");
1565 1563 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1566 1564 return (rc);
1567 1565 }
1568 1566
1569 1567 /* Initialize myaddr */
1570 1568 myaddr.maxlen = info.dl_addr_length;
1571 1569 myaddr.buf = kmem_alloc(myaddr.maxlen, KM_SLEEP);
1572 1570
1573 1571 revarp_start(lh, &myaddr);
1574 1572
1575 1573 bcopy(myaddr.buf, &sin.sin_addr, myaddr.len);
1576 1574 sin.sin_family = AF_INET;
1577 1575
1578 1576 sbuf.buf = (caddr_t)&sin;
1579 1577 sbuf.maxlen = sbuf.len = sizeof (sin);
1580 1578 if (rc = ifioctl(tiptr, SIOCSIFADDR, &sbuf)) {
1581 1579 nfs_perror(rc,
1582 1580 "revarp_myaddr: couldn't set interface net address: %m\n");
1583 1581 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1584 1582 kmem_free(myaddr.buf, myaddr.maxlen);
1585 1583 return (rc);
1586 1584 }
1587 1585
1588 1586 /* Now turn on the interface */
1589 1587 if (rc = setifflags(tiptr, IFF_UP)) {
1590 1588 nfs_perror(rc,
1591 1589 "revarp_myaddr: couldn't enable network interface: %m\n");
1592 1590 }
1593 1591
1594 1592 (void) ldi_close(lh, FREAD|FWRITE, CRED());
1595 1593 kmem_free(myaddr.buf, myaddr.maxlen);
1596 1594 return (rc);
1597 1595 }
1598 1596
1599 1597 static void
1600 1598 revarp_start(ldi_handle_t lh, struct netbuf *myaddr)
1601 1599 {
1602 1600 struct ether_arp *ea;
1603 1601 int rc;
1604 1602 dl_unitdata_req_t *dl_udata;
1605 1603 mblk_t *bp;
1606 1604 mblk_t *mp;
1607 1605 struct dladdr *dlsap;
1608 1606 static int done = 0;
1609 1607 size_t addrlen = ETHERADDRL;
1610 1608
1611 1609 if (dl_phys_addr(lh, (uchar_t *)&myether, &addrlen, NULL) != 0 ||
1612 1610 addrlen != ETHERADDRL) {
1613 1611 /* Fallback using per-node address */
1614 1612 (void) localetheraddr((struct ether_addr *)NULL, &myether);
1615 1613 cmn_err(CE_CONT, "?DLPI failed to get Ethernet address. Using "
1616 1614 "system wide Ethernet address %s\n",
1617 1615 ether_sprintf(&myether));
1618 1616 }
1619 1617
1620 1618 getreply:
1621 1619 if (myaddr->len != 0) {
1622 1620 cmn_err(CE_CONT, "?Found my IP address: %x (%d.%d.%d.%d)\n",
1623 1621 *(int *)myaddr->buf,
1624 1622 (uchar_t)myaddr->buf[0], (uchar_t)myaddr->buf[1],
1625 1623 (uchar_t)myaddr->buf[2], (uchar_t)myaddr->buf[3]);
1626 1624 return;
1627 1625 }
1628 1626
1629 1627 if (done++ == 0)
1630 1628 cmn_err(CE_CONT, "?Requesting Internet address for %s\n",
1631 1629 ether_sprintf(&myether));
1632 1630
1633 1631 /*
1634 1632 * Send another RARP request.
1635 1633 */
1636 1634 if ((mp = allocb(sizeof (dl_unitdata_req_t) + sizeof (*dlsap),
1637 1635 BPRI_HI)) == NULL) {
1638 1636 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory");
1639 1637 return;
1640 1638 }
1641 1639 if ((bp = allocb(sizeof (struct ether_arp), BPRI_HI)) == NULL) {
1642 1640 cmn_err(CE_WARN, "revarp_myaddr: allocb no memory");
1643 1641 return;
1644 1642 }
1645 1643
1646 1644 /*
1647 1645 * Format the transmit request part.
1648 1646 */
1649 1647 mp->b_datap->db_type = M_PROTO;
1650 1648 dl_udata = (dl_unitdata_req_t *)mp->b_wptr;
1651 1649 mp->b_wptr += sizeof (dl_unitdata_req_t) + sizeof (*dlsap);
1652 1650 dl_udata->dl_primitive = DL_UNITDATA_REQ;
1653 1651 dl_udata->dl_dest_addr_length = sizeof (*dlsap);
1654 1652 dl_udata->dl_dest_addr_offset = sizeof (*dl_udata);
1655 1653 dl_udata->dl_priority.dl_min = 0;
1656 1654 dl_udata->dl_priority.dl_max = 0;
1657 1655
1658 1656 dlsap = (struct dladdr *)(mp->b_rptr + sizeof (*dl_udata));
1659 1657 bcopy(ðerbroadcastaddr, &dlsap->dl_phys,
1660 1658 sizeof (etherbroadcastaddr));
1661 1659 dlsap->dl_sap = ETHERTYPE_REVARP;
1662 1660
1663 1661 /*
1664 1662 * Format the actual REVARP request.
1665 1663 */
1666 1664 bzero(bp->b_wptr, sizeof (struct ether_arp));
1667 1665 ea = (struct ether_arp *)bp->b_wptr;
1668 1666 bp->b_wptr += sizeof (struct ether_arp);
1669 1667 ea->arp_hrd = htons(ARPHRD_ETHER);
1670 1668 ea->arp_pro = htons(ETHERTYPE_IP);
1671 1669 ea->arp_hln = sizeof (ea->arp_sha); /* hardware address length */
1672 1670 ea->arp_pln = sizeof (ea->arp_spa); /* protocol address length */
1673 1671 ea->arp_op = htons(REVARP_REQUEST);
1674 1672 ether_copy(&myether, &ea->arp_sha);
1675 1673 ether_copy(&myether, &ea->arp_tha);
1676 1674
1677 1675 mp->b_cont = bp;
1678 1676
1679 1677 if ((rc = ldi_putmsg(lh, mp)) != 0) {
1680 1678 nfs_perror(rc, "revarp_start: ldi_putmsg failed: %m\n");
1681 1679 return;
1682 1680 }
1683 1681 revarpinput(lh, myaddr);
1684 1682
1685 1683 goto getreply;
1686 1684 }
1687 1685
1688 1686 /*
1689 1687 * Client side Reverse-ARP input
1690 1688 * Server side is handled by user level server
1691 1689 */
1692 1690 static void
1693 1691 revarpinput(ldi_handle_t lh, struct netbuf *myaddr)
1694 1692 {
1695 1693 struct ether_arp *ea;
1696 1694 mblk_t *bp;
1697 1695 mblk_t *mp;
1698 1696 int rc;
1699 1697 timestruc_t tv, give_up, now;
1700 1698
1701 1699 /*
1702 1700 * Choose the time at which we will give up, and resend our
1703 1701 * request.
1704 1702 */
1705 1703 gethrestime(&give_up);
1706 1704 give_up.tv_sec += REVARP_TIMEO;
1707 1705 wait:
1708 1706 /*
1709 1707 * Compute new timeout value.
1710 1708 */
1711 1709 tv = give_up;
1712 1710 gethrestime(&now);
1713 1711 timespecsub(&tv, &now);
1714 1712 /*
1715 1713 * If we don't have at least one full second remaining, give up.
1716 1714 * This means we might wait only just over 4.0 seconds, but that's
1717 1715 * okay.
1718 1716 */
1719 1717 if (tv.tv_sec <= 0)
1720 1718 return;
1721 1719 rc = ldi_getmsg(lh, &mp, &tv);
1722 1720 if (rc == ETIME) {
1723 1721 goto out;
1724 1722 } else if (rc != 0) {
1725 1723 nfs_perror(rc, "revarpinput: ldi_getmsg failed: %m\n");
1726 1724 return;
1727 1725 }
1728 1726
1729 1727 if (mp->b_cont == NULL) {
1730 1728 printf("revarpinput: b_cont == NULL\n");
1731 1729 goto out;
1732 1730 }
1733 1731
1734 1732 if (mp->b_datap->db_type != M_PROTO) {
1735 1733 printf("revarpinput: bad header type %d\n",
1736 1734 mp->b_datap->db_type);
1737 1735 goto out;
1738 1736 }
1739 1737
1740 1738 bp = mp->b_cont;
1741 1739
1742 1740 if (bp->b_wptr - bp->b_rptr < sizeof (*ea)) {
1743 1741 printf("revarpinput: bad data len %d, expect %d\n",
1744 1742 (int)(bp->b_wptr - bp->b_rptr), (int)sizeof (*ea));
1745 1743 goto out;
1746 1744 }
1747 1745
1748 1746 ea = (struct ether_arp *)bp->b_rptr;
1749 1747
1750 1748 if ((ushort_t)ntohs(ea->arp_pro) != ETHERTYPE_IP) {
1751 1749 /* We could have received another broadcast arp packet. */
1752 1750 if (dldebug)
1753 1751 printf("revarpinput: bad type %x\n",
1754 1752 (ushort_t)ntohs(ea->arp_pro));
1755 1753 freemsg(mp);
1756 1754 goto wait;
1757 1755 }
1758 1756 if ((ushort_t)ntohs(ea->arp_op) != REVARP_REPLY) {
1759 1757 /* We could have received a broadcast arp request. */
1760 1758 if (dldebug)
1761 1759 printf("revarpinput: bad op %x\n",
1762 1760 (ushort_t)ntohs(ea->arp_op));
1763 1761 freemsg(mp);
1764 1762 goto wait;
1765 1763 }
1766 1764
1767 1765 if (!ether_cmp(&ea->arp_tha, &myether)) {
1768 1766 bcopy(&ea->arp_tpa, myaddr->buf, sizeof (ea->arp_tpa));
1769 1767 myaddr->len = sizeof (ea->arp_tpa);
1770 1768 } else {
1771 1769 /* We could have gotten a broadcast arp response. */
1772 1770 if (dldebug)
1773 1771 printf("revarpinput: got reply, but not my address\n");
1774 1772 freemsg(mp);
1775 1773 goto wait;
1776 1774 }
1777 1775 out:
1778 1776 freemsg(mp);
1779 1777 }
1780 1778
1781 1779 /*
1782 1780 * From rpcsvc/mountxdr.c in SunOS. We can't
1783 1781 * put this into the rpc directory because
1784 1782 * it calls xdr_fhandle() which is in a
1785 1783 * loadable module.
1786 1784 */
1787 1785 static bool_t
1788 1786 myxdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp)
1789 1787 {
1790 1788
1791 1789 if (!xdr_int(xdrs, &fhsp->fhs_status))
1792 1790 return (FALSE);
1793 1791 if (fhsp->fhs_status == 0) {
1794 1792 if (!myxdr_fhandle(xdrs, &fhsp->fhs_fh))
1795 1793 return (FALSE);
1796 1794 }
1797 1795 return (TRUE);
1798 1796 }
1799 1797
1800 1798 /*
1801 1799 * From nfs_xdr.c.
1802 1800 *
1803 1801 * File access handle
1804 1802 * The fhandle struct is treated a opaque data on the wire
1805 1803 */
1806 1804 static bool_t
1807 1805 myxdr_fhandle(XDR *xdrs, fhandle_t *fh)
1808 1806 {
1809 1807 return (xdr_opaque(xdrs, (caddr_t)fh, NFS_FHSIZE));
1810 1808 }
1811 1809
1812 1810 static bool_t
1813 1811 myxdr_mountres3(XDR *xdrs, struct mountres3 *objp)
1814 1812 {
1815 1813 if (!myxdr_mountstat3(xdrs, &objp->fhs_status))
1816 1814 return (FALSE);
1817 1815 switch (objp->fhs_status) {
1818 1816 case MNT_OK:
1819 1817 if (!myxdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
1820 1818 return (FALSE);
1821 1819 break;
1822 1820 default:
1823 1821 break;
1824 1822 }
1825 1823 return (TRUE);
1826 1824 }
1827 1825
1828 1826 static bool_t
1829 1827 myxdr_mountstat3(XDR *xdrs, enum mountstat3 *objp)
1830 1828 {
1831 1829 return (xdr_enum(xdrs, (enum_t *)objp));
1832 1830 }
1833 1831
1834 1832 static bool_t
1835 1833 myxdr_mountres3_ok(XDR *xdrs, struct mountres3_ok *objp)
1836 1834 {
1837 1835 if (!myxdr_fhandle3(xdrs, &objp->fhandle))
1838 1836 return (FALSE);
1839 1837 if (!xdr_array(xdrs, (char **)&objp->auth_flavors.auth_flavors_val,
1840 1838 (uint_t *)&objp->auth_flavors.auth_flavors_len, ~0,
1841 1839 sizeof (int), (xdrproc_t)xdr_int))
1842 1840 return (FALSE);
1843 1841 return (TRUE);
1844 1842 }
1845 1843
1846 1844 static bool_t
1847 1845 myxdr_fhandle3(XDR *xdrs, struct fhandle3 *objp)
1848 1846 {
1849 1847 return (xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
1850 1848 (uint_t *)&objp->fhandle3_len, FHSIZE3));
1851 1849 }
1852 1850
1853 1851 /*
1854 1852 * From SunOS pmap_clnt.c
1855 1853 *
1856 1854 * Port mapper routines:
1857 1855 * pmap_kgetport() - get port number.
1858 1856 * pmap_rmt_call() - indirect call via port mapper.
1859 1857 *
1860 1858 */
1861 1859 static enum clnt_stat
1862 1860 pmap_kgetport(struct knetconfig *knconf, struct netbuf *call_addr,
1863 1861 rpcprog_t prog, rpcvers_t vers, rpcprot_t prot)
1864 1862 {
1865 1863 ushort_t port;
1866 1864 int tries;
1867 1865 enum clnt_stat stat;
1868 1866 struct pmap pmap_parms;
1869 1867 RPCB rpcb_parms;
1870 1868 char *ua = NULL;
1871 1869
1872 1870 port = 0;
1873 1871
1874 1872 ((struct sockaddr_in *)call_addr->buf)->sin_port = htons(PMAPPORT);
1875 1873
1876 1874 pmap_parms.pm_prog = prog;
1877 1875 pmap_parms.pm_vers = vers;
1878 1876 pmap_parms.pm_prot = prot;
1879 1877 pmap_parms.pm_port = 0;
1880 1878 for (tries = 0; tries < 5; tries++) {
1881 1879 stat = mycallrpc(knconf, call_addr,
1882 1880 PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
1883 1881 myxdr_pmap, (char *)&pmap_parms,
1884 1882 xdr_u_short, (char *)&port,
1885 1883 DEFAULT_TIMEO, DEFAULT_RETRIES);
1886 1884
1887 1885 if (stat != RPC_TIMEDOUT)
1888 1886 break;
1889 1887 cmn_err(CE_WARN,
1890 1888 "pmap_kgetport: Portmapper not responding; still trying");
1891 1889 }
1892 1890
1893 1891 if (stat == RPC_PROGUNAVAIL) {
1894 1892 cmn_err(CE_WARN,
1895 1893 "pmap_kgetport: Portmapper failed - trying rpcbind");
1896 1894
1897 1895 rpcb_parms.r_prog = prog;
1898 1896 rpcb_parms.r_vers = vers;
1899 1897 rpcb_parms.r_netid = knconf->knc_proto;
1900 1898 rpcb_parms.r_addr = rpcb_parms.r_owner = "";
1901 1899
1902 1900 for (tries = 0; tries < 5; tries++) {
1903 1901 stat = mycallrpc(knconf, call_addr,
1904 1902 RPCBPROG, RPCBVERS, RPCBPROC_GETADDR,
1905 1903 xdr_rpcb, (char *)&rpcb_parms,
1906 1904 xdr_wrapstring, (char *)&ua,
1907 1905 DEFAULT_TIMEO, DEFAULT_RETRIES);
1908 1906
1909 1907 if (stat != RPC_TIMEDOUT)
1910 1908 break;
1911 1909 cmn_err(CE_WARN,
1912 1910 "pmap_kgetport: rpcbind not responding; still trying");
1913 1911 }
1914 1912
1915 1913 if (stat == RPC_SUCCESS) {
1916 1914 if ((ua != NULL) && (ua[0] != NULL)) {
1917 1915 port = rpc_uaddr2port(AF_INET, ua);
1918 1916 } else {
1919 1917 /* Address unknown */
1920 1918 stat = RPC_PROGUNAVAIL;
1921 1919 }
1922 1920 }
1923 1921 }
1924 1922
1925 1923 if (stat == RPC_SUCCESS)
1926 1924 ((struct sockaddr_in *)call_addr->buf)->sin_port = ntohs(port);
1927 1925
1928 1926 return (stat);
1929 1927 }
1930 1928
1931 1929 /*
1932 1930 * pmapper remote-call-service interface.
1933 1931 * This routine is used to call the pmapper remote call service
1934 1932 * which will look up a service program in the port maps, and then
1935 1933 * remotely call that routine with the given parameters. This allows
1936 1934 * programs to do a lookup and call in one step. In addition to the call_addr,
1937 1935 * the caller provides a boolean hint about the destination address (TRUE if
1938 1936 * address is a broadcast address, FALSE otherwise).
1939 1937 *
1940 1938 * On return, `call addr' contains the port number for the
1941 1939 * service requested, and `resp_addr' contains its IP address.
1942 1940 */
1943 1941 static enum clnt_stat
1944 1942 pmap_rmt_call(struct knetconfig *knconf, struct netbuf *call_addr,
1945 1943 bool_t bcast, rpcprog_t progn, rpcvers_t versn, rpcproc_t procn,
1946 1944 xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp,
1947 1945 struct timeval tout, struct netbuf *resp_addr)
1948 1946 {
1949 1947 CLIENT *cl;
1950 1948 enum clnt_stat stat;
1951 1949 rpcport_t port;
1952 1950 int rc;
1953 1951 struct rmtcallargs pmap_args;
1954 1952 struct rmtcallres pmap_res;
1955 1953 struct rpcb_rmtcallargs rpcb_args;
1956 1954 struct rpcb_rmtcallres rpcb_res;
1957 1955 char ua[100]; /* XXX */
1958 1956
1959 1957 ((struct sockaddr_in *)call_addr->buf)->sin_port = htons(PMAPPORT);
1960 1958
1961 1959 rc = clnt_tli_kcreate(knconf, call_addr, PMAPPROG, PMAPVERS,
1962 1960 0, PMAP_RETRIES, CRED(), &cl);
1963 1961 if (rc != 0) {
1964 1962 nfs_perror(rc,
1965 1963 "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
1966 1964 return (RPC_SYSTEMERROR); /* XXX */
1967 1965 }
1968 1966 if (cl == (CLIENT *)NULL) {
1969 1967 panic("pmap_rmt_call: clnt_tli_kcreate failed");
1970 1968 /* NOTREACHED */
1971 1969 }
1972 1970
1973 1971 (void) CLNT_CONTROL(cl, CLSET_BCAST, (char *)&bcast);
1974 1972
1975 1973 pmap_args.prog = progn;
1976 1974 pmap_args.vers = versn;
1977 1975 pmap_args.proc = procn;
1978 1976 pmap_args.args_ptr = argsp;
1979 1977 pmap_args.xdr_args = xdrargs;
1980 1978 pmap_res.port_ptr = &port;
1981 1979 pmap_res.results_ptr = resp;
1982 1980 pmap_res.xdr_results = xdrres;
1983 1981 stat = clnt_clts_kcallit_addr(cl, PMAPPROC_CALLIT,
1984 1982 myxdr_rmtcall_args, (caddr_t)&pmap_args,
1985 1983 myxdr_rmtcallres, (caddr_t)&pmap_res,
1986 1984 tout, resp_addr);
1987 1985
1988 1986 if (stat == RPC_SUCCESS) {
1989 1987 ((struct sockaddr_in *)resp_addr->buf)->sin_port =
1990 1988 htons((ushort_t)port);
1991 1989 }
1992 1990 CLNT_DESTROY(cl);
1993 1991
1994 1992 if (stat != RPC_PROGUNAVAIL)
1995 1993 return (stat);
1996 1994
1997 1995 cmn_err(CE_WARN, "pmap_rmt_call: Portmapper failed - trying rpcbind");
1998 1996
1999 1997 rc = clnt_tli_kcreate(knconf, call_addr, RPCBPROG, RPCBVERS,
2000 1998 0, PMAP_RETRIES, CRED(), &cl);
2001 1999 if (rc != 0) {
2002 2000 nfs_perror(rc, "pmap_rmt_call: clnt_tli_kcreate failed: %m\n");
2003 2001 return (RPC_SYSTEMERROR); /* XXX */
2004 2002 }
2005 2003
2006 2004 if (cl == NULL) {
2007 2005 panic("pmap_rmt_call: clnt_tli_kcreate failed");
2008 2006 /* NOTREACHED */
2009 2007 }
2010 2008
2011 2009 rpcb_args.prog = progn;
2012 2010 rpcb_args.vers = versn;
2013 2011 rpcb_args.proc = procn;
2014 2012 rpcb_args.args_ptr = argsp;
2015 2013 rpcb_args.xdr_args = xdrargs;
2016 2014 rpcb_res.addr_ptr = ua;
2017 2015 rpcb_res.results_ptr = resp;
2018 2016 rpcb_res.xdr_results = xdrres;
2019 2017 stat = clnt_clts_kcallit_addr(cl, PMAPPROC_CALLIT,
2020 2018 xdr_rpcb_rmtcallargs, (caddr_t)&rpcb_args,
2021 2019 xdr_rpcb_rmtcallres, (caddr_t)&rpcb_res,
2022 2020 tout, resp_addr);
2023 2021
2024 2022 if (stat == RPC_SUCCESS)
2025 2023 ((struct sockaddr_in *)resp_addr->buf)->sin_port =
2026 2024 rpc_uaddr2port(AF_INET, ua);
2027 2025 CLNT_DESTROY(cl);
2028 2026
2029 2027 return (stat);
2030 2028 }
2031 2029
2032 2030 /*
2033 2031 * XDR remote call arguments
2034 2032 * written for XDR_ENCODE direction only
2035 2033 */
2036 2034 static bool_t
2037 2035 myxdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
2038 2036 {
2039 2037 uint_t lenposition;
2040 2038 uint_t argposition;
2041 2039 uint_t position;
2042 2040
2043 2041 if (xdr_rpcprog(xdrs, &(cap->prog)) &&
2044 2042 xdr_rpcvers(xdrs, &(cap->vers)) &&
2045 2043 xdr_rpcproc(xdrs, &(cap->proc))) {
2046 2044 lenposition = XDR_GETPOS(xdrs);
2047 2045 if (!xdr_u_int(xdrs, &cap->arglen))
2048 2046 return (FALSE);
2049 2047 argposition = XDR_GETPOS(xdrs);
2050 2048 if (!(*(cap->xdr_args))(xdrs, cap->args_ptr))
2051 2049 return (FALSE);
2052 2050 position = XDR_GETPOS(xdrs);
2053 2051 cap->arglen = (uint_t)position - (uint_t)argposition;
2054 2052 XDR_SETPOS(xdrs, lenposition);
2055 2053 if (!xdr_u_int(xdrs, &cap->arglen))
2056 2054 return (FALSE);
2057 2055 XDR_SETPOS(xdrs, position);
2058 2056 return (TRUE);
2059 2057 }
2060 2058 return (FALSE);
2061 2059 }
2062 2060
2063 2061 /*
2064 2062 * XDR remote call results
2065 2063 * written for XDR_DECODE direction only
2066 2064 */
2067 2065 static bool_t
2068 2066 myxdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp)
2069 2067 {
2070 2068 caddr_t port_ptr;
2071 2069
2072 2070 port_ptr = (caddr_t)crp->port_ptr;
2073 2071 if (xdr_reference(xdrs, &port_ptr, sizeof (uint_t), xdr_u_int) &&
2074 2072 xdr_u_int(xdrs, &crp->resultslen)) {
2075 2073 crp->port_ptr = (rpcport_t *)port_ptr;
2076 2074 return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
2077 2075 }
2078 2076 return (FALSE);
2079 2077 }
2080 2078
2081 2079 static bool_t
2082 2080 myxdr_pmap(XDR *xdrs, struct pmap *regs)
2083 2081 {
2084 2082 if (xdr_rpcprog(xdrs, ®s->pm_prog) &&
2085 2083 xdr_rpcvers(xdrs, ®s->pm_vers) &&
2086 2084 xdr_rpcprot(xdrs, ®s->pm_prot))
2087 2085 return (xdr_rpcport(xdrs, ®s->pm_port));
2088 2086
2089 2087 return (FALSE);
2090 2088 }
2091 2089
2092 2090 /*
2093 2091 * From SunOS callrpc.c
2094 2092 */
2095 2093 static enum clnt_stat
2096 2094 mycallrpc(struct knetconfig *knconf, struct netbuf *call_addr,
2097 2095 rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum,
2098 2096 xdrproc_t inproc, char *in, xdrproc_t outproc, char *out,
2099 2097 int timeo, int retries)
2100 2098 {
2101 2099 CLIENT *cl;
2102 2100 struct timeval tv;
2103 2101 enum clnt_stat cl_stat;
2104 2102 int rc;
2105 2103
2106 2104 rc = clnt_tli_kcreate(knconf, call_addr, prognum, versnum,
2107 2105 0, retries, CRED(), &cl);
2108 2106 if (rc) {
2109 2107 nfs_perror(rc, "mycallrpc: clnt_tli_kcreate failed: %m\n");
2110 2108 return (RPC_SYSTEMERROR); /* XXX */
2111 2109 }
2112 2110 tv.tv_sec = timeo;
2113 2111 tv.tv_usec = 0;
2114 2112 cl_stat = CLNT_CALL(cl, procnum, inproc, in, outproc, out, tv);
2115 2113 AUTH_DESTROY(cl->cl_auth);
2116 2114 CLNT_DESTROY(cl);
2117 2115 return (cl_stat);
2118 2116 }
2119 2117
2120 2118 /*
2121 2119 * Configure the 'default' interface based on existing boot properties.
2122 2120 */
2123 2121 static int
2124 2122 bp_netconfig(void)
2125 2123 {
2126 2124 char *str;
2127 2125 struct in_addr my_ip, my_netmask, my_router, my_broadcast;
2128 2126 struct sockaddr_in *sin;
2129 2127 TIUSER *tiptr;
2130 2128 int rc;
2131 2129 struct rtentry rtentry;
2132 2130
2133 2131 my_ip.s_addr = my_netmask.s_addr = my_router.s_addr = 0;
2134 2132
2135 2133 /*
2136 2134 * No way of getting this right now. Collude with dlifconfig()
2137 2135 * to let the protocol stack choose.
2138 2136 */
2139 2137 my_broadcast.s_addr = INADDR_BROADCAST;
2140 2138
2141 2139 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2142 2140 DDI_PROP_DONTPASS, BP_HOST_IP, &str) == DDI_SUCCESS) {
2143 2141 if (inet_aton(str, (uchar_t *)&my_ip) != 0)
2144 2142 cmn_err(CE_NOTE, "host-ip %s is invalid\n",
2145 2143 str);
2146 2144 ddi_prop_free(str);
2147 2145 if (dldebug)
2148 2146 printf("host ip is %s\n",
2149 2147 inet_ntoa(my_ip));
2150 2148 }
2151 2149 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2152 2150 DDI_PROP_DONTPASS, BP_SUBNET_MASK, &str) == DDI_SUCCESS) {
2153 2151 if (inet_aton(str, (uchar_t *)&my_netmask) != 0)
2154 2152 cmn_err(CE_NOTE, "subnet-mask %s is invalid\n",
2155 2153 str);
2156 2154 ddi_prop_free(str);
2157 2155 if (dldebug)
2158 2156 printf("subnet mask is %s\n",
2159 2157 inet_ntoa(my_netmask));
2160 2158 }
2161 2159 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2162 2160 DDI_PROP_DONTPASS, BP_ROUTER_IP, &str) == DDI_SUCCESS) {
2163 2161 if (inet_aton(str, (uchar_t *)&my_router) != 0)
2164 2162 cmn_err(CE_NOTE, "router-ip %s is invalid\n",
2165 2163 str);
2166 2164 ddi_prop_free(str);
2167 2165 if (dldebug)
2168 2166 printf("router ip is %s\n",
2169 2167 inet_ntoa(my_router));
2170 2168 }
2171 2169 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2172 2170 DDI_PROP_DONTPASS, BP_SERVER_PATH, &server_path_c);
2173 2171 (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2174 2172 DDI_PROP_DONTPASS, BP_SERVER_NAME, &server_name_c);
2175 2173 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2176 2174 DDI_PROP_DONTPASS, BP_SERVER_ROOTOPTS, &str) == DDI_SUCCESS) {
2177 2175 (void) strlcpy(rootopts, str, sizeof (rootopts));
2178 2176 ddi_prop_free(str);
2179 2177 }
2180 2178 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
2181 2179 DDI_PROP_DONTPASS, BP_SERVER_IP, &str) == DDI_SUCCESS) {
2182 2180 if (inet_aton(str, server_ip) != 0)
2183 2181 cmn_err(CE_NOTE, "server-ip %s is invalid\n",
2184 2182 str);
2185 2183 ddi_prop_free(str);
2186 2184 if (dldebug)
2187 2185 printf("server ip is %s\n",
2188 2186 inet_ntoa(*(struct in_addr *)server_ip));
2189 2187 }
2190 2188
2191 2189 /*
2192 2190 * We need all of these to configure based on properties.
2193 2191 */
2194 2192 if ((my_ip.s_addr == 0) ||
2195 2193 (my_netmask.s_addr == 0) ||
2196 2194 (server_path_c == NULL) ||
2197 2195 (server_name_c == NULL) ||
2198 2196 (*(uint_t *)server_ip == 0))
2199 2197 return (-1);
2200 2198
2201 2199 cmn_err(CE_CONT, "?IP address: %s\n", inet_ntoa(my_ip));
2202 2200 cmn_err(CE_CONT, "?IP netmask: %s\n", inet_ntoa(my_netmask));
2203 2201 if (my_router.s_addr != 0)
2204 2202 cmn_err(CE_CONT, "?IP router: %s\n", inet_ntoa(my_router));
2205 2203 cmn_err(CE_CONT, "?NFS server: %s (%s)\n", server_name_c,
2206 2204 inet_ntoa(*(struct in_addr *)server_ip));
2207 2205 cmn_err(CE_CONT, "?NFS path: %s\n", server_path_c);
2208 2206
2209 2207 /*
2210 2208 * Configure the interface.
2211 2209 */
2212 2210 if ((rc = t_kopen((file_t *)NULL, dl_udp_netconf.knc_rdev,
2213 2211 FREAD|FWRITE, &tiptr, CRED())) != 0) {
2214 2212 nfs_perror(rc, "bp_netconfig: t_kopen udp failed: %m.\n");
2215 2213 return (rc);
2216 2214 }
2217 2215
2218 2216 if ((rc = dlifconfig(tiptr, &my_ip, &my_netmask, &my_broadcast,
2219 2217 0)) < 0) {
2220 2218 nfs_perror(rc, "bp_netconfig: dlifconfig failed: %m.\n");
2221 2219 (void) t_kclose(tiptr, 0);
2222 2220 return (rc);
2223 2221 }
2224 2222
2225 2223 if (my_router.s_addr != 0) {
2226 2224 /*
2227 2225 * Add a default route.
2228 2226 */
2229 2227 sin = (struct sockaddr_in *)&rtentry.rt_dst;
2230 2228 bzero(sin, sizeof (*sin));
2231 2229 sin->sin_family = AF_INET;
2232 2230
2233 2231 sin = (struct sockaddr_in *)&rtentry.rt_gateway;
2234 2232 bzero(sin, sizeof (*sin));
2235 2233 sin->sin_family = AF_INET;
2236 2234 sin->sin_addr = my_router;
2237 2235
2238 2236 rtentry.rt_flags = RTF_GATEWAY | RTF_UP;
2239 2237
2240 2238 if ((rc = rtioctl(tiptr, SIOCADDRT, &rtentry)) != 0) {
2241 2239 nfs_perror(rc,
2242 2240 "bp_netconfig: couldn't add route: %m.\n");
2243 2241 (void) t_kclose(tiptr, 0);
2244 2242 return (rc);
2245 2243 }
2246 2244 }
2247 2245
2248 2246 (void) t_kclose(tiptr, 0);
2249 2247
2250 2248 return (0);
2251 2249 }
2252 2250
2253 2251 /*
2254 2252 * The network device we will use to boot from is plumbed. Extract the details
2255 2253 * from rootfs.
2256 2254 */
2257 2255 static void
2258 2256 init_config(void)
2259 2257 {
2260 2258 (void) strlcpy(ndev_path, rootfs.bo_devname, sizeof (ndev_path));
2261 2259 (void) strlcpy(ifname, rootfs.bo_ifname, sizeof (ifname));
2262 2260 ifunit = rootfs.bo_ppa;
2263 2261
2264 2262 /*
2265 2263 * Assumes only one linkage array element.
2266 2264 */
2267 2265 dl_udp_netconf.knc_rdev =
2268 2266 makedevice(clone_major, ddi_name_to_major("udp"));
2269 2267 dl_tcp_netconf.knc_rdev =
2270 2268 makedevice(clone_major, ddi_name_to_major("tcp"));
2271 2269
2272 2270 /*
2273 2271 * Now we bringup the interface.
2274 2272 * Try cached dhcp response first. If it fails, do rarp.
2275 2273 */
2276 2274 if ((bp_netconfig() != 0) &&
2277 2275 (dhcpinit() != 0) &&
2278 2276 (whoami() != 0))
2279 2277 cmn_err(CE_WARN,
2280 2278 "%s: no response from interface", ifname);
2281 2279 else if (dldebug)
2282 2280 printf("init_config: ifname %s is up\n", ifname);
2283 2281 }
2284 2282
2285 2283 /*
2286 2284 * These options are duplicated in cmd/fs.d/nfs/mount/mount.c
2287 2285 * Changes must be made to both lists.
2288 2286 */
2289 2287 static char *optlist[] = {
2290 2288 #define OPT_RO 0
2291 2289 MNTOPT_RO,
2292 2290 #define OPT_RW 1
2293 2291 MNTOPT_RW,
2294 2292 #define OPT_QUOTA 2
2295 2293 MNTOPT_QUOTA,
2296 2294 #define OPT_NOQUOTA 3
2297 2295 MNTOPT_NOQUOTA,
2298 2296 #define OPT_SOFT 4
2299 2297 MNTOPT_SOFT,
2300 2298 #define OPT_HARD 5
2301 2299 MNTOPT_HARD,
2302 2300 #define OPT_SUID 6
2303 2301 MNTOPT_SUID,
2304 2302 #define OPT_NOSUID 7
2305 2303 MNTOPT_NOSUID,
2306 2304 #define OPT_GRPID 8
2307 2305 MNTOPT_GRPID,
2308 2306 #define OPT_REMOUNT 9
2309 2307 MNTOPT_REMOUNT,
2310 2308 #define OPT_NOSUB 10
2311 2309 MNTOPT_NOSUB,
2312 2310 #define OPT_INTR 11
2313 2311 MNTOPT_INTR,
2314 2312 #define OPT_NOINTR 12
2315 2313 MNTOPT_NOINTR,
2316 2314 #define OPT_PORT 13
2317 2315 MNTOPT_PORT,
2318 2316 #define OPT_SECURE 14
2319 2317 MNTOPT_SECURE,
2320 2318 #define OPT_RSIZE 15
2321 2319 MNTOPT_RSIZE,
2322 2320 #define OPT_WSIZE 16
2323 2321 MNTOPT_WSIZE,
2324 2322 #define OPT_TIMEO 17
2325 2323 MNTOPT_TIMEO,
2326 2324 #define OPT_RETRANS 18
2327 2325 MNTOPT_RETRANS,
2328 2326 #define OPT_ACTIMEO 19
2329 2327 MNTOPT_ACTIMEO,
2330 2328 #define OPT_ACREGMIN 20
2331 2329 MNTOPT_ACREGMIN,
2332 2330 #define OPT_ACREGMAX 21
2333 2331 MNTOPT_ACREGMAX,
2334 2332 #define OPT_ACDIRMIN 22
2335 2333 MNTOPT_ACDIRMIN,
2336 2334 #define OPT_ACDIRMAX 23
2337 2335 MNTOPT_ACDIRMAX,
2338 2336 #define OPT_BG 24
2339 2337 MNTOPT_BG,
2340 2338 #define OPT_FG 25
2341 2339 MNTOPT_FG,
2342 2340 #define OPT_RETRY 26
2343 2341 MNTOPT_RETRY,
2344 2342 #define OPT_NOAC 27
2345 2343 MNTOPT_NOAC,
2346 2344 #define OPT_NOCTO 28
2347 2345 MNTOPT_NOCTO,
2348 2346 #define OPT_LLOCK 29
2349 2347 MNTOPT_LLOCK,
2350 2348 #define OPT_POSIX 30
2351 2349 MNTOPT_POSIX,
2352 2350 #define OPT_VERS 31
2353 2351 MNTOPT_VERS,
2354 2352 #define OPT_PROTO 32
2355 2353 MNTOPT_PROTO,
2356 2354 #define OPT_SEMISOFT 33
2357 2355 MNTOPT_SEMISOFT,
2358 2356 #define OPT_NOPRINT 34
2359 2357 MNTOPT_NOPRINT,
2360 2358 #define OPT_SEC 35
2361 2359 MNTOPT_SEC,
2362 2360 #define OPT_LARGEFILES 36
2363 2361 MNTOPT_LARGEFILES,
2364 2362 #define OPT_NOLARGEFILES 37
2365 2363 MNTOPT_NOLARGEFILES,
2366 2364 #define OPT_PUBLIC 38
2367 2365 MNTOPT_PUBLIC,
2368 2366 #define OPT_DIRECTIO 39
2369 2367 MNTOPT_FORCEDIRECTIO,
2370 2368 #define OPT_NODIRECTIO 40
2371 2369 MNTOPT_NOFORCEDIRECTIO,
2372 2370 #define OPT_XATTR 41
2373 2371 MNTOPT_XATTR,
2374 2372 #define OPT_NOXATTR 42
2375 2373 MNTOPT_NOXATTR,
2376 2374 #define OPT_DEVICES 43
2377 2375 MNTOPT_DEVICES,
2378 2376 #define OPT_NODEVICES 44
2379 2377 MNTOPT_NODEVICES,
2380 2378 #define OPT_SETUID 45
2381 2379 MNTOPT_SETUID,
2382 2380 #define OPT_NOSETUID 46
2383 2381 MNTOPT_NOSETUID,
2384 2382 #define OPT_EXEC 47
2385 2383 MNTOPT_EXEC,
2386 2384 #define OPT_NOEXEC 48
2387 2385 MNTOPT_NOEXEC,
2388 2386 NULL
2389 2387 };
2390 2388
2391 2389 static int
2392 2390 isdigit(int ch)
2393 2391 {
2394 2392 return (ch >= '0' && ch <= '9');
2395 2393 }
2396 2394
2397 2395 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
2398 2396 #define bad(val) (val == NULL || !isdigit(*val))
2399 2397
2400 2398 static int
2401 2399 atoi(const char *p)
2402 2400 {
2403 2401 int n;
2404 2402 int c, neg = 0;
2405 2403
2406 2404 if (!isdigit(c = *p)) {
2407 2405 while (isspace(c))
2408 2406 c = *++p;
2409 2407 switch (c) {
2410 2408 case '-':
2411 2409 neg++;
2412 2410 /* FALLTHROUGH */
2413 2411 case '+':
2414 2412 c = *++p;
2415 2413 }
2416 2414 if (!isdigit(c))
2417 2415 return (0);
2418 2416 }
2419 2417 for (n = '0' - c; isdigit(c = *++p); ) {
2420 2418 n *= 10; /* two steps to avoid unnecessary overflow */
2421 2419 n += '0' - c; /* accum neg to avoid surprises at MAX */
2422 2420 }
2423 2421 return (neg ? n : -n);
2424 2422 }
2425 2423
2426 2424 /*
2427 2425 * Default root read tsize XXX
2428 2426 */
2429 2427 int nfs_root_rsize = 8 * 1024; /* conservative for dumb NICs */
2430 2428 int nfs4_root_rsize = 32 * 1024; /* only runs on TCP be aggressive */
2431 2429
2432 2430 /*
2433 2431 * Default flags: NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT
2434 2432 */
2435 2433 int nfs_rootopts = NFSMNT_NOCTO|NFSMNT_LLOCK|NFSMNT_INT;
2436 2434
2437 2435 static int
2438 2436 init_mountopts(struct nfs_args *args, int version, struct knetconfig **dl_cf,
2439 2437 int *vfsflags)
2440 2438 {
2441 2439 char servername[SYS_NMLN];
2442 2440 static int first = 0;
2443 2441 struct netbuf server_address;
2444 2442 char *opts, *val;
2445 2443 int vers;
2446 2444 struct knetconfig *cf = *dl_cf;
2447 2445 char rootoptsbuf[256];
2448 2446
2449 2447 /*
2450 2448 * Set default mount options
2451 2449 */
2452 2450 args->flags = nfs_rootopts;
2453 2451 args->rsize = 0;
2454 2452 args->flags |= NFSMNT_ACREGMIN;
2455 2453 args->acregmin = ACMINMAX;
2456 2454 args->flags |= NFSMNT_ACREGMAX;
2457 2455 args->acregmax = ACMAXMAX;
2458 2456 args->flags |= NFSMNT_ACDIRMIN;
2459 2457 args->acdirmin = ACMINMAX;
2460 2458 args->flags |= NFSMNT_ACDIRMAX;
2461 2459 args->acdirmax = ACMAXMAX;
2462 2460
2463 2461 *vfsflags = 0;
2464 2462
2465 2463 /*
2466 2464 * Only look up the rootopts the first time, we store this in
2467 2465 * a static buffer but we are guaranteed to be single threaded
2468 2466 * and not reentrant.
2469 2467 */
2470 2468 if (first == 0) {
2471 2469 first++;
2472 2470
2473 2471 init_netbuf(&server_address);
2474 2472
2475 2473 if (getfile("rootopts", servername, &server_address,
2476 2474 rootopts)) {
2477 2475 rootopts[0] = '\0';
2478 2476 free_netbuf(&server_address);
2479 2477 goto sanity;
2480 2478 }
2481 2479 free_netbuf(&server_address);
2482 2480 }
2483 2481
2484 2482 if (dldebug)
2485 2483 printf("rootopts = %s\n", rootopts);
2486 2484
2487 2485 /*
2488 2486 * We have to preserve rootopts for second time.
2489 2487 */
2490 2488 (void) strncpy(rootoptsbuf, rootopts, sizeof (rootoptsbuf));
2491 2489 rootoptsbuf[sizeof (rootoptsbuf) - 1] = '\0';
2492 2490 opts = rootoptsbuf;
2493 2491 while (*opts) {
2494 2492 int opt;
2495 2493
2496 2494 switch (opt = getsubopt(&opts, optlist, &val)) {
2497 2495 /*
2498 2496 * Options that are defaults or meaningless so ignored
2499 2497 */
2500 2498 case OPT_QUOTA:
2501 2499 case OPT_NOQUOTA:
2502 2500 case OPT_SUID:
2503 2501 case OPT_DEVICES:
2504 2502 case OPT_SETUID:
2505 2503 case OPT_BG:
2506 2504 case OPT_FG:
2507 2505 case OPT_RETRY:
2508 2506 case OPT_POSIX:
2509 2507 case OPT_LARGEFILES:
2510 2508 case OPT_XATTR:
2511 2509 case OPT_NOXATTR:
2512 2510 case OPT_EXEC:
2513 2511 break;
2514 2512 case OPT_RO:
2515 2513 *vfsflags |= MS_RDONLY;
2516 2514 break;
2517 2515 case OPT_RW:
2518 2516 *vfsflags &= ~(MS_RDONLY);
2519 2517 break;
2520 2518 case OPT_SOFT:
2521 2519 args->flags |= NFSMNT_SOFT;
2522 2520 args->flags &= ~(NFSMNT_SEMISOFT);
2523 2521 break;
2524 2522 case OPT_SEMISOFT:
2525 2523 args->flags |= NFSMNT_SOFT;
2526 2524 args->flags |= NFSMNT_SEMISOFT;
2527 2525 break;
2528 2526 case OPT_HARD:
2529 2527 args->flags &= ~(NFSMNT_SOFT);
2530 2528 args->flags &= ~(NFSMNT_SEMISOFT);
2531 2529 break;
2532 2530 case OPT_NOSUID:
2533 2531 case OPT_NODEVICES:
2534 2532 case OPT_NOSETUID:
2535 2533 case OPT_NOEXEC:
2536 2534 cmn_err(CE_WARN,
2537 2535 "nfs_dlboot: may not set root partition %s",
2538 2536 optlist[opt]);
2539 2537 break;
2540 2538 case OPT_GRPID:
2541 2539 args->flags |= NFSMNT_GRPID;
2542 2540 break;
2543 2541 case OPT_REMOUNT:
2544 2542 cmn_err(CE_WARN,
2545 2543 "nfs_dlboot: may not remount root partition");
2546 2544 break;
2547 2545 case OPT_INTR:
2548 2546 args->flags |= NFSMNT_INT;
2549 2547 break;
2550 2548 case OPT_NOINTR:
2551 2549 args->flags &= ~(NFSMNT_INT);
2552 2550 break;
2553 2551 case OPT_NOAC:
2554 2552 args->flags |= NFSMNT_NOAC;
2555 2553 break;
2556 2554 case OPT_PORT:
2557 2555 cmn_err(CE_WARN,
2558 2556 "nfs_dlboot: may not change root port number");
2559 2557 break;
2560 2558 case OPT_SECURE:
2561 2559 cmn_err(CE_WARN,
2562 2560 "nfs_dlboot: root mounted auth_unix, secure ignored");
2563 2561 break;
2564 2562 case OPT_NOCTO:
2565 2563 args->flags |= NFSMNT_NOCTO;
2566 2564 break;
2567 2565 case OPT_RSIZE:
2568 2566 if (bad(val)) {
2569 2567 cmn_err(CE_WARN,
2570 2568 "nfs_dlboot: invalid option: rsize");
2571 2569 break;
2572 2570 }
2573 2571 args->flags |= NFSMNT_RSIZE;
2574 2572 args->rsize = atoi(val);
2575 2573 break;
2576 2574 case OPT_WSIZE:
2577 2575 if (bad(val)) {
2578 2576 cmn_err(CE_WARN,
2579 2577 "nfs_dlboot: invalid option: wsize");
2580 2578 break;
2581 2579 }
2582 2580 args->flags |= NFSMNT_WSIZE;
2583 2581 args->wsize = atoi(val);
2584 2582 break;
2585 2583 case OPT_TIMEO:
2586 2584 if (bad(val)) {
2587 2585 cmn_err(CE_WARN,
2588 2586 "nfs_dlboot: invalid option: timeo");
2589 2587 break;
2590 2588 }
2591 2589 args->flags |= NFSMNT_TIMEO;
2592 2590 args->timeo = atoi(val);
2593 2591 break;
2594 2592 case OPT_RETRANS:
2595 2593 if (bad(val)) {
2596 2594 cmn_err(CE_WARN,
2597 2595 "nfs_dlboot: invalid option: retrans");
2598 2596 break;
2599 2597 }
2600 2598 args->flags |= NFSMNT_RETRANS;
2601 2599 args->retrans = atoi(val);
2602 2600 break;
2603 2601 case OPT_ACTIMEO:
2604 2602 if (bad(val)) {
2605 2603 cmn_err(CE_WARN,
2606 2604 "nfs_dlboot: invalid option: actimeo");
2607 2605 break;
2608 2606 }
2609 2607 args->flags |= NFSMNT_ACDIRMAX;
2610 2608 args->flags |= NFSMNT_ACREGMAX;
2611 2609 args->flags |= NFSMNT_ACDIRMIN;
2612 2610 args->flags |= NFSMNT_ACREGMIN;
2613 2611 args->acdirmin = args->acregmin = args->acdirmax =
2614 2612 args->acregmax = atoi(val);
2615 2613 break;
2616 2614 case OPT_ACREGMIN:
2617 2615 if (bad(val)) {
2618 2616 cmn_err(CE_WARN,
2619 2617 "nfs_dlboot: invalid option: acregmin");
2620 2618 break;
2621 2619 }
2622 2620 args->flags |= NFSMNT_ACREGMIN;
2623 2621 args->acregmin = atoi(val);
2624 2622 break;
2625 2623 case OPT_ACREGMAX:
2626 2624 if (bad(val)) {
2627 2625 cmn_err(CE_WARN,
2628 2626 "nfs_dlboot: invalid option: acregmax");
2629 2627 break;
2630 2628 }
2631 2629 args->flags |= NFSMNT_ACREGMAX;
2632 2630 args->acregmax = atoi(val);
2633 2631 break;
2634 2632 case OPT_ACDIRMIN:
2635 2633 if (bad(val)) {
2636 2634 cmn_err(CE_WARN,
2637 2635 "nfs_dlboot: invalid option: acdirmin");
2638 2636 break;
2639 2637 }
2640 2638 args->flags |= NFSMNT_ACDIRMIN;
2641 2639 args->acdirmin = atoi(val);
2642 2640 break;
2643 2641 case OPT_ACDIRMAX:
2644 2642 if (bad(val)) {
2645 2643 cmn_err(CE_WARN,
2646 2644 "nfs_dlboot: invalid option: acdirmax");
2647 2645 break;
2648 2646 }
2649 2647 args->flags |= NFSMNT_ACDIRMAX;
2650 2648 args->acdirmax = atoi(val);
2651 2649 break;
2652 2650 case OPT_LLOCK:
2653 2651 args->flags |= NFSMNT_LLOCK;
2654 2652 break;
2655 2653 case OPT_VERS:
2656 2654 if (bad(val)) {
2657 2655 cmn_err(CE_WARN,
2658 2656 "nfs_dlboot: invalid option: vers");
2659 2657 break;
2660 2658 }
2661 2659 vers = atoi(val);
2662 2660 /*
2663 2661 * If the requested version is less than what we
2664 2662 * chose, pretend the chosen version doesn't exist
2665 2663 */
2666 2664 if (vers < version) {
2667 2665 return (EPROTONOSUPPORT);
2668 2666 }
2669 2667 if (vers > version) {
2670 2668 cmn_err(CE_WARN,
2671 2669 "nfs_dlboot: version %d unavailable",
2672 2670 vers);
2673 2671 return (EINVAL);
2674 2672 }
2675 2673 break;
2676 2674 case OPT_PROTO:
2677 2675 /*
2678 2676 * NFSv4 can only run over TCP, if they requested
2679 2677 * UDP pretend v4 doesn't exist, they might not have
2680 2678 * specified a version allowing a fallback to v2 or v3.
2681 2679 */
2682 2680 if (version == NFS_V4 && strcmp(val, NC_UDP) == 0)
2683 2681 return (EPROTONOSUPPORT);
2684 2682 /*
2685 2683 * TCP is always chosen over UDP, so if the
2686 2684 * requested is the same as the chosen either
2687 2685 * they chose TCP when available or UDP on a UDP
2688 2686 * only server.
2689 2687 */
2690 2688 if (strcmp(cf->knc_proto, val) == 0)
2691 2689 break;
2692 2690 /*
2693 2691 * If we chose UDP, they must have requested TCP
2694 2692 */
2695 2693 if (strcmp(cf->knc_proto, NC_TCP) != 0) {
2696 2694 cmn_err(CE_WARN,
2697 2695 "nfs_dlboot: TCP protocol unavailable");
2698 2696 return (EINVAL);
2699 2697 }
2700 2698 /*
2701 2699 * They can only have requested UDP
2702 2700 */
2703 2701 if (strcmp(val, NC_UDP) != 0) {
2704 2702 cmn_err(CE_WARN,
2705 2703 "nfs_dlboot: unknown protocol");
2706 2704 return (EINVAL);
2707 2705 }
2708 2706 *dl_cf = &dl_udp_netconf;
2709 2707 break;
2710 2708 case OPT_NOPRINT:
2711 2709 args->flags |= NFSMNT_NOPRINT;
2712 2710 break;
2713 2711 case OPT_NOLARGEFILES:
2714 2712 cmn_err(CE_WARN,
2715 2713 "nfs_dlboot: NFS can't support nolargefiles");
2716 2714 break;
2717 2715 case OPT_SEC:
2718 2716 cmn_err(CE_WARN,
2719 2717 "nfs_dlboot: root mounted auth_unix, sec ignored");
2720 2718 break;
2721 2719
2722 2720 case OPT_DIRECTIO:
2723 2721 args->flags |= NFSMNT_DIRECTIO;
2724 2722 break;
2725 2723
2726 2724 case OPT_NODIRECTIO:
2727 2725 args->flags &= ~(NFSMNT_DIRECTIO);
2728 2726 break;
2729 2727
2730 2728 default:
2731 2729 cmn_err(CE_WARN,
2732 2730 "nfs_dlboot: ignoring invalid option \"%s\"", val);
2733 2731 break;
2734 2732 }
2735 2733 }
2736 2734 sanity:
2737 2735 /*
2738 2736 * Set some sane limits on read size
2739 2737 */
2740 2738 if (!(args->flags & NFSMNT_RSIZE) || args->rsize == 0) {
2741 2739 /*
2742 2740 * Establish defaults
2743 2741 */
2744 2742 args->flags |= NFSMNT_RSIZE;
2745 2743 if (version == NFS_V4)
2746 2744 args->rsize = nfs4_root_rsize;
2747 2745 else
2748 2746 args->rsize = nfs_root_rsize;
2749 2747 return (0);
2750 2748 }
2751 2749 /*
2752 2750 * No less than 512 bytes, otherwise it will take forever to boot
2753 2751 */
2754 2752 if (args->rsize < 512)
2755 2753 args->rsize = 512;
2756 2754 /*
2757 2755 * If we are running over UDP, we cannot exceed 64KB, trim
2758 2756 * to 56KB to allow room for headers.
2759 2757 */
2760 2758 if (*dl_cf == &dl_udp_netconf && args->rsize > (56 * 1024))
2761 2759 args->rsize = 56 * 1024;
2762 2760 return (0);
2763 2761 }
↓ open down ↓ |
2512 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX