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