xref: /titanic_44/usr/src/uts/common/fs/sockfs/nl7c.c (revision ea8dc4b6d2251b437950c0056bc626b311c73c27)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * NL7C (Network Layer 7 Cache) as part of SOCKFS provides an in-kernel
31  * gateway cache for the request/response message based L7 protocol HTTP
32  * (Hypertext Transfer Protocol, see HTTP/1.1 RFC2616) in a semantically
33  * transparent manner.
34  *
35  * Neither the requesting user agent (client, e.g. web broweser) nor the
36  * origin server (e.g. webserver) that provided the response cached by
37  * NL7C are impacted in any way.
38  *
39  * Note, currently NL7C only processes HTTP messages via the embedded
40  * URI of scheme http (not https nor any other), additional scheme are
41  * intended to be supproted as is practical such that much of the NL7C
42  * framework may appear more gerneral purpose then would be needed just
43  * for an HTTP gateway cache.
44  *
45  * NL7C replaces NCA (Network Cache and Accelerator) and in the future
46  * NCAS (NCA/SSL).
47  *
48  * Further, NL7C uses all NCA configuration files, see "/etc/nca/", the
49  * NCA socket API, "AF_NCA", and "ndd /dev/nca" for backwards compatability.
50  */
51 
52 #include <sys/promif.h>
53 #include <sys/systm.h>
54 #include <sys/strsun.h>
55 #include <sys/strsubr.h>
56 #include <inet/common.h>
57 #include <inet/led.h>
58 #include <inet/mi.h>
59 #include <netinet/in.h>
60 #include <fs/sockfs/nl7c.h>
61 #include <fs/sockfs/nl7curi.h>
62 
63 #include <inet/nca/ncadoorhdr.h>
64 #include <inet/nca/ncalogd.h>
65 
66 /*
67  * NL7C, NCA, NL7C logger enabled:
68  */
69 
70 boolean_t	nl7c_enabled = B_FALSE;
71 
72 boolean_t	nl7c_logd_enabled = B_FALSE;
73 boolean_t	nl7c_logd_started = B_FALSE;
74 boolean_t	nl7c_logd_cycle = B_TRUE;
75 
76 /*
77  * Some externs:
78  */
79 
80 extern int	inet_pton(int, char *, void *);
81 
82 extern void	nl7c_uri_init(void);
83 extern boolean_t nl7c_logd_init(int, caddr_t *);
84 extern void	nl7c_nca_init(void);
85 
86 /*
87  * nl7c_addr_t - a singly linked grounded list, pointed to by *nl7caddrs,
88  * constructed at init time by parsing "/etc/nca/ncaport.conf".
89  *
90  * This list is searched at bind(3SOCKET) time when an application doesn't
91  * explicitly set AF_NCA but instead uses AF_INET, if a match is found then
92  * the underlying socket is marked so_nl7c_flags NL7C_ENABLED.
93  */
94 
95 typedef struct nl7c_addr_s {
96 	struct nl7c_addr_s *next;	/* next entry */
97 	sa_family_t	family;		/* addr type, only INET and INET6 */
98 	uint16_t	port;		/* port */
99 	union {
100 		ipaddr_t	v4;	/* IPv4 address */
101 		in6_addr_t	v6;	/* IPv6 address */
102 		void		*align;	/* foce alignment */
103 	}		addr;		/* address */
104 
105 	queue_t		*listenerq;	/* listen()er's Q (NULL if none ) */
106 	boolean_t	temp;		/* temporary addr via add_addr() ? */
107 } nl7c_addr_t;
108 
109 nl7c_addr_t	*nl7caddrs = NULL;
110 
111 void
112 nl7c_listener_addr(void *arg, queue_t *q)
113 {
114 	nl7c_addr_t	*p = (nl7c_addr_t *)arg;
115 
116 	if (p->listenerq == NULL)
117 		p->listenerq = q;
118 }
119 
120 void *
121 nl7c_lookup_addr(void *addr, t_uscalar_t addrlen)
122 {
123 	struct sockaddr		*sap = addr;
124 	struct sockaddr_in	*v4p = addr;
125 	nl7c_addr_t		*p = nl7caddrs;
126 
127 	if (sap->sa_family != AF_INET || addrlen != sizeof (*v4p)) {
128 		/* Only support IPv4 */
129 		return (B_FALSE);
130 	}
131 	while (p) {
132 		if (sap->sa_family == p->family &&
133 		    v4p->sin_port == p->port &&
134 		    (v4p->sin_addr.s_addr == p->addr.v4 ||
135 		    p->addr.v4 == INADDR_ANY)) {
136 			/* Match */
137 			return (p);
138 		}
139 		p = p->next;
140 	}
141 	return (NULL);
142 }
143 
144 void *
145 nl7c_add_addr(void *addr, t_uscalar_t addrlen)
146 {
147 	struct sockaddr		*sap = addr;
148 	struct sockaddr_in	*v4p = addr;
149 	nl7c_addr_t		*new = NULL;
150 	nl7c_addr_t		*old;
151 	nl7c_addr_t		*p;
152 	boolean_t		alloced;
153 
154 	if (sap->sa_family != AF_INET || addrlen != sizeof (*v4p)) {
155 		/* Only support IPv4 */
156 		return (NULL);
157 	}
158 again:
159 	old = nl7caddrs;
160 	p = nl7caddrs;
161 	while (p) {
162 		if (new == NULL && p->port == 0)
163 			new = p;
164 		if (sap->sa_family == p->family &&
165 		    v4p->sin_port == p->port &&
166 		    (v4p->sin_addr.s_addr == p->addr.v4 ||
167 		    p->addr.v4 == INADDR_ANY)) {
168 			/* Match */
169 			return (p);
170 		}
171 		p = p->next;
172 	}
173 	if (new == NULL) {
174 		new = kmem_zalloc(sizeof (*new), KM_SLEEP);
175 		if (new == NULL)
176 			return (NULL);
177 		alloced = B_TRUE;
178 	} else
179 		alloced = B_FALSE;
180 
181 	new->family = sap->sa_family;
182 	new->port = v4p->sin_port;
183 	new->addr.v4 = v4p->sin_addr.s_addr;
184 	new->temp = B_TRUE;
185 
186 	if (alloced) {
187 		new->next = old;
188 		if (atomic_cas_ptr(&nl7caddrs, old, new) != old) {
189 			kmem_free(new, sizeof (*new));
190 			goto again;
191 		}
192 	}
193 
194 	return (new);
195 }
196 
197 boolean_t
198 nl7c_close_addr(struct sonode *so)
199 {
200 	nl7c_addr_t	*p = nl7caddrs;
201 	queue_t		*q = strvp2wq(SOTOV(so));
202 
203 	while (p) {
204 		if (p->listenerq == q) {
205 			if (p->temp)
206 				p->port = (uint16_t)-1;
207 			p->listenerq = NULL;
208 			return (B_TRUE);
209 		}
210 		p = p->next;
211 	}
212 	return (B_FALSE);
213 }
214 
215 static void
216 nl7c_addr_add(nl7c_addr_t *p)
217 {
218 	p->next = nl7caddrs;
219 	nl7caddrs = p;
220 }
221 
222 void
223 nl7c_mi_report_addr(mblk_t *mp)
224 {
225 	ipaddr_t	ip;
226 	uint16_t	port;
227 	nl7c_addr_t	*p = nl7caddrs;
228 	char		addr[32];
229 
230 	(void) mi_mpprintf(mp, "Door  Up-Call-Queue IPaddr:TCPport Listenning");
231 
232 	while (p) {
233 		if (p->listenerq != NULL) {
234 			/* Only report listen()ed on addr(s) */
235 			ip = ntohl(p->addr.v4);
236 			port = ntohs(p->port);
237 
238 			if (ip == INADDR_ANY) {
239 				(void) strcpy(addr, "*");
240 			} else {
241 				int a1 = (ip >> 24) & 0xFF;
242 				int a2 = (ip >> 16) & 0xFF;
243 				int a3 = (ip >> 8) & 0xFF;
244 				int a4 = ip & 0xFF;
245 
246 				(void) mi_sprintf(addr, "%d.%d.%d.%d",
247 					a1, a2, a3, a4);
248 			}
249 			(void) mi_sprintf(addr, "%s:%d", addr, port);
250 			(void) mi_mpprintf(mp, "%p  %p  %s  %d", (void *)NULL,
251 				(void *)p->listenerq, addr, 1);
252 		}
253 		p = p->next;
254 	}
255 }
256 
257 /*
258  * ASCII to unsigned.
259  *
260  * Note, it's assumed that *p is a valid zero byte terminated string.
261  */
262 
263 static unsigned
264 atou(const char *p)
265 {
266 	int c;
267 	int v = 0;
268 
269 	/* Shift and add digit by digit */
270 	while ((c = *p++) != NULL && isdigit(c)) {
271 		v *= 10;
272 		v += c - '0';
273 	}
274 	return (v);
275 }
276 
277 /*
278  * strdup(), yet another strdup() in the kernel.
279  */
280 
281 static char *
282 strdup(char *s)
283 {
284 	int	len = strlen(s) + 1;
285 	char	*ret = kmem_alloc(len, KM_SLEEP);
286 
287 	bcopy(s, ret, len);
288 
289 	return (ret);
290 }
291 
292 /*
293  * Inet ASCII to binary.
294  *
295  * Note, it's assumed that *s is a valid zero byte terminated string, and
296  * that *p is a zero initialized struct (this is important as the value of
297  * INADDR_ANY and IN6ADDR_ANY is zero).
298  */
299 
300 static int
301 inet_atob(char *s, nl7c_addr_t *p)
302 {
303 	if (strcmp(s, "*") == 0) {
304 		/* INADDR_ANY */
305 		p->family = AF_INET;
306 		return (0);
307 	}
308 	if (strcmp(s, "::") == 0) {
309 		/* IN6ADDR_ANY */
310 		p->family = AF_INET6;
311 		return (0);
312 	}
313 	/* IPv4 address ? */
314 	if (inet_pton(AF_INET, s, &p->addr.v4) != 1) {
315 		/* Nop, IPv6 address ? */
316 		if (inet_pton(AF_INET6, s, &p->addr.v6) != 1) {
317 			/* Nop, return error */
318 			return (1);
319 		}
320 		p->family = AF_INET6;
321 	} else {
322 		p->family = AF_INET;
323 	}
324 	return (0);
325 }
326 
327 /*
328  * Open and read each line from "/etc/nca/ncaport.conf", the syntax of a
329  * ncaport.conf file line is: ncaport=IPaddr/Port, all other lines will
330  * be ignored, where:
331  *
332  * ncaport - the only token recognized.
333  *
334  *  IPaddr - an IPv4 numeric dot address (e.g. 192.168.84.71) or '*' for
335  *           INADDR_ANY, or an IPv6 numeric address or "::" for IN6ADDR_ANY.
336  *
337  *       / - IPaddr/Port seperator.
338  *
339  *    Port - a TCP decimal port number.
340  */
341 
342 static void
343 ncaportconf_read(void)
344 {
345 	int	ret;
346 	struct vnode *vp;
347 	char	c;
348 	ssize_t resid;
349 	char	buf[1024];
350 	char	*ebp = &buf[sizeof (buf)];
351 	char	*bp = ebp;
352 	offset_t off = 0;
353 	enum parse_e {START, TOK, ADDR, PORT, EOL} parse = START;
354 	nl7c_addr_t *addrp = NULL;
355 	char	*ncaport = "ncaport";
356 	char	string[] = "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX";
357 	char	*stringp;
358 	char	*tok;
359 	char	*portconf = "/etc/nca/ncaport.conf";
360 
361 	ret = vn_open(portconf, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0);
362 	if (ret == ENOENT) {
363 		/* No portconf file, nothing to do */
364 		return;
365 	}
366 	if (ret != 0) {
367 		/* Error of some sort, tell'm about it */
368 		cmn_err(CE_WARN, "%s: open error %d", portconf, ret);
369 		return;
370 	}
371 	/*
372 	 * Read portconf one buf[] at a time, parse one char at a time.
373 	 */
374 	for (;;) {
375 		if (bp == ebp) {
376 			/* Nothing left in buf[], read another */
377 			ret = vn_rdwr(UIO_READ, vp, buf, sizeof (buf), off,
378 			    UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid);
379 			if (ret != 0) {
380 				/* Error of some sort, tell'm about it */
381 				cmn_err(CE_WARN, "%s: read error %d",
382 					portconf, ret);
383 				break;
384 			}
385 			if (resid == sizeof (buf)) {
386 				/* EOF, done */
387 				break;
388 			}
389 			/* Initilize per buf[] state */
390 			bp = buf;
391 			ebp = &buf[sizeof (buf) - resid];
392 			off += sizeof (buf) - resid;
393 		}
394 		c = *bp++;
395 		switch (parse) {
396 		case START:
397 			/* Initilize all per file line state */
398 			if (addrp == NULL) {
399 				addrp = kmem_zalloc(sizeof (*addrp),
400 				    KM_NOSLEEP);
401 			}
402 			tok = ncaport;
403 			stringp = string;
404 			parse = TOK;
405 			/*FALLTHROUGH*/
406 		case TOK:
407 			if (c == '#') {
408 				/* Comment through end of line */
409 				parse = EOL;
410 				break;
411 			}
412 			if (isalpha(c)) {
413 				if (c != *tok++) {
414 					/* Only know one token, skip */
415 					parse = EOL;
416 				}
417 			} else if (c == '=') {
418 				if (*tok != NULL) {
419 					/* Only know one token, skip */
420 					parse = EOL;
421 					break;
422 				}
423 				parse = ADDR;
424 			} else if (c == '\n') {
425 				/* Found EOL, empty line, next line */
426 				parse = START;
427 			} else {
428 				/* Unexpected char, skip */
429 				parse = EOL;
430 			}
431 			break;
432 
433 		case ADDR:
434 			if (c == '/') {
435 				/* addr/port separator, end of addr */
436 				*stringp = NULL;
437 				if (inet_atob(string, addrp)) {
438 					/* Bad addr, skip */
439 					parse = EOL;
440 				} else {
441 					stringp = string;
442 					parse = PORT;
443 				}
444 			} else {
445 				/* Save char to string */
446 				if (stringp ==
447 				    &string[sizeof (string) - 1]) {
448 					/* Would overflow, skip */
449 					parse = EOL;
450 				} else {
451 					/* Copy IP addr char */
452 					*stringp++ = c;
453 				}
454 			}
455 			break;
456 
457 		case PORT:
458 			if (isdigit(c)) {
459 				/* Save char to string */
460 				if (stringp ==
461 				    &string[sizeof (string) - 1]) {
462 					/* Would overflow, skip */
463 					parse = EOL;
464 				} else {
465 					/* Copy port digit char */
466 					*stringp++ = c;
467 				}
468 				break;
469 			} else if (c == '#' || isspace(c)) {
470 				/* End of port number, convert */
471 				*stringp = NULL;
472 				addrp->port = atou(string);
473 
474 				/* End of parse, add entry */
475 				nl7c_addr_add(addrp);
476 				addrp = NULL;
477 				parse = EOL;
478 			} else {
479 				/* Unrecognized char, skip */
480 				parse = EOL;
481 				break;
482 			}
483 			/*FALLTHROUGH*/
484 		case EOL:
485 			if (c == '\n') {
486 				/* Found EOL, start on next line */
487 				parse = START;
488 			}
489 			break;
490 		}
491 
492 	}
493 	if (addrp != NULL) {
494 		kmem_free(addrp, sizeof (*addrp));
495 	}
496 	(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
497 	VN_RELE(vp);
498 }
499 
500 /*
501  * Open and read each line from "/etc/nca/ncakmod.conf" and parse looking
502  * for the NCA enabled, the syntax is: status=enabled, all other lines will
503  * be ignored.
504  */
505 
506 static void
507 ncakmodconf_read(void)
508 {
509 	int	ret;
510 	struct vnode *vp;
511 	char	c;
512 	ssize_t resid;
513 	char	buf[1024];
514 	char	*ebp = &buf[sizeof (buf)];
515 	char	*bp = ebp;
516 	offset_t off = 0;
517 	enum parse_e {START, TOK, EOL} parse = START;
518 	char	*status = "status=enabled";
519 	char	*tok;
520 	char	*ncakmod = "/etc/nca/ncakmod.conf";
521 
522 	ret = vn_open(ncakmod, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0);
523 	if (ret == ENOENT) {
524 		/* No ncakmod file, nothing to do */
525 		return;
526 	}
527 	if (ret != 0) {
528 		/* Error of some sort, tell'm about it */
529 		cmn_err(CE_WARN, "%s: open error %d", status, ret);
530 		return;
531 	}
532 	/*
533 	 * Read ncakmod one buf[] at a time, parse one char at a time.
534 	 */
535 	for (;;) {
536 		if (bp == ebp) {
537 			/* Nothing left in buf[], read another */
538 			ret = vn_rdwr(UIO_READ, vp, buf, sizeof (buf), off,
539 			    UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid);
540 			if (ret != 0) {
541 				/* Error of some sort, tell'm about it */
542 				cmn_err(CE_WARN, "%s: read error %d",
543 					status, ret);
544 				break;
545 			}
546 			if (resid == sizeof (buf)) {
547 				/* EOF, done */
548 				break;
549 			}
550 			/* Initilize per buf[] state */
551 			bp = buf;
552 			ebp = &buf[sizeof (buf) - resid];
553 			off += sizeof (buf) - resid;
554 		}
555 		c = *bp++;
556 		switch (parse) {
557 		case START:
558 			/* Initilize all per file line state */
559 			tok = status;
560 			parse = TOK;
561 			/*FALLTHROUGH*/
562 		case TOK:
563 			if (c == '#') {
564 				/* Comment through end of line */
565 				parse = EOL;
566 				break;
567 			}
568 			if (isalpha(c) || c == '=') {
569 				if (c != *tok++) {
570 					/* Only know one token, skip */
571 					parse = EOL;
572 				}
573 			} else if (c == '\n') {
574 				/*
575 				 * Found EOL, if tok found done,
576 				 * else start on next-line.
577 				 */
578 				if (*tok == NULL) {
579 					nl7c_enabled = B_TRUE;
580 					goto done;
581 				}
582 				parse = START;
583 			} else {
584 				/* Unexpected char, skip */
585 				parse = EOL;
586 			}
587 			break;
588 
589 		case EOL:
590 			if (c == '\n') {
591 				/* Found EOL, start on next line */
592 				parse = START;
593 			}
594 			break;
595 		}
596 
597 	}
598 done:
599 	(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
600 	VN_RELE(vp);
601 }
602 
603 /*
604  * Open and read each line from "/etc/nca/ncalogd.conf" and parse for
605  * the tokens and token text (i.e. key and value ncalogd.conf(4)):
606  *
607  *	status=enabled
608  *
609  *	logd_file_size=[0-9]+
610  *
611  *	logd_file_name=["]filename( filename)*["]
612  */
613 
614 static int	file_size = 1000000;
615 static caddr_t	fnv[NCA_FIOV_SZ];
616 
617 static void
618 ncalogdconf_read(void)
619 {
620 	int	ret;
621 	struct vnode *vp;
622 	char	c;
623 	int	sz;
624 	ssize_t resid;
625 	char	buf[1024];
626 	char	*ebp = &buf[sizeof (buf)];
627 	char	*bp = ebp;
628 	offset_t off = 0;
629 	enum parse_e {START, TOK, TEXT, EOL} parse = START;
630 	char	*tokstatus = "status\0enabled";
631 	char	*toksize = "logd_file_size";
632 	char	*tokfile = "logd_path_name";
633 	char	*tokstatusp;
634 	char	*toksizep;
635 	char	*tokfilep;
636 	char	*tok;
637 	int	tokdelim = 0;
638 	char	*ncalogd = "/etc/nca/ncalogd.conf";
639 	char	*ncadeflog = "/var/nca/log";
640 	char	file[TYPICALMAXPATHLEN] = {0};
641 	char	*fp = file;
642 	caddr_t	*fnvp = fnv;
643 
644 	ret = vn_open(ncalogd, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0);
645 	if (ret == ENOENT) {
646 		/* No ncalogd file, nothing to do */
647 		return;
648 	}
649 	if (ret != 0) {
650 		/* Error of some sort, tell'm about it */
651 		cmn_err(CE_WARN, "ncalogdconf_read: %s: open error(%d).",
652 		    ncalogd, ret);
653 		return;
654 	}
655 	/*
656 	 * Read ncalogd.conf one buf[] at a time, parse one char at a time.
657 	 */
658 	for (;;) {
659 		if (bp == ebp) {
660 			/* Nothing left in buf[], read another */
661 			ret = vn_rdwr(UIO_READ, vp, buf, sizeof (buf), off,
662 			    UIO_SYSSPACE, 0, (rlim64_t)0, CRED(), &resid);
663 			if (ret != 0) {
664 				/* Error of some sort, tell'm about it */
665 				cmn_err(CE_WARN, "%s: read error %d",
666 					ncalogd, ret);
667 				break;
668 			}
669 			if (resid == sizeof (buf)) {
670 				/* EOF, done */
671 				break;
672 			}
673 			/* Initilize per buf[] state */
674 			bp = buf;
675 			ebp = &buf[sizeof (buf) - resid];
676 			off += sizeof (buf) - resid;
677 		}
678 		c = *bp++;
679 		switch (parse) {
680 		case START:
681 			/* Initilize all per file line state */
682 			tokstatusp = tokstatus;
683 			toksizep = toksize;
684 			tokfilep = tokfile;
685 			tok = NULL;
686 			parse = TOK;
687 			sz = 0;
688 			/*FALLTHROUGH*/
689 		case TOK:
690 			if (isalpha(c) || c == '_') {
691 				/*
692 				 * Found a valid tok char, if matches
693 				 * any of the tokens continue else NULL
694 				 * then string pointer.
695 				 */
696 				if (tokstatusp != NULL && c != *tokstatusp++)
697 					tokstatusp = NULL;
698 				if (toksizep != NULL && c != *toksizep++)
699 					toksizep = NULL;
700 				if (tokfilep != NULL && c != *tokfilep++)
701 					tokfilep = NULL;
702 
703 				if (tokstatusp == NULL &&
704 				    toksizep == NULL &&
705 				    tokfilep == NULL) {
706 					/*
707 					 * All tok string pointers are NULL
708 					 * so skip rest of line.
709 					 */
710 					parse = EOL;
711 				}
712 			} else if (c == '=') {
713 				/*
714 				 * Found tok separator, if tok found get
715 				 * tok text, else skip rest of line.
716 				 */
717 				if (tokstatusp != NULL && *tokstatusp == NULL)
718 					tok = tokstatus;
719 				else if (toksizep != NULL && *toksizep == NULL)
720 					tok = toksize;
721 				else if (tokfilep != NULL && *tokfilep == NULL)
722 					tok = tokfile;
723 				if (tok != NULL)
724 					parse = TEXT;
725 				else
726 					parse = EOL;
727 			} else if (c == '\n') {
728 				/* Found EOL, start on next line */
729 				parse = START;
730 			} else {
731 				/* Comment or unknown char, skip rest of line */
732 				parse = EOL;
733 			}
734 			break;
735 		case TEXT:
736 			if (c == '\n') {
737 				/*
738 				 * Found EOL, finish up tok text processing
739 				 * (if any) and start on next line.
740 				 */
741 				if (tok == tokstatus) {
742 					if (*++tokstatusp == NULL)
743 						nl7c_logd_enabled = B_TRUE;
744 				} else if (tok == toksize) {
745 					file_size = sz;
746 				} else if (tok == tokfile) {
747 					if (tokdelim == 0) {
748 						/* Non delimited path name */
749 						*fnvp++ = strdup(file);
750 					} else if (fp != file) {
751 						/* No closing delimiter */
752 						/*EMPTY*/;
753 					}
754 				}
755 				parse = START;
756 			} else if (tok == tokstatus) {
757 				if (! isalpha(c) || *++tokstatusp == NULL ||
758 				    c != *tokstatusp) {
759 					/* Not enabled, skip line */
760 					parse = EOL;
761 				}
762 			} else if (tok == toksize) {
763 				if (isdigit(c)) {
764 					sz *= 10;
765 					sz += c - '0';
766 				} else {
767 					/* Not a decimal digit, skip line */
768 					parse = EOL;
769 				}
770 			} else {
771 				/* File name */
772 				if (c == '"' && tokdelim++ == 0) {
773 					/* Opening delimiter, skip */
774 					/*EMPTY*/;
775 				} else if (c == '"' || c == ' ') {
776 					/* List delim or filename seperator */
777 					*fnvp++ = strdup(file);
778 					fp = file;
779 				} else if (fp < &file[sizeof (file) - 1]) {
780 					/* Filename char */
781 					*fp++ = c;
782 				} else {
783 					/* Filename to long, skip line */
784 					parse = EOL;
785 				}
786 			}
787 			break;
788 
789 		case EOL:
790 			if (c == '\n') {
791 				/* Found EOL, start on next line */
792 				parse = START;
793 			}
794 			break;
795 		}
796 
797 	}
798 done:
799 	(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED());
800 	VN_RELE(vp);
801 
802 	if (nl7c_logd_enabled) {
803 		if (fnvp == fnv) {
804 			/*
805 			 * No logfile was specified and found so
806 			 * so use defualt NCA log file path.
807 			 */
808 			*fnvp++ = strdup(ncadeflog);
809 		}
810 		if (fnvp < &fnv[NCA_FIOV_SZ]) {
811 			/* NULL terminate list */
812 			*fnvp = NULL;
813 		}
814 	}
815 }
816 
817 void
818 nl7clogd_startup(void)
819 {
820 	static kmutex_t startup;
821 
822 	/*
823 	 * Called on the first log() attempt, have to wait until then to
824 	 * initialize logd as at logdconf_read() the root fs is read-only.
825 	 */
826 	mutex_enter(&startup);
827 	if (nl7c_logd_started) {
828 		/* Lost the race, nothing todo */
829 		mutex_exit(&startup);
830 		return;
831 	}
832 	nl7c_logd_started = B_TRUE;
833 	if (! nl7c_logd_init(file_size, fnv)) {
834 		/* Failure, disable logging */
835 		nl7c_logd_enabled = B_FALSE;
836 		cmn_err(CE_WARN, "nl7clogd_startup: failed, disabling loggin");
837 		mutex_exit(&startup);
838 		return;
839 	}
840 	mutex_exit(&startup);
841 }
842 
843 
844 void
845 nl7c_startup()
846 {
847 	ncalogdconf_read();
848 	nl7c_uri_init();
849 	nl7c_nca_init();
850 
851 	nl7c_enabled = B_TRUE;
852 }
853 
854 void
855 nl7c_init()
856 {
857 	/* Open, read, and parse the NCA kmod configuration file */
858 	ncakmodconf_read();
859 
860 	if (nl7c_enabled) {
861 		/*
862 		 * NL7C is enabled so open, read, and parse
863 		 * the NCA address/port configuration file
864 		 * and call startup() to finish config/init.
865 		 */
866 		ncaportconf_read();
867 		nl7c_startup();
868 	}
869 }
870 
871 /*
872  * The main processing function called by accept() on a newly created
873  * socket prior to returning it to the caller of accept().
874  *
875  * Here data is read from the socket until a completed L7 request parse
876  * is completed. Data will be read in the context of the user thread
877  * which called accept(), when parse has been completed either B_TRUE
878  * or B_FALSE will be returned.
879  *
880  * If NL7C successfully process the L7 protocol request, i.e. generates
881  * a response, B_TRUE will be returned.
882  *
883  * Else, B_FALSE will be returned if NL7C can't process the request:
884  *
885  * 1) Couldn't locate a URI within the request.
886  *
887  * 2) URI scheme not reqcognized.
888  *
889  * 3) A request which can't be procesed.
890  *
891  * 4) A request which could be processed but NL7C dosen't currently have
892  *    the response data. In which case NL7C will parse the returned response
893  *    from the application for possible caching for subsequent request(s).
894  */
895 
896 volatile uint64_t nl7c_proc_cnt = 0;
897 volatile uint64_t nl7c_proc_error = 0;
898 volatile uint64_t nl7c_proc_ETIME = 0;
899 volatile uint64_t nl7c_proc_again = 0;
900 volatile uint64_t nl7c_proc_next = 0;
901 volatile uint64_t nl7c_proc_rcv = 0;
902 volatile uint64_t nl7c_proc_noLRI = 0;
903 
904 boolean_t
905 nl7c_process(struct sonode *so, boolean_t nonblocking, int max_mblk)
906 {
907 	vnode_t	*vp = SOTOV(so);
908 	mblk_t	*mp = so->so_nl7c_rcv_mp;
909 	mblk_t	*tmp;
910 	clock_t	timout;
911 	uchar_t pri;
912 	int 	pflag;
913 	mblk_t	*rmp;
914 	rval_t	rval;
915 	int	error;
916 	boolean_t ret;
917 	boolean_t more;
918 
919 	nl7c_proc_cnt++;
920 
921 	error = so_lock_read_intr(so, nonblocking ? FNDELAY|FNONBLOCK : 0);
922 	if (error) {
923 		/* Couldn't read lock, pass on this socket */
924 		so->so_nl7c_flags = 0;
925 		ret = B_FALSE;
926 		nl7c_proc_noLRI++;
927 		goto out;
928 	}
929 	mutex_exit(&so->so_lock);
930 
931 	if (mp != NULL) {
932 		/*
933 		 * Some data from a previous process() call,
934 		 * move to rmp so we skip the first kstrgetmsg().
935 		 */
936 		rmp = mp;
937 		mp = NULL;
938 	} else
939 		rmp = NULL;
940 
941 	/* Initialize some kstrgetmsg() constants */
942 	pflag = MSG_ANY;
943 	pri = 0;
944 	if (nonblocking)
945 		timout = 0;
946 	else
947 		timout = -1;
948 
949 	do {
950 		if (rmp == NULL) {
951 			rval.r_vals = 0;
952 			error = kstrgetmsg(vp, &rmp, NULL, &pri, &pflag,
953 					timout, &rval);
954 
955 			if (error) {
956 				if (error == ETIME) {
957 					/* Timeout */
958 					error = 0;
959 					nl7c_proc_ETIME++;
960 				} else {
961 					/* Error of some sort */
962 					nl7c_proc_error++;
963 				}
964 				ret = B_FALSE;
965 				break;
966 			}
967 
968 			if (rmp == NULL) {
969 				/* No more data */
970 				ret = B_FALSE;
971 				break;
972 			}
973 		}
974 		if (mp == NULL) {
975 			/* First msg, common case */
976 			mp = rmp;
977 			so->so_nl7c_rcv_mp = mp;
978 		} else {
979 			/*
980 			 * Add msg to tail.
981 			 *
982 			 * Note, mp == NULL first pass through the loop
983 			 * and tmp is set below.
984 			 */
985 			/*LINTED*/
986 			tmp->b_cont = rmp;
987 		}
988 
989 		/* New tail */
990 		tmp = rmp;
991 		rmp = NULL;
992 		while (tmp->b_cont != NULL)
993 			tmp = tmp->b_cont;
994 
995 	again:
996 		more = nl7c_parse(so, nonblocking, &ret, max_mblk);
997 
998 		if (more == B_FALSE && ret == B_TRUE &&
999 		    (so->so_nl7c_flags & NL7C_SOPERSIST)) {
1000 			/*
1001 			 * Parse complete, socket is persistent so
1002 			 * process the next request (if any).
1003 			 */
1004 			if (so->so_nl7c_rcv_mp) {
1005 				/* More recv-side data, pipelined ? */
1006 				nl7c_proc_again++;
1007 				goto again;
1008 			}
1009 			nl7c_proc_next++;
1010 			if (nonblocking)
1011 				timout = 0;
1012 			else
1013 				timout = 15000; /* 15 seconds */
1014 			mp = NULL;
1015 			more = B_TRUE;
1016 			ret = B_FALSE;
1017 		}
1018 
1019 	} while (more);
1020 
1021 	if (error) {
1022 		/*
1023 		 * An error of some sort occured above, save the error
1024 		 * value for passing the socket onto the accept()er.
1025 		 *
1026 		 * Update the saved rval_t with the error value and
1027 		 * clear the NL7C so_state so the socket accept() can
1028 		 * complete, return B_FALSE.
1029 		 */
1030 		so->so_nl7c_rcv_rval = (int64_t)error;
1031 		so->so_nl7c_flags = 0;
1032 		ret = B_FALSE;
1033 	} else if (so->so_nl7c_rcv_mp) {
1034 		/*
1035 		 * Recieve side data leftover so save the last rval_t
1036 		 * from above for subsequent read() processing and if
1037 		 * POLLIN is indicated (i.e. a read-side poll() may be
1038 		 * pending) do a pollwakeup().
1039 		 */
1040 		nl7c_proc_rcv++;
1041 		so->so_nl7c_rcv_rval = rval.r_vals;
1042 	}
1043 	mutex_enter(&so->so_lock);
1044 	so_unlock_read(so);
1045 out:
1046 	return (ret);
1047 }
1048