Print this page
3910 t_look(3NSL) should never return T_ERROR
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c
+++ new/usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright (c) 2012 by Delphix. All rights reserved.
25 25 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
26 + * Copyright 2014 Gary Mills
26 27 */
27 28
28 29
29 30 /*
30 31 * nfs_tbind.c, common part for nfsd and lockd.
31 32 */
32 33
33 34 #include <tiuser.h>
34 35 #include <fcntl.h>
35 36 #include <netconfig.h>
36 37 #include <stropts.h>
37 38 #include <errno.h>
38 39 #include <syslog.h>
39 40 #include <rpc/rpc.h>
40 41 #include <sys/time.h>
41 42 #include <sys/resource.h>
42 43 #include <signal.h>
43 44 #include <netdir.h>
44 45 #include <unistd.h>
45 46 #include <string.h>
46 47 #include <netinet/tcp.h>
47 48 #include <malloc.h>
48 49 #include <stdlib.h>
49 50 #include "nfs_tbind.h"
50 51 #include <nfs/nfs.h>
51 52 #include <nfs/nfs_acl.h>
52 53 #include <nfs/nfssys.h>
53 54 #include <nfs/nfs4.h>
54 55 #include <zone.h>
55 56 #include <sys/socket.h>
56 57 #include <tsol/label.h>
57 58
58 59 /*
59 60 * Determine valid semantics for most applications.
60 61 */
61 62 #define OK_TPI_TYPE(_nconf) \
62 63 (_nconf->nc_semantics == NC_TPI_CLTS || \
63 64 _nconf->nc_semantics == NC_TPI_COTS || \
64 65 _nconf->nc_semantics == NC_TPI_COTS_ORD)
65 66
66 67 #define BE32_TO_U32(a) \
67 68 ((((ulong_t)((uchar_t *)a)[0] & 0xFF) << (ulong_t)24) | \
68 69 (((ulong_t)((uchar_t *)a)[1] & 0xFF) << (ulong_t)16) | \
69 70 (((ulong_t)((uchar_t *)a)[2] & 0xFF) << (ulong_t)8) | \
70 71 ((ulong_t)((uchar_t *)a)[3] & 0xFF))
71 72
72 73 /*
73 74 * Number of elements to add to the poll array on each allocation.
74 75 */
75 76 #define POLL_ARRAY_INC_SIZE 64
76 77
77 78 /*
78 79 * Number of file descriptors by which the process soft limit may be
79 80 * increased on each call to nofile_increase(0).
80 81 */
81 82 #define NOFILE_INC_SIZE 64
82 83
83 84 /*
84 85 * Default TCP send and receive buffer size of NFS server.
85 86 */
86 87 #define NFSD_TCP_BUFSZ (1024*1024)
87 88
88 89 struct conn_ind {
89 90 struct conn_ind *conn_next;
90 91 struct conn_ind *conn_prev;
91 92 struct t_call *conn_call;
92 93 };
93 94
94 95 struct conn_entry {
95 96 bool_t closing;
96 97 struct netconfig nc;
97 98 };
98 99
99 100 /*
100 101 * this file contains transport routines common to nfsd and lockd
101 102 */
102 103 static int nofile_increase(int);
103 104 static int reuseaddr(int);
104 105 static int recvucred(int);
105 106 static int anonmlp(int);
106 107 static void add_to_poll_list(int, struct netconfig *);
107 108 static char *serv_name_to_port_name(char *);
108 109 static int bind_to_proto(char *, char *, struct netbuf **,
109 110 struct netconfig **);
110 111 static int bind_to_provider(char *, char *, struct netbuf **,
111 112 struct netconfig **);
112 113 static void conn_close_oldest(void);
113 114 static boolean_t conn_get(int, struct netconfig *, struct conn_ind **);
114 115 static void cots_listen_event(int, int);
115 116 static int discon_get(int, struct netconfig *, struct conn_ind **);
116 117 static int do_poll_clts_action(int, int);
117 118 static int do_poll_cots_action(int, int);
118 119 static void remove_from_poll_list(int);
119 120 static int set_addrmask(int, struct netconfig *, struct netbuf *);
120 121 static int is_listen_fd_index(int);
121 122
122 123 static struct pollfd *poll_array;
123 124 static struct conn_entry *conn_polled;
124 125 static int num_conns; /* Current number of connections */
125 126 int (*Mysvc4)(int, struct netbuf *, struct netconfig *, int,
126 127 struct netbuf *);
127 128 static int setopt(int fd, int level, int name, int value);
128 129 static int get_opt(int fd, int level, int name);
129 130 static void nfslib_set_sockbuf(int fd);
130 131
131 132 /*
132 133 * Called to create and prepare a transport descriptor for in-kernel
133 134 * RPC service.
134 135 * Returns -1 on failure and a valid descriptor on success.
135 136 */
136 137 int
137 138 nfslib_transport_open(struct netconfig *nconf)
138 139 {
139 140 int fd;
140 141 struct strioctl strioc;
141 142
142 143 if ((nconf == (struct netconfig *)NULL) ||
143 144 (nconf->nc_device == (char *)NULL)) {
144 145 syslog(LOG_ERR, "no netconfig device");
145 146 return (-1);
146 147 }
147 148
148 149 /*
149 150 * Open the transport device.
150 151 */
151 152 fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
152 153 if (fd == -1) {
153 154 if (t_errno == TSYSERR && errno == EMFILE &&
154 155 (nofile_increase(0) == 0)) {
155 156 /* Try again with a higher NOFILE limit. */
156 157 fd = t_open(nconf->nc_device, O_RDWR,
157 158 (struct t_info *)NULL);
158 159 }
159 160 if (fd == -1) {
160 161 syslog(LOG_ERR, "t_open %s failed: t_errno %d, %m",
161 162 nconf->nc_device, t_errno);
162 163 return (-1);
163 164 }
164 165 }
165 166
166 167 /*
167 168 * Pop timod because the RPC module must be as close as possible
168 169 * to the transport.
169 170 */
170 171 if (ioctl(fd, I_POP, 0) < 0) {
171 172 syslog(LOG_ERR, "I_POP of timod failed: %m");
172 173 (void) t_close(fd);
173 174 return (-1);
174 175 }
175 176
176 177 /*
177 178 * Common code for CLTS and COTS transports
178 179 */
179 180 if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
180 181 syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m");
181 182 (void) t_close(fd);
182 183 return (-1);
183 184 }
184 185
185 186 strioc.ic_cmd = RPC_SERVER;
186 187 strioc.ic_dp = (char *)0;
187 188 strioc.ic_len = 0;
188 189 strioc.ic_timout = -1;
189 190
190 191 /* Tell rpcmod to act like a server stream. */
191 192 if (ioctl(fd, I_STR, &strioc) < 0) {
192 193 syslog(LOG_ERR, "rpcmod set-up ioctl failed: %m");
193 194 (void) t_close(fd);
194 195 return (-1);
195 196 }
196 197
197 198 /*
198 199 * Re-push timod so that we will still be doing TLI
199 200 * operations on the descriptor.
200 201 */
201 202 if (ioctl(fd, I_PUSH, "timod") < 0) {
202 203 syslog(LOG_ERR, "I_PUSH of timod failed: %m");
203 204 (void) t_close(fd);
204 205 return (-1);
205 206 }
206 207
207 208 /*
208 209 * Enable options of returning the ip's for udp.
209 210 */
210 211 if (strcmp(nconf->nc_netid, "udp6") == 0)
211 212 __rpc_tli_set_options(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1);
212 213 else if (strcmp(nconf->nc_netid, "udp") == 0)
213 214 __rpc_tli_set_options(fd, IPPROTO_IP, IP_RECVDSTADDR, 1);
214 215
215 216 return (fd);
216 217 }
217 218
218 219 static int
219 220 nofile_increase(int limit)
220 221 {
221 222 struct rlimit rl;
222 223
223 224 if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
224 225 syslog(LOG_ERR, "getrlimit of NOFILE failed: %m");
225 226 return (-1);
226 227 }
227 228
228 229 if (limit > 0)
229 230 rl.rlim_cur = limit;
230 231 else
231 232 rl.rlim_cur += NOFILE_INC_SIZE;
232 233
233 234 if (rl.rlim_cur > rl.rlim_max &&
234 235 rl.rlim_max != RLIM_INFINITY)
235 236 rl.rlim_max = rl.rlim_cur;
236 237
237 238 if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
238 239 syslog(LOG_ERR, "setrlimit of NOFILE to %d failed: %m",
239 240 rl.rlim_cur);
240 241 return (-1);
241 242 }
242 243
243 244 return (0);
244 245 }
245 246
246 247 static void
247 248 nfslib_set_sockbuf(int fd)
248 249 {
249 250 int curval, val;
250 251
251 252 val = NFSD_TCP_BUFSZ;
252 253
253 254 curval = get_opt(fd, SOL_SOCKET, SO_SNDBUF);
254 255 syslog(LOG_DEBUG, "Current SO_SNDBUF value is %d", curval);
255 256 if ((curval != -1) && (curval < val)) {
256 257 syslog(LOG_DEBUG, "Set SO_SNDBUF option to %d", val);
257 258 if (setopt(fd, SOL_SOCKET, SO_SNDBUF, val) < 0) {
258 259 syslog(LOG_ERR,
259 260 "couldn't set SO_SNDBUF to %d - t_errno = %d",
260 261 val, t_errno);
261 262 syslog(LOG_ERR,
262 263 "Check and increase system-wide tcp_max_buf");
263 264 }
264 265 }
265 266
266 267 curval = get_opt(fd, SOL_SOCKET, SO_RCVBUF);
267 268 syslog(LOG_DEBUG, "Current SO_RCVBUF value is %d", curval);
268 269 if ((curval != -1) && (curval < val)) {
269 270 syslog(LOG_DEBUG, "Set SO_RCVBUF option to %d", val);
270 271 if (setopt(fd, SOL_SOCKET, SO_RCVBUF, val) < 0) {
271 272 syslog(LOG_ERR,
272 273 "couldn't set SO_RCVBUF to %d - t_errno = %d",
273 274 val, t_errno);
274 275 syslog(LOG_ERR,
275 276 "Check and increase system-wide tcp_max_buf");
276 277 }
277 278 }
278 279 }
279 280
280 281 int
281 282 nfslib_bindit(struct netconfig *nconf, struct netbuf **addr,
282 283 struct nd_hostserv *hs, int backlog)
283 284 {
284 285 int fd;
285 286 struct t_bind *ntb;
286 287 struct t_bind tb;
287 288 struct nd_addrlist *addrlist;
288 289 struct t_optmgmt req, resp;
289 290 struct opthdr *opt;
290 291 char reqbuf[128];
291 292 bool_t use_any = FALSE;
292 293 bool_t gzone = TRUE;
293 294
294 295 if ((fd = nfslib_transport_open(nconf)) == -1) {
295 296 syslog(LOG_ERR, "cannot establish transport service over %s",
296 297 nconf->nc_device);
297 298 return (-1);
298 299 }
299 300
300 301 addrlist = (struct nd_addrlist *)NULL;
301 302
302 303 /* nfs4_callback service does not used a fieed port number */
303 304
304 305 if (strcmp(hs->h_serv, "nfs4_callback") == 0) {
305 306 tb.addr.maxlen = 0;
306 307 tb.addr.len = 0;
307 308 tb.addr.buf = 0;
308 309 use_any = TRUE;
309 310 gzone = (getzoneid() == GLOBAL_ZONEID);
310 311 } else if (netdir_getbyname(nconf, hs, &addrlist) != 0) {
311 312
312 313 syslog(LOG_ERR,
313 314 "Cannot get address for transport %s host %s service %s",
314 315 nconf->nc_netid, hs->h_host, hs->h_serv);
315 316 (void) t_close(fd);
316 317 return (-1);
317 318 }
318 319
319 320 if (strcmp(nconf->nc_proto, "tcp") == 0) {
320 321 /*
321 322 * If we're running over TCP, then set the
322 323 * SO_REUSEADDR option so that we can bind
323 324 * to our preferred address even if previously
324 325 * left connections exist in FIN_WAIT states.
325 326 * This is somewhat bogus, but otherwise you have
326 327 * to wait 2 minutes to restart after killing it.
327 328 */
328 329 if (reuseaddr(fd) == -1) {
329 330 syslog(LOG_WARNING,
330 331 "couldn't set SO_REUSEADDR option on transport");
331 332 }
332 333 } else if (strcmp(nconf->nc_proto, "udp") == 0) {
333 334 /*
334 335 * In order to run MLP on UDP, we need to handle creds.
335 336 */
336 337 if (recvucred(fd) == -1) {
337 338 syslog(LOG_WARNING,
338 339 "couldn't set SO_RECVUCRED option on transport");
339 340 }
340 341 }
341 342
342 343 /*
343 344 * Make non global zone nfs4_callback port MLP
344 345 */
345 346 if (use_any && is_system_labeled() && !gzone) {
346 347 if (anonmlp(fd) == -1) {
347 348 /*
348 349 * failing to set this option means nfs4_callback
349 350 * could fail silently later. So fail it with
350 351 * with an error message now.
351 352 */
352 353 syslog(LOG_ERR,
353 354 "couldn't set SO_ANON_MLP option on transport");
354 355 (void) t_close(fd);
355 356 return (-1);
356 357 }
357 358 }
358 359
359 360 if (nconf->nc_semantics == NC_TPI_CLTS)
360 361 tb.qlen = 0;
361 362 else
362 363 tb.qlen = backlog;
363 364
364 365 /* LINTED pointer alignment */
365 366 ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL);
366 367 if (ntb == (struct t_bind *)NULL) {
367 368 syslog(LOG_ERR, "t_alloc failed: t_errno %d, %m", t_errno);
368 369 (void) t_close(fd);
369 370 netdir_free((void *)addrlist, ND_ADDRLIST);
370 371 return (-1);
371 372 }
372 373
373 374 /*
374 375 * XXX - what about the space tb->addr.buf points to? This should
375 376 * be either a memcpy() to/from the buf fields, or t_alloc(fd,T_BIND,)
376 377 * should't be called with T_ALL.
377 378 */
378 379 if (addrlist)
379 380 tb.addr = *(addrlist->n_addrs); /* structure copy */
380 381
381 382 if (t_bind(fd, &tb, ntb) == -1) {
382 383 syslog(LOG_ERR, "t_bind failed: t_errno %d, %m", t_errno);
383 384 (void) t_free((char *)ntb, T_BIND);
384 385 netdir_free((void *)addrlist, ND_ADDRLIST);
385 386 (void) t_close(fd);
386 387 return (-1);
387 388 }
388 389
389 390 /* make sure we bound to the right address */
390 391 if (use_any == FALSE &&
391 392 (tb.addr.len != ntb->addr.len ||
392 393 memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0)) {
393 394 syslog(LOG_ERR, "t_bind to wrong address");
394 395 (void) t_free((char *)ntb, T_BIND);
395 396 netdir_free((void *)addrlist, ND_ADDRLIST);
396 397 (void) t_close(fd);
397 398 return (-1);
398 399 }
399 400
400 401 /*
401 402 * Call nfs4svc_setport so that the kernel can be
402 403 * informed what port number the daemon is listing
403 404 * for incoming connection requests.
404 405 */
405 406
406 407 if ((nconf->nc_semantics == NC_TPI_COTS ||
407 408 nconf->nc_semantics == NC_TPI_COTS_ORD) && Mysvc4 != NULL)
408 409 (*Mysvc4)(fd, NULL, nconf, NFS4_SETPORT, &ntb->addr);
409 410
410 411 *addr = &ntb->addr;
411 412 netdir_free((void *)addrlist, ND_ADDRLIST);
412 413
413 414 if (strcmp(nconf->nc_proto, "tcp") == 0) {
414 415 /*
415 416 * Disable the Nagle algorithm on TCP connections.
416 417 * Connections accepted from this listener will
417 418 * inherit the listener options.
418 419 */
419 420
420 421 /* LINTED pointer alignment */
421 422 opt = (struct opthdr *)reqbuf;
422 423 opt->level = IPPROTO_TCP;
423 424 opt->name = TCP_NODELAY;
424 425 opt->len = sizeof (int);
425 426
426 427 /* LINTED pointer alignment */
427 428 *(int *)((char *)opt + sizeof (*opt)) = 1;
428 429
429 430 req.flags = T_NEGOTIATE;
430 431 req.opt.len = sizeof (*opt) + opt->len;
431 432 req.opt.buf = (char *)opt;
432 433 resp.flags = 0;
433 434 resp.opt.buf = reqbuf;
434 435 resp.opt.maxlen = sizeof (reqbuf);
435 436
436 437 if (t_optmgmt(fd, &req, &resp) < 0 ||
437 438 resp.flags != T_SUCCESS) {
438 439 syslog(LOG_ERR,
439 440 "couldn't set NODELAY option for proto %s: t_errno = %d, %m",
440 441 nconf->nc_proto, t_errno);
441 442 }
442 443
443 444 nfslib_set_sockbuf(fd);
444 445 }
445 446
446 447 return (fd);
447 448 }
448 449
449 450 static int
450 451 get_opt(int fd, int level, int name)
451 452 {
452 453 struct t_optmgmt req, res;
453 454 struct {
454 455 struct opthdr opt;
455 456 int value;
456 457 } reqbuf;
457 458
458 459 reqbuf.opt.level = level;
459 460 reqbuf.opt.name = name;
460 461 reqbuf.opt.len = sizeof (int);
461 462 reqbuf.value = 0;
462 463
463 464 req.flags = T_CURRENT;
464 465 req.opt.len = sizeof (reqbuf);
465 466 req.opt.buf = (char *)&reqbuf;
466 467
467 468 res.flags = 0;
468 469 res.opt.buf = (char *)&reqbuf;
469 470 res.opt.maxlen = sizeof (reqbuf);
470 471
471 472 if (t_optmgmt(fd, &req, &res) < 0 || res.flags != T_SUCCESS) {
472 473 t_error("t_optmgmt");
473 474 return (-1);
474 475 }
475 476 return (reqbuf.value);
476 477 }
477 478
478 479 static int
479 480 setopt(int fd, int level, int name, int value)
480 481 {
481 482 struct t_optmgmt req, resp;
482 483 struct {
483 484 struct opthdr opt;
484 485 int value;
485 486 } reqbuf;
486 487
487 488 reqbuf.opt.level = level;
488 489 reqbuf.opt.name = name;
489 490 reqbuf.opt.len = sizeof (int);
490 491
491 492 reqbuf.value = value;
492 493
493 494 req.flags = T_NEGOTIATE;
494 495 req.opt.len = sizeof (reqbuf);
495 496 req.opt.buf = (char *)&reqbuf;
496 497
497 498 resp.flags = 0;
498 499 resp.opt.buf = (char *)&reqbuf;
499 500 resp.opt.maxlen = sizeof (reqbuf);
500 501
501 502 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
502 503 t_error("t_optmgmt");
503 504 return (-1);
504 505 }
505 506 return (0);
506 507 }
507 508
508 509 static int
509 510 reuseaddr(int fd)
510 511 {
511 512 return (setopt(fd, SOL_SOCKET, SO_REUSEADDR, 1));
512 513 }
513 514
514 515 static int
515 516 recvucred(int fd)
516 517 {
517 518 return (setopt(fd, SOL_SOCKET, SO_RECVUCRED, 1));
518 519 }
519 520
520 521 static int
521 522 anonmlp(int fd)
522 523 {
523 524 return (setopt(fd, SOL_SOCKET, SO_ANON_MLP, 1));
524 525 }
525 526
526 527 void
527 528 nfslib_log_tli_error(char *tli_name, int fd, struct netconfig *nconf)
528 529 {
529 530 int error;
530 531
531 532 /*
532 533 * Save the error code across syslog(), just in case syslog()
533 534 * gets its own error and, therefore, overwrites errno.
534 535 */
535 536 error = errno;
536 537 if (t_errno == TSYSERR) {
537 538 syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m",
538 539 tli_name, fd, nconf->nc_proto);
539 540 } else {
540 541 syslog(LOG_ERR,
541 542 "%s(file descriptor %d/transport %s) TLI error %d",
542 543 tli_name, fd, nconf->nc_proto, t_errno);
543 544 }
544 545 errno = error;
545 546 }
546 547
547 548 /*
548 549 * Called to set up service over a particular transport.
549 550 */
550 551 void
551 552 do_one(char *provider, NETSELDECL(proto), struct protob *protobp0,
552 553 int (*svc)(int, struct netbuf, struct netconfig *))
553 554 {
554 555 register int sock;
555 556 struct protob *protobp;
556 557 struct netbuf *retaddr;
557 558 struct netconfig *retnconf;
558 559 struct netbuf addrmask;
559 560 int vers;
560 561 int err;
561 562 int l;
562 563
563 564 if (provider)
564 565 sock = bind_to_provider(provider, protobp0->serv, &retaddr,
565 566 &retnconf);
566 567 else
567 568 sock = bind_to_proto(proto, protobp0->serv, &retaddr,
568 569 &retnconf);
569 570
570 571 if (sock == -1) {
571 572 (void) syslog(LOG_ERR,
572 573 "Cannot establish %s service over %s: transport setup problem.",
573 574 protobp0->serv, provider ? provider : proto);
574 575 return;
575 576 }
576 577
577 578 if (set_addrmask(sock, retnconf, &addrmask) < 0) {
578 579 (void) syslog(LOG_ERR,
579 580 "Cannot set address mask for %s", retnconf->nc_netid);
580 581 return;
581 582 }
582 583
583 584 /*
584 585 * Register all versions of the programs in the protocol block list.
585 586 */
586 587 l = strlen(NC_UDP);
587 588 for (protobp = protobp0; protobp; protobp = protobp->next) {
588 589 for (vers = protobp->versmin; vers <= protobp->versmax;
589 590 vers++) {
590 591 if ((protobp->program == NFS_PROGRAM ||
591 592 protobp->program == NFS_ACL_PROGRAM) &&
592 593 vers == NFS_V4 &&
593 594 strncasecmp(retnconf->nc_proto, NC_UDP, l) == 0)
594 595 continue;
595 596
596 597 (void) rpcb_unset(protobp->program, vers, retnconf);
597 598 (void) rpcb_set(protobp->program, vers, retnconf,
598 599 retaddr);
599 600 }
600 601 }
601 602
602 603 /*
603 604 * Register services with CLTS semantics right now.
604 605 * Note: services with COTS/COTS_ORD semantics will be
605 606 * registered later from cots_listen_event function.
606 607 */
607 608 if (retnconf->nc_semantics == NC_TPI_CLTS) {
608 609 /* Don't drop core if supporting module(s) aren't loaded. */
609 610 (void) signal(SIGSYS, SIG_IGN);
610 611
611 612 /*
612 613 * svc() doesn't block, it returns success or failure.
613 614 */
614 615
615 616 if (svc == NULL && Mysvc4 != NULL)
616 617 err = (*Mysvc4)(sock, &addrmask, retnconf,
617 618 NFS4_SETPORT|NFS4_KRPC_START, retaddr);
618 619 else
619 620 err = (*svc)(sock, addrmask, retnconf);
620 621
621 622 if (err < 0) {
622 623 (void) syslog(LOG_ERR,
623 624 "Cannot establish %s service over <file desc."
624 625 " %d, protocol %s> : %m. Exiting",
625 626 protobp0->serv, sock, retnconf->nc_proto);
626 627 exit(1);
627 628 }
628 629 }
629 630 free(addrmask.buf);
630 631
631 632 /*
632 633 * We successfully set up the server over this transport.
633 634 * Add this descriptor to the one being polled on.
634 635 */
635 636 add_to_poll_list(sock, retnconf);
636 637 }
637 638
638 639 /*
639 640 * Set up the NFS service over all the available transports.
640 641 * Returns -1 for failure, 0 for success.
641 642 */
642 643 int
643 644 do_all(struct protob *protobp,
644 645 int (*svc)(int, struct netbuf, struct netconfig *))
645 646 {
646 647 struct netconfig *nconf;
647 648 NCONF_HANDLE *nc;
648 649 int l;
649 650
650 651 if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
651 652 syslog(LOG_ERR, "setnetconfig failed: %m");
652 653 return (-1);
653 654 }
654 655 l = strlen(NC_UDP);
655 656 while (nconf = getnetconfig(nc)) {
656 657 if ((nconf->nc_flag & NC_VISIBLE) &&
657 658 strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 &&
658 659 OK_TPI_TYPE(nconf) &&
659 660 (protobp->program != NFS4_CALLBACK ||
660 661 strncasecmp(nconf->nc_proto, NC_UDP, l) != 0))
661 662 do_one(nconf->nc_device, nconf->nc_proto,
662 663 protobp, svc);
663 664 }
664 665 (void) endnetconfig(nc);
665 666 return (0);
666 667 }
667 668
668 669 /*
669 670 * poll on the open transport descriptors for events and errors.
670 671 */
671 672 void
672 673 poll_for_action(void)
673 674 {
674 675 int nfds;
675 676 int i;
676 677
677 678 /*
678 679 * Keep polling until all transports have been closed. When this
679 680 * happens, we return.
680 681 */
681 682 while ((int)num_fds > 0) {
682 683 nfds = poll(poll_array, num_fds, INFTIM);
683 684 switch (nfds) {
684 685 case 0:
685 686 continue;
686 687
687 688 case -1:
688 689 /*
689 690 * Some errors from poll could be
690 691 * due to temporary conditions, and we try to
691 692 * be robust in the face of them. Other
692 693 * errors (should never happen in theory)
693 694 * are fatal (eg. EINVAL, EFAULT).
694 695 */
695 696 switch (errno) {
696 697 case EINTR:
697 698 continue;
698 699
699 700 case EAGAIN:
700 701 case ENOMEM:
701 702 (void) sleep(10);
702 703 continue;
703 704
704 705 default:
705 706 (void) syslog(LOG_ERR,
706 707 "poll failed: %m. Exiting");
707 708 exit(1);
708 709 }
709 710 default:
710 711 break;
711 712 }
712 713
713 714 /*
714 715 * Go through the poll list looking for events.
715 716 */
716 717 for (i = 0; i < num_fds && nfds > 0; i++) {
717 718 if (poll_array[i].revents) {
718 719 nfds--;
719 720 /*
720 721 * We have a message, so try to read it.
721 722 * Record the error return in errno,
722 723 * so that syslog(LOG_ERR, "...%m")
723 724 * dumps the corresponding error string.
724 725 */
725 726 if (conn_polled[i].nc.nc_semantics ==
726 727 NC_TPI_CLTS) {
727 728 errno = do_poll_clts_action(
728 729 poll_array[i].fd, i);
729 730 } else {
730 731 errno = do_poll_cots_action(
731 732 poll_array[i].fd, i);
732 733 }
733 734
734 735 if (errno == 0)
735 736 continue;
736 737 /*
737 738 * Most returned error codes mean that there is
738 739 * fatal condition which we can only deal with
739 740 * by closing the transport.
740 741 */
741 742 if (errno != EAGAIN && errno != ENOMEM) {
742 743 (void) syslog(LOG_ERR,
743 744 "Error (%m) reading descriptor %d/transport %s. Closing it.",
744 745 poll_array[i].fd,
745 746 conn_polled[i].nc.nc_proto);
746 747 (void) t_close(poll_array[i].fd);
747 748 remove_from_poll_list(poll_array[i].fd);
748 749
749 750 } else if (errno == ENOMEM)
750 751 (void) sleep(5);
751 752 }
752 753 }
753 754 }
754 755
755 756 (void) syslog(LOG_ERR,
756 757 "All transports have been closed with errors. Exiting.");
757 758 }
758 759
759 760 /*
760 761 * Allocate poll/transport array entries for this descriptor.
761 762 */
762 763 static void
763 764 add_to_poll_list(int fd, struct netconfig *nconf)
764 765 {
765 766 static int poll_array_size = 0;
766 767
767 768 /*
768 769 * If the arrays are full, allocate new ones.
769 770 */
770 771 if (num_fds == poll_array_size) {
771 772 struct pollfd *tpa;
772 773 struct conn_entry *tnp;
773 774
774 775 if (poll_array_size != 0) {
775 776 tpa = poll_array;
776 777 tnp = conn_polled;
777 778 } else
778 779 tpa = (struct pollfd *)0;
779 780
780 781 poll_array_size += POLL_ARRAY_INC_SIZE;
781 782 /*
782 783 * Allocate new arrays.
783 784 */
784 785 poll_array = (struct pollfd *)
785 786 malloc(poll_array_size * sizeof (struct pollfd) + 256);
786 787 conn_polled = (struct conn_entry *)
787 788 malloc(poll_array_size * sizeof (struct conn_entry) + 256);
788 789 if (poll_array == (struct pollfd *)NULL ||
789 790 conn_polled == (struct conn_entry *)NULL) {
790 791 syslog(LOG_ERR, "malloc failed for poll array");
791 792 exit(1);
792 793 }
793 794
794 795 /*
795 796 * Copy the data of the old ones into new arrays, and
796 797 * free the old ones.
797 798 */
798 799 if (tpa) {
799 800 (void) memcpy((void *)poll_array, (void *)tpa,
800 801 num_fds * sizeof (struct pollfd));
801 802 (void) memcpy((void *)conn_polled, (void *)tnp,
802 803 num_fds * sizeof (struct conn_entry));
803 804 free((void *)tpa);
804 805 free((void *)tnp);
805 806 }
806 807 }
807 808
808 809 /*
809 810 * Set the descriptor and event list. All possible events are
810 811 * polled for.
811 812 */
812 813 poll_array[num_fds].fd = fd;
813 814 poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI;
814 815
815 816 /*
816 817 * Copy the transport data over too.
817 818 */
818 819 conn_polled[num_fds].nc = *nconf;
819 820 conn_polled[num_fds].closing = 0;
820 821
821 822 /*
822 823 * Set the descriptor to non-blocking. Avoids a race
823 824 * between data arriving on the stream and then having it
824 825 * flushed before we can read it.
825 826 */
826 827 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
827 828 (void) syslog(LOG_ERR,
828 829 "fcntl(file desc. %d/transport %s, F_SETFL, O_NONBLOCK): %m. Exiting",
829 830 num_fds, nconf->nc_proto);
830 831 exit(1);
831 832 }
832 833
833 834 /*
834 835 * Count this descriptor.
835 836 */
836 837 ++num_fds;
837 838 }
838 839
839 840 static void
840 841 remove_from_poll_list(int fd)
841 842 {
842 843 int i;
843 844 int num_to_copy;
844 845
845 846 for (i = 0; i < num_fds; i++) {
846 847 if (poll_array[i].fd == fd) {
847 848 --num_fds;
848 849 num_to_copy = num_fds - i;
849 850 (void) memcpy((void *)&poll_array[i],
850 851 (void *)&poll_array[i+1],
851 852 num_to_copy * sizeof (struct pollfd));
852 853 (void) memset((void *)&poll_array[num_fds], 0,
853 854 sizeof (struct pollfd));
854 855 (void) memcpy((void *)&conn_polled[i],
855 856 (void *)&conn_polled[i+1],
856 857 num_to_copy * sizeof (struct conn_entry));
857 858 (void) memset((void *)&conn_polled[num_fds], 0,
858 859 sizeof (struct conn_entry));
859 860 return;
860 861 }
861 862 }
862 863 syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list");
863 864
864 865 }
865 866
866 867 /*
867 868 * Called to read and interpret the event on a connectionless descriptor.
868 869 * Returns 0 if successful, or a UNIX error code if failure.
869 870 */
870 871 static int
871 872 do_poll_clts_action(int fd, int conn_index)
872 873 {
873 874 int error;
874 875 int ret;
875 876 int flags;
876 877 struct netconfig *nconf = &conn_polled[conn_index].nc;
877 878 static struct t_unitdata *unitdata = NULL;
878 879 static struct t_uderr *uderr = NULL;
879 880 static int oldfd = -1;
880 881 struct nd_hostservlist *host = NULL;
881 882 struct strbuf ctl[1], data[1];
882 883 /*
883 884 * We just need to have some space to consume the
884 885 * message in the event we can't use the TLI interface to do the
885 886 * job.
886 887 *
887 888 * We flush the message using getmsg(). For the control part
888 889 * we allocate enough for any TPI header plus 32 bytes for address
889 890 * and options. For the data part, there is nothing magic about
890 891 * the size of the array, but 256 bytes is probably better than
891 892 * 1 byte, and we don't expect any data portion anyway.
892 893 *
893 894 * If the array sizes are too small, we handle this because getmsg()
894 895 * (called to consume the message) will return MOREDATA|MORECTL.
895 896 * Thus we just call getmsg() until it's read the message.
896 897 */
897 898 char ctlbuf[sizeof (union T_primitives) + 32];
898 899 char databuf[256];
899 900
900 901 /*
901 902 * If this is the same descriptor as the last time
902 903 * do_poll_clts_action was called, we can save some
903 904 * de-allocation and allocation.
904 905 */
905 906 if (oldfd != fd) {
906 907 oldfd = fd;
907 908
908 909 if (unitdata) {
909 910 (void) t_free((char *)unitdata, T_UNITDATA);
910 911 unitdata = NULL;
911 912 }
912 913 if (uderr) {
913 914 (void) t_free((char *)uderr, T_UDERROR);
914 915 uderr = NULL;
915 916 }
916 917 }
917 918
918 919 /*
919 920 * Allocate a unitdata structure for receiving the event.
920 921 */
921 922 if (unitdata == NULL) {
922 923 /* LINTED pointer alignment */
923 924 unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL);
924 925 if (unitdata == NULL) {
925 926 if (t_errno == TSYSERR) {
926 927 /*
927 928 * Save the error code across
928 929 * syslog(), just in case
929 930 * syslog() gets its own error
930 931 * and therefore overwrites errno.
931 932 */
932 933 error = errno;
933 934 (void) syslog(LOG_ERR,
934 935 "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m",
935 936 fd, nconf->nc_proto);
936 937 return (error);
937 938 }
938 939 (void) syslog(LOG_ERR,
939 940 "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d",
940 941 fd, nconf->nc_proto, t_errno);
941 942 goto flush_it;
942 943 }
943 944 }
944 945
945 946 try_again:
946 947 flags = 0;
947 948
948 949 /*
949 950 * The idea is we wait for T_UNITDATA_IND's. Of course,
950 951 * we don't get any, because rpcmod filters them out.
951 952 * However, we need to call t_rcvudata() to let TLI
952 953 * tell us we have a T_UDERROR_IND.
953 954 *
954 955 * algorithm is:
955 956 * t_rcvudata(), expecting TLOOK.
956 957 * t_look(), expecting T_UDERR.
957 958 * t_rcvuderr(), expecting success (0).
958 959 * expand destination address into ASCII,
959 960 * and dump it.
960 961 */
961 962
962 963 ret = t_rcvudata(fd, unitdata, &flags);
963 964 if (ret == 0 || t_errno == TBUFOVFLW) {
964 965 (void) syslog(LOG_WARNING,
965 966 "t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes",
966 967 fd, nconf->nc_proto, unitdata->udata.len);
967 968
968 969 /*
969 970 * Even though we don't expect any data, in case we do,
970 971 * keep reading until there is no more.
971 972 */
972 973 if (flags & T_MORE)
973 974 goto try_again;
974 975
975 976 return (0);
976 977 }
977 978
978 979 switch (t_errno) {
979 980 case TNODATA:
980 981 return (0);
981 982 case TSYSERR:
982 983 /*
983 984 * System errors are returned to caller.
984 985 * Save the error code across
985 986 * syslog(), just in case
986 987 * syslog() gets its own error
987 988 * and therefore overwrites errno.
988 989 */
989 990 error = errno;
990 991 (void) syslog(LOG_ERR,
991 992 "t_rcvudata(file descriptor %d/transport %s) %m",
992 993 fd, nconf->nc_proto);
993 994 return (error);
994 995 case TLOOK:
995 996 break;
996 997 default:
997 998 (void) syslog(LOG_ERR,
998 999 "t_rcvudata(file descriptor %d/transport %s) TLI error %d",
999 1000 fd, nconf->nc_proto, t_errno);
1000 1001 goto flush_it;
1001 1002 }
1002 1003
1003 1004 ret = t_look(fd);
1004 1005 switch (ret) {
1005 1006 case 0:
1006 1007 return (0);
1007 1008 case -1:
1008 1009 /*
1009 1010 * System errors are returned to caller.
1010 1011 */
1011 1012 if (t_errno == TSYSERR) {
1012 1013 /*
1013 1014 * Save the error code across
1014 1015 * syslog(), just in case
1015 1016 * syslog() gets its own error
1016 1017 * and therefore overwrites errno.
1017 1018 */
1018 1019 error = errno;
1019 1020 (void) syslog(LOG_ERR,
1020 1021 "t_look(file descriptor %d/transport %s) %m",
1021 1022 fd, nconf->nc_proto);
1022 1023 return (error);
1023 1024 }
1024 1025 (void) syslog(LOG_ERR,
1025 1026 "t_look(file descriptor %d/transport %s) TLI error %d",
1026 1027 fd, nconf->nc_proto, t_errno);
1027 1028 goto flush_it;
1028 1029 case T_UDERR:
1029 1030 break;
1030 1031 default:
1031 1032 (void) syslog(LOG_WARNING,
1032 1033 "t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)",
1033 1034 fd, nconf->nc_proto, ret, T_UDERR);
1034 1035 }
1035 1036
1036 1037 if (uderr == NULL) {
1037 1038 /* LINTED pointer alignment */
1038 1039 uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL);
1039 1040 if (uderr == NULL) {
1040 1041 if (t_errno == TSYSERR) {
1041 1042 /*
1042 1043 * Save the error code across
1043 1044 * syslog(), just in case
1044 1045 * syslog() gets its own error
1045 1046 * and therefore overwrites errno.
1046 1047 */
1047 1048 error = errno;
1048 1049 (void) syslog(LOG_ERR,
1049 1050 "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m",
1050 1051 fd, nconf->nc_proto);
1051 1052 return (error);
1052 1053 }
1053 1054 (void) syslog(LOG_ERR,
1054 1055 "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d",
1055 1056 fd, nconf->nc_proto, t_errno);
1056 1057 goto flush_it;
1057 1058 }
1058 1059 }
1059 1060
1060 1061 ret = t_rcvuderr(fd, uderr);
1061 1062 if (ret == 0) {
1062 1063
1063 1064 /*
1064 1065 * Save the datagram error in errno, so that the
1065 1066 * %m argument to syslog picks up the error string.
1066 1067 */
1067 1068 errno = uderr->error;
1068 1069
1069 1070 /*
1070 1071 * Log the datagram error, then log the host that
1071 1072 * probably triggerred. Cannot log both in the
1072 1073 * same transaction because of packet size limitations
1073 1074 * in /dev/log.
1074 1075 */
1075 1076 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1076 1077 "NFS response over <file descriptor %d/transport %s> generated error: %m",
1077 1078 fd, nconf->nc_proto);
1078 1079
1079 1080 /*
1080 1081 * Try to map the client's address back to a
1081 1082 * name.
1082 1083 */
1083 1084 ret = netdir_getbyaddr(nconf, &host, &uderr->addr);
1084 1085 if (ret != -1 && host && host->h_cnt > 0 &&
1085 1086 host->h_hostservs) {
1086 1087 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1087 1088 "Bad NFS response was sent to client with host name: %s; service port: %s",
1088 1089 host->h_hostservs->h_host,
1089 1090 host->h_hostservs->h_serv);
1090 1091 } else {
1091 1092 int i, j;
1092 1093 char *buf;
1093 1094 char *hex = "0123456789abcdef";
1094 1095
1095 1096 /*
1096 1097 * Mapping failed, print the whole thing
1097 1098 * in ASCII hex.
1098 1099 */
1099 1100 buf = (char *)malloc(uderr->addr.len * 2 + 1);
1100 1101 for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) {
1101 1102 buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf];
1102 1103 buf[j+1] = hex[uderr->addr.buf[i] & 0xf];
1103 1104 }
1104 1105 buf[j] = '\0';
1105 1106 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1106 1107 "Bad NFS response was sent to client with transport address: 0x%s",
1107 1108 buf);
1108 1109 free((void *)buf);
1109 1110 }
1110 1111
1111 1112 if (ret == 0 && host != NULL)
1112 1113 netdir_free((void *)host, ND_HOSTSERVLIST);
1113 1114 return (0);
1114 1115 }
1115 1116
1116 1117 switch (t_errno) {
1117 1118 case TNOUDERR:
1118 1119 goto flush_it;
1119 1120 case TSYSERR:
1120 1121 /*
1121 1122 * System errors are returned to caller.
1122 1123 * Save the error code across
1123 1124 * syslog(), just in case
1124 1125 * syslog() gets its own error
1125 1126 * and therefore overwrites errno.
1126 1127 */
1127 1128 error = errno;
1128 1129 (void) syslog(LOG_ERR,
1129 1130 "t_rcvuderr(file descriptor %d/transport %s) %m",
1130 1131 fd, nconf->nc_proto);
1131 1132 return (error);
1132 1133 default:
1133 1134 (void) syslog(LOG_ERR,
1134 1135 "t_rcvuderr(file descriptor %d/transport %s) TLI error %d",
1135 1136 fd, nconf->nc_proto, t_errno);
1136 1137 goto flush_it;
1137 1138 }
1138 1139
1139 1140 flush_it:
1140 1141 /*
1141 1142 * If we get here, then we could not cope with whatever message
1142 1143 * we attempted to read, so flush it. If we did read a message,
1143 1144 * and one isn't present, that is all right, because fd is in
1144 1145 * nonblocking mode.
1145 1146 */
1146 1147 (void) syslog(LOG_ERR,
1147 1148 "Flushing one input message from <file descriptor %d/transport %s>",
1148 1149 fd, nconf->nc_proto);
1149 1150
1150 1151 /*
1151 1152 * Read and discard the message. Do this this until there is
1152 1153 * no more control/data in the message or until we get an error.
1153 1154 */
1154 1155 do {
1155 1156 ctl->maxlen = sizeof (ctlbuf);
1156 1157 ctl->buf = ctlbuf;
1157 1158 data->maxlen = sizeof (databuf);
1158 1159 data->buf = databuf;
1159 1160 flags = 0;
1160 1161 ret = getmsg(fd, ctl, data, &flags);
1161 1162 if (ret == -1)
1162 1163 return (errno);
1163 1164 } while (ret != 0);
1164 1165
1165 1166 return (0);
1166 1167 }
1167 1168
1168 1169 static void
1169 1170 conn_close_oldest(void)
1170 1171 {
1171 1172 int fd;
1172 1173 int i1;
1173 1174
1174 1175 /*
1175 1176 * Find the oldest connection that is not already in the
1176 1177 * process of shutting down.
1177 1178 */
1178 1179 for (i1 = end_listen_fds; /* no conditional expression */; i1++) {
1179 1180 if (i1 >= num_fds)
1180 1181 return;
1181 1182 if (conn_polled[i1].closing == 0)
1182 1183 break;
1183 1184 }
1184 1185 #ifdef DEBUG
1185 1186 printf("too many connections (%d), releasing oldest (%d)\n",
1186 1187 num_conns, poll_array[i1].fd);
1187 1188 #else
1188 1189 syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)",
1189 1190 num_conns, poll_array[i1].fd);
1190 1191 #endif
1191 1192 fd = poll_array[i1].fd;
1192 1193 if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) {
1193 1194 /*
1194 1195 * For politeness, send a T_DISCON_REQ to the transport
1195 1196 * provider. We close the stream anyway.
1196 1197 */
1197 1198 (void) t_snddis(fd, (struct t_call *)0);
1198 1199 num_conns--;
1199 1200 remove_from_poll_list(fd);
1200 1201 (void) t_close(fd);
1201 1202 } else {
1202 1203 /*
1203 1204 * For orderly release, we do not close the stream
1204 1205 * until the T_ORDREL_IND arrives to complete
1205 1206 * the handshake.
1206 1207 */
1207 1208 if (t_sndrel(fd) == 0)
1208 1209 conn_polled[i1].closing = 1;
1209 1210 }
1210 1211 }
1211 1212
1212 1213 static boolean_t
1213 1214 conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
1214 1215 {
1215 1216 struct conn_ind *conn;
1216 1217 struct conn_ind *next_conn;
1217 1218
1218 1219 conn = (struct conn_ind *)malloc(sizeof (*conn));
1219 1220 if (conn == NULL) {
1220 1221 syslog(LOG_ERR, "malloc for listen indication failed");
1221 1222 return (FALSE);
1222 1223 }
1223 1224
1224 1225 /* LINTED pointer alignment */
1225 1226 conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL);
1226 1227 if (conn->conn_call == NULL) {
1227 1228 free((char *)conn);
1228 1229 nfslib_log_tli_error("t_alloc", fd, nconf);
1229 1230 return (FALSE);
1230 1231 }
1231 1232
1232 1233 if (t_listen(fd, conn->conn_call) == -1) {
1233 1234 nfslib_log_tli_error("t_listen", fd, nconf);
1234 1235 (void) t_free((char *)conn->conn_call, T_CALL);
1235 1236 free((char *)conn);
1236 1237 return (FALSE);
1237 1238 }
1238 1239
1239 1240 if (conn->conn_call->udata.len > 0) {
1240 1241 syslog(LOG_WARNING,
1241 1242 "rejecting inbound connection(%s) with %d bytes of connect data",
1242 1243 nconf->nc_proto, conn->conn_call->udata.len);
1243 1244
1244 1245 conn->conn_call->udata.len = 0;
1245 1246 (void) t_snddis(fd, conn->conn_call);
1246 1247 (void) t_free((char *)conn->conn_call, T_CALL);
1247 1248 free((char *)conn);
1248 1249 return (FALSE);
1249 1250 }
1250 1251
1251 1252 if ((next_conn = *connp) != NULL) {
1252 1253 next_conn->conn_prev->conn_next = conn;
1253 1254 conn->conn_next = next_conn;
1254 1255 conn->conn_prev = next_conn->conn_prev;
1255 1256 next_conn->conn_prev = conn;
1256 1257 } else {
1257 1258 conn->conn_next = conn;
1258 1259 conn->conn_prev = conn;
1259 1260 *connp = conn;
1260 1261 }
1261 1262 return (TRUE);
1262 1263 }
1263 1264
1264 1265 static int
1265 1266 discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
1266 1267 {
1267 1268 struct conn_ind *conn;
1268 1269 struct t_discon discon;
1269 1270
1270 1271 discon.udata.buf = (char *)0;
1271 1272 discon.udata.maxlen = 0;
1272 1273 if (t_rcvdis(fd, &discon) == -1) {
1273 1274 nfslib_log_tli_error("t_rcvdis", fd, nconf);
1274 1275 return (-1);
1275 1276 }
1276 1277
1277 1278 conn = *connp;
1278 1279 if (conn == NULL)
1279 1280 return (0);
1280 1281
1281 1282 do {
1282 1283 if (conn->conn_call->sequence == discon.sequence) {
1283 1284 if (conn->conn_next == conn)
1284 1285 *connp = (struct conn_ind *)0;
1285 1286 else {
1286 1287 if (conn == *connp) {
1287 1288 *connp = conn->conn_next;
1288 1289 }
1289 1290 conn->conn_next->conn_prev = conn->conn_prev;
1290 1291 conn->conn_prev->conn_next = conn->conn_next;
1291 1292 }
1292 1293 free((char *)conn);
1293 1294 break;
1294 1295 }
1295 1296 conn = conn->conn_next;
1296 1297 } while (conn != *connp);
1297 1298
1298 1299 return (0);
1299 1300 }
1300 1301
1301 1302 static void
1302 1303 cots_listen_event(int fd, int conn_index)
1303 1304 {
1304 1305 struct t_call *call;
1305 1306 struct conn_ind *conn;
1306 1307 struct conn_ind *conn_head;
1307 1308 int event;
1308 1309 struct netconfig *nconf = &conn_polled[conn_index].nc;
1309 1310 int new_fd;
1310 1311 struct netbuf addrmask;
1311 1312 int ret = 0;
1312 1313 char *clnt;
1313 1314 char *clnt_uaddr = NULL;
1314 1315 struct nd_hostservlist *clnt_serv = NULL;
1315 1316
1316 1317 conn_head = NULL;
1317 1318 (void) conn_get(fd, nconf, &conn_head);
1318 1319
1319 1320 while ((conn = conn_head) != NULL) {
1320 1321 conn_head = conn->conn_next;
1321 1322 if (conn_head == conn)
1322 1323 conn_head = NULL;
1323 1324 else {
1324 1325 conn_head->conn_prev = conn->conn_prev;
1325 1326 conn->conn_prev->conn_next = conn_head;
1326 1327 }
1327 1328 call = conn->conn_call;
1328 1329 free(conn);
1329 1330
1330 1331 /*
1331 1332 * If we have already accepted the maximum number of
1332 1333 * connections allowed on the command line, then drop
1333 1334 * the oldest connection (for any protocol) before
1334 1335 * accepting the new connection. Unless explicitly
1335 1336 * set on the command line, max_conns_allowed is -1.
1336 1337 */
1337 1338 if (max_conns_allowed != -1 && num_conns >= max_conns_allowed)
1338 1339 conn_close_oldest();
1339 1340
1340 1341 /*
1341 1342 * Create a new transport endpoint for the same proto as
1342 1343 * the listener.
1343 1344 */
1344 1345 new_fd = nfslib_transport_open(nconf);
1345 1346 if (new_fd == -1) {
1346 1347 call->udata.len = 0;
1347 1348 (void) t_snddis(fd, call);
1348 1349 (void) t_free((char *)call, T_CALL);
1349 1350 syslog(LOG_ERR, "Cannot establish transport over %s",
1350 1351 nconf->nc_device);
1351 1352 continue;
1352 1353 }
1353 1354
1354 1355 /* Bind to a generic address/port for the accepting stream. */
1355 1356 if (t_bind(new_fd, NULL, NULL) == -1) {
1356 1357 nfslib_log_tli_error("t_bind", new_fd, nconf);
1357 1358 call->udata.len = 0;
1358 1359 (void) t_snddis(fd, call);
1359 1360 (void) t_free((char *)call, T_CALL);
1360 1361 (void) t_close(new_fd);
1361 1362 continue;
1362 1363 }
1363 1364
1364 1365 while (t_accept(fd, new_fd, call) == -1) {
1365 1366 if (t_errno != TLOOK) {
1366 1367 #ifdef DEBUG
1367 1368 nfslib_log_tli_error("t_accept", fd, nconf);
1368 1369 #endif
1369 1370 call->udata.len = 0;
1370 1371 (void) t_snddis(fd, call);
1371 1372 (void) t_free((char *)call, T_CALL);
1372 1373 (void) t_close(new_fd);
1373 1374 goto do_next_conn;
1374 1375 }
1375 1376 while (event = t_look(fd)) {
1376 1377 switch (event) {
1377 1378 case T_LISTEN:
1378 1379 #ifdef DEBUG
1379 1380 printf(
1380 1381 "cots_listen_event(%s): T_LISTEN during accept processing\n", nconf->nc_proto);
1381 1382 #endif
1382 1383 (void) conn_get(fd, nconf, &conn_head);
1383 1384 continue;
1384 1385 case T_DISCONNECT:
1385 1386 #ifdef DEBUG
1386 1387 printf(
1387 1388 "cots_listen_event(%s): T_DISCONNECT during accept processing\n",
1388 1389 nconf->nc_proto);
1389 1390 #endif
1390 1391 (void) discon_get(fd, nconf,
1391 1392 &conn_head);
1392 1393 continue;
1393 1394 default:
1394 1395 syslog(LOG_ERR,
1395 1396 "unexpected event 0x%x during accept processing (%s)",
1396 1397 event, nconf->nc_proto);
1397 1398 call->udata.len = 0;
1398 1399 (void) t_snddis(fd, call);
1399 1400 (void) t_free((char *)call, T_CALL);
1400 1401 (void) t_close(new_fd);
1401 1402 goto do_next_conn;
1402 1403 }
1403 1404 }
1404 1405 }
1405 1406
1406 1407 if (set_addrmask(new_fd, nconf, &addrmask) < 0) {
1407 1408 (void) syslog(LOG_ERR,
1408 1409 "Cannot set address mask for %s",
1409 1410 nconf->nc_netid);
1410 1411 (void) t_snddis(new_fd, NULL);
1411 1412 (void) t_free((char *)call, T_CALL);
1412 1413 (void) t_close(new_fd);
1413 1414 continue;
1414 1415 }
1415 1416
1416 1417 /* Tell kRPC about the new stream. */
1417 1418 if (Mysvc4 != NULL)
1418 1419 ret = (*Mysvc4)(new_fd, &addrmask, nconf,
1419 1420 NFS4_KRPC_START, &call->addr);
1420 1421 else
1421 1422 ret = (*Mysvc)(new_fd, addrmask, nconf);
1422 1423
1423 1424 if (ret < 0) {
1424 1425 if (errno != ENOTCONN) {
1425 1426 syslog(LOG_ERR,
1426 1427 "unable to register new connection: %m");
1427 1428 } else {
1428 1429 /*
1429 1430 * This is the only error that could be
1430 1431 * caused by the client, so who was it?
1431 1432 */
1432 1433 if (netdir_getbyaddr(nconf, &clnt_serv,
1433 1434 &(call->addr)) == ND_OK &&
1434 1435 clnt_serv->h_cnt > 0)
1435 1436 clnt = clnt_serv->h_hostservs->h_host;
1436 1437 else
1437 1438 clnt = clnt_uaddr = taddr2uaddr(nconf,
1438 1439 &(call->addr));
1439 1440 /*
1440 1441 * If we don't know who the client was,
1441 1442 * remain silent.
1442 1443 */
1443 1444 if (clnt)
1444 1445 syslog(LOG_ERR,
1445 1446 "unable to register new connection: client %s has dropped connection", clnt);
1446 1447 if (clnt_serv) {
1447 1448 netdir_free(clnt_serv, ND_HOSTSERVLIST);
1448 1449 clnt_serv = NULL;
1449 1450 }
1450 1451 if (clnt_uaddr) {
1451 1452 free(clnt_uaddr);
1452 1453 clnt_uaddr = NULL;
1453 1454 }
1454 1455 }
1455 1456 free(addrmask.buf);
1456 1457 (void) t_snddis(new_fd, NULL);
1457 1458 (void) t_free((char *)call, T_CALL);
1458 1459 (void) t_close(new_fd);
1459 1460 goto do_next_conn;
1460 1461 }
1461 1462
1462 1463 free(addrmask.buf);
1463 1464 (void) t_free((char *)call, T_CALL);
1464 1465
1465 1466 /*
1466 1467 * Poll on the new descriptor so that we get disconnect
1467 1468 * and orderly release indications.
1468 1469 */
1469 1470 num_conns++;
1470 1471 add_to_poll_list(new_fd, nconf);
1471 1472
1472 1473 /* Reset nconf in case it has been moved. */
1473 1474 nconf = &conn_polled[conn_index].nc;
1474 1475 do_next_conn:;
1475 1476 }
1476 1477 }
1477 1478
1478 1479 static int
1479 1480 do_poll_cots_action(int fd, int conn_index)
1480 1481 {
1481 1482 char buf[256];
1482 1483 int event;
1483 1484 int i1;
1484 1485 int flags;
1485 1486 struct conn_entry *connent = &conn_polled[conn_index];
1486 1487 struct netconfig *nconf = &(connent->nc);
1487 1488 const char *errorstr;
1488 1489
1489 1490 while (event = t_look(fd)) {
1490 1491 switch (event) {
1491 1492 case T_LISTEN:
1492 1493 #ifdef DEBUG
1493 1494 printf("do_poll_cots_action(%s,%d): T_LISTEN event\n", nconf->nc_proto, fd);
1494 1495 #endif
1495 1496 cots_listen_event(fd, conn_index);
1496 1497 break;
1497 1498
1498 1499 case T_DATA:
1499 1500 #ifdef DEBUG
1500 1501 printf("do_poll_cots_action(%d,%s): T_DATA event\n", fd, nconf->nc_proto);
1501 1502 #endif
1502 1503 /*
1503 1504 * Receive a private notification from CONS rpcmod.
1504 1505 */
1505 1506 i1 = t_rcv(fd, buf, sizeof (buf), &flags);
1506 1507 if (i1 == -1) {
1507 1508 syslog(LOG_ERR, "t_rcv failed");
1508 1509 break;
1509 1510 }
1510 1511 if (i1 < sizeof (int))
1511 1512 break;
1512 1513 i1 = BE32_TO_U32(buf);
1513 1514 if (i1 == 1 || i1 == 2) {
1514 1515 /*
1515 1516 * This connection has been idle for too long,
1516 1517 * so release it as politely as we can. If we
1517 1518 * have already initiated an orderly release
1518 1519 * and we get notified that the stream is
1519 1520 * still idle, pull the plug. This prevents
1520 1521 * hung connections from continuing to consume
1521 1522 * resources.
1522 1523 */
1523 1524 #ifdef DEBUG
1524 1525 printf("do_poll_cots_action(%s,%d): ", nconf->nc_proto, fd);
1525 1526 printf("initiating orderly release of idle connection\n");
1526 1527 #endif
1527 1528 if (nconf->nc_semantics == NC_TPI_COTS ||
1528 1529 connent->closing != 0) {
1529 1530 (void) t_snddis(fd, (struct t_call *)0);
1530 1531 goto fdclose;
1531 1532 }
1532 1533 /*
1533 1534 * For NC_TPI_COTS_ORD, the stream is closed
1534 1535 * and removed from the poll list when the
1535 1536 * T_ORDREL is received from the provider. We
1536 1537 * don't wait for it here because it may take
1537 1538 * a while for the transport to shut down.
1538 1539 */
1539 1540 if (t_sndrel(fd) == -1) {
1540 1541 syslog(LOG_ERR,
1541 1542 "unable to send orderly release %m");
1542 1543 }
1543 1544 connent->closing = 1;
1544 1545 } else
1545 1546 syslog(LOG_ERR,
1546 1547 "unexpected event from CONS rpcmod %d", i1);
1547 1548 break;
1548 1549
1549 1550 case T_ORDREL:
1550 1551 #ifdef DEBUG
1551 1552 printf("do_poll_cots_action(%s,%d): T_ORDREL event\n", nconf->nc_proto, fd);
1552 1553 #endif
1553 1554 /* Perform an orderly release. */
1554 1555 if (t_rcvrel(fd) == 0) {
1555 1556 /* T_ORDREL on listen fd's should be ignored */
1556 1557 if (!is_listen_fd_index(conn_index)) {
1557 1558 (void) t_sndrel(fd);
1558 1559 goto fdclose;
1559 1560 }
1560 1561 break;
1561 1562
1562 1563 } else if (t_errno == TLOOK) {
1563 1564 break;
1564 1565 } else {
1565 1566 nfslib_log_tli_error("t_rcvrel", fd, nconf);
1566 1567
1567 1568 /*
1568 1569 * check to make sure we do not close
1569 1570 * listen fd
1570 1571 */
1571 1572 if (is_listen_fd_index(conn_index))
1572 1573 break;
1573 1574 else
1574 1575 goto fdclose;
1575 1576 }
1576 1577
1577 1578 case T_DISCONNECT:
1578 1579 #ifdef DEBUG
1579 1580 printf("do_poll_cots_action(%s,%d): T_DISCONNECT event\n", nconf->nc_proto, fd);
1580 1581 #endif
1581 1582 if (t_rcvdis(fd, (struct t_discon *)NULL) == -1)
↓ open down ↓ |
1546 lines elided |
↑ open up ↑ |
1582 1583 nfslib_log_tli_error("t_rcvdis", fd, nconf);
1583 1584
1584 1585 /*
1585 1586 * T_DISCONNECT on listen fd's should be ignored.
1586 1587 */
1587 1588 if (is_listen_fd_index(conn_index))
1588 1589 break;
1589 1590 else
1590 1591 goto fdclose;
1591 1592
1592 - case T_ERROR:
1593 1593 default:
1594 - if (event == T_ERROR || t_errno == TSYSERR) {
1594 + if (t_errno == TSYSERR) {
1595 1595 if ((errorstr = strerror(errno)) == NULL) {
1596 1596 (void) sprintf(buf,
1597 1597 "Unknown error num %d", errno);
1598 1598 errorstr = (const char *) buf;
1599 1599 }
1600 1600 } else if (event == -1)
1601 1601 errorstr = t_strerror(t_errno);
1602 1602 else
1603 1603 errorstr = "";
1604 1604 syslog(LOG_ERR,
1605 1605 "unexpected TLI event (0x%x) on "
1606 1606 "connection-oriented transport(%s,%d):%s",
1607 1607 event, nconf->nc_proto, fd, errorstr);
1608 1608 fdclose:
1609 1609 num_conns--;
1610 1610 remove_from_poll_list(fd);
1611 1611 (void) t_close(fd);
1612 1612 return (0);
1613 1613 }
1614 1614 }
1615 1615
1616 1616 return (0);
1617 1617 }
1618 1618
1619 1619 static char *
1620 1620 serv_name_to_port_name(char *name)
1621 1621 {
1622 1622 /*
1623 1623 * Map service names (used primarily in logging) to
1624 1624 * RPC port names (used by netdir_*() routines).
1625 1625 */
1626 1626 if (strcmp(name, "NFS") == 0) {
1627 1627 return ("nfs");
1628 1628 } else if (strcmp(name, "NLM") == 0) {
1629 1629 return ("lockd");
1630 1630 } else if (strcmp(name, "NFS4_CALLBACK") == 0) {
1631 1631 return ("nfs4_callback");
1632 1632 }
1633 1633
1634 1634 return ("unrecognized");
1635 1635 }
1636 1636
1637 1637 static int
1638 1638 bind_to_provider(char *provider, char *serv, struct netbuf **addr,
1639 1639 struct netconfig **retnconf)
1640 1640 {
1641 1641 struct netconfig *nconf;
1642 1642 NCONF_HANDLE *nc;
1643 1643 struct nd_hostserv hs;
1644 1644
1645 1645 hs.h_host = HOST_SELF;
1646 1646 hs.h_serv = serv_name_to_port_name(serv);
1647 1647
1648 1648 if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
1649 1649 syslog(LOG_ERR, "setnetconfig failed: %m");
1650 1650 return (-1);
1651 1651 }
1652 1652 while (nconf = getnetconfig(nc)) {
1653 1653 if (OK_TPI_TYPE(nconf) &&
1654 1654 strcmp(nconf->nc_device, provider) == 0) {
1655 1655 *retnconf = nconf;
1656 1656 return (nfslib_bindit(nconf, addr, &hs,
1657 1657 listen_backlog));
1658 1658 }
1659 1659 }
1660 1660 (void) endnetconfig(nc);
1661 1661
1662 1662 syslog(LOG_ERR, "couldn't find netconfig entry for provider %s",
1663 1663 provider);
1664 1664 return (-1);
1665 1665 }
1666 1666
1667 1667 static int
1668 1668 bind_to_proto(NETSELDECL(proto), char *serv, struct netbuf **addr,
1669 1669 struct netconfig **retnconf)
1670 1670 {
1671 1671 struct netconfig *nconf;
1672 1672 NCONF_HANDLE *nc = NULL;
1673 1673 struct nd_hostserv hs;
1674 1674
1675 1675 hs.h_host = HOST_SELF;
1676 1676 hs.h_serv = serv_name_to_port_name(serv);
1677 1677
1678 1678 if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
1679 1679 syslog(LOG_ERR, "setnetconfig failed: %m");
1680 1680 return (-1);
1681 1681 }
1682 1682 while (nconf = getnetconfig(nc)) {
1683 1683 if (OK_TPI_TYPE(nconf) && NETSELEQ(nconf->nc_proto, proto)) {
1684 1684 *retnconf = nconf;
1685 1685 return (nfslib_bindit(nconf, addr, &hs,
1686 1686 listen_backlog));
1687 1687 }
1688 1688 }
1689 1689 (void) endnetconfig(nc);
1690 1690
1691 1691 syslog(LOG_ERR, "couldn't find netconfig entry for protocol %s",
1692 1692 proto);
1693 1693 return (-1);
1694 1694 }
1695 1695
1696 1696 #include <netinet/in.h>
1697 1697
1698 1698 /*
1699 1699 * Create an address mask appropriate for the transport.
1700 1700 * The mask is used to obtain the host-specific part of
1701 1701 * a network address when comparing addresses.
1702 1702 * For an internet address the host-specific part is just
1703 1703 * the 32 bit IP address and this part of the mask is set
1704 1704 * to all-ones. The port number part of the mask is zeroes.
1705 1705 */
1706 1706 static int
1707 1707 set_addrmask(int fd,
1708 1708 struct netconfig *nconf,
1709 1709 struct netbuf *mask)
1710 1710 {
1711 1711 struct t_info info;
1712 1712
1713 1713 /*
1714 1714 * Find the size of the address we need to mask.
1715 1715 */
1716 1716 if (t_getinfo(fd, &info) < 0) {
1717 1717 t_error("t_getinfo");
1718 1718 return (-1);
1719 1719 }
1720 1720 mask->len = mask->maxlen = info.addr;
1721 1721 if (info.addr <= 0) {
1722 1722 /*
1723 1723 * loopback devices have infinite addr size
1724 1724 * (it is identified by -1 in addr field of t_info structure),
1725 1725 * so don't build the netmask for them. It's a special case
1726 1726 * that should be handled properly.
1727 1727 */
1728 1728 if ((info.addr == -1) &&
1729 1729 (0 == strcmp(nconf->nc_protofmly, NC_LOOPBACK))) {
1730 1730 memset(mask, 0, sizeof (*mask));
1731 1731 return (0);
1732 1732 }
1733 1733
1734 1734 syslog(LOG_ERR, "set_addrmask: address size: %ld", info.addr);
1735 1735 return (-1);
1736 1736 }
1737 1737
1738 1738 mask->buf = (char *)malloc(mask->len);
1739 1739 if (mask->buf == NULL) {
1740 1740 syslog(LOG_ERR, "set_addrmask: no memory");
1741 1741 return (-1);
1742 1742 }
1743 1743 (void) memset(mask->buf, 0, mask->len); /* reset all mask bits */
1744 1744
1745 1745 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
1746 1746 /*
1747 1747 * Set the mask so that the port is ignored.
1748 1748 */
1749 1749 /* LINTED pointer alignment */
1750 1750 ((struct sockaddr_in *)mask->buf)->sin_addr.s_addr =
1751 1751 (ulong_t)~0;
1752 1752 /* LINTED pointer alignment */
1753 1753 ((struct sockaddr_in *)mask->buf)->sin_family =
1754 1754 (ushort_t)~0;
1755 1755 } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
1756 1756 /* LINTED pointer alignment */
1757 1757 (void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr,
1758 1758 (uchar_t)~0, sizeof (struct in6_addr));
1759 1759 /* LINTED pointer alignment */
1760 1760 ((struct sockaddr_in6 *)mask->buf)->sin6_family =
1761 1761 (ushort_t)~0;
1762 1762 } else {
1763 1763
1764 1764 /*
1765 1765 * Set all mask bits.
1766 1766 */
1767 1767 (void) memset(mask->buf, 0xFF, mask->len);
1768 1768 }
1769 1769 return (0);
1770 1770 }
1771 1771
1772 1772 /*
1773 1773 * For listen fd's index is always less than end_listen_fds.
1774 1774 * end_listen_fds is defined externally in the daemon that uses this library.
1775 1775 * It's value is equal to the number of open file descriptors after the
1776 1776 * last listen end point was opened but before any connection was accepted.
1777 1777 */
1778 1778 static int
1779 1779 is_listen_fd_index(int index)
1780 1780 {
1781 1781 return (index < end_listen_fds);
1782 1782 }
↓ open down ↓ |
178 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX