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