|
|
1.1 ! root 1: /* tcp.c - MIB realization of the TCP group */ ! 2: ! 3: #ifndef lint ! 4: static char *rcsid = "$Header: /f/osi/snmp/RCS/tcp.c,v 7.7 90/07/09 14:49:43 mrose Exp $"; ! 5: #endif ! 6: ! 7: /* ! 8: * $Header: /f/osi/snmp/RCS/tcp.c,v 7.7 90/07/09 14:49:43 mrose Exp $ ! 9: * ! 10: * Contributed by NYSERNet Inc. This work was partially supported by the ! 11: * U.S. Defense Advanced Research Projects Agency and the Rome Air Development ! 12: * Center of the U.S. Air Force Systems Command under contract number ! 13: * F30602-88-C-0016. ! 14: * ! 15: * ! 16: * $Log: tcp.c,v $ ! 17: * Revision 7.7 90/07/09 14:49:43 mrose ! 18: * sync ! 19: * ! 20: * Revision 7.6 90/06/05 20:47:27 mrose ! 21: * touch-up ! 22: * ! 23: * Revision 7.5 90/04/23 00:08:16 mrose ! 24: * touch-up ! 25: * ! 26: * Revision 7.4 90/04/18 08:52:06 mrose ! 27: * oid_normalize ! 28: * ! 29: * Revision 7.3 90/02/27 18:50:07 mrose ! 30: * unix stuff ! 31: * ! 32: * Revision 7.2 90/01/27 08:22:09 mrose ! 33: * touch-up ! 34: * ! 35: * Revision 7.1 89/12/11 10:40:40 mrose ! 36: * touch-up ! 37: * ! 38: * Revision 7.0 89/11/23 22:23:35 mrose ! 39: * Release 6.0 ! 40: * ! 41: */ ! 42: ! 43: /* ! 44: * NOTICE ! 45: * ! 46: * Acquisition, use, and distribution of this module and related ! 47: * materials are subject to the restrictions of a license agreement. ! 48: * Consult the Preface in the User's Manual for the full terms of ! 49: * this agreement. ! 50: * ! 51: */ ! 52: ! 53: ! 54: #include <stdio.h> ! 55: #include "mib.h" ! 56: #ifdef BSD43_Tahoe ! 57: #include <machine/endian.h> ! 58: #endif ! 59: ! 60: #include "internet.h" ! 61: #ifdef BSD44 ! 62: #include <machine/machparam.h> ! 63: #endif ! 64: #include <sys/protosw.h> ! 65: #include <sys/socketvar.h> ! 66: #include <net/route.h> ! 67: #include <netinet/in_systm.h> ! 68: #ifdef BSD44 ! 69: #include <netinet/ip.h> ! 70: #endif ! 71: #include <netinet/in_pcb.h> ! 72: #include <netinet/tcp.h> ! 73: #include <netinet/tcp_fsm.h> ! 74: #include <netinet/tcp_timer.h> ! 75: #include <netinet/tcp_var.h> ! 76: ! 77: /* */ ! 78: ! 79: #define RTOA_OTHER 1 /* tcpRtoAlgorithm */ ! 80: #define RTOA_VANJ 4 /* .. */ ! 81: ! 82: #define MXCN_NONE (-1) /* tcpMaxConn */ ! 83: ! 84: ! 85: static struct tcpstat tcpstat; ! 86: ! 87: static int tcpConnections; ! 88: ! 89: /* */ ! 90: ! 91: #define tcpRtoAlgorithm 0 ! 92: #define tcpRtoMin 1 ! 93: #define tcpRtoMax 2 ! 94: #define tcpMaxConn 3 ! 95: #define tcpActiveOpens 4 ! 96: #define tcpPassiveOpens 5 ! 97: #define tcpAttemptFails 6 ! 98: #define tcpEstabResets 7 ! 99: #define tcpCurrEstab 8 ! 100: #define tcpInSegs 9 ! 101: #define tcpOutSegs 10 ! 102: #define tcpRetransSegs 11 ! 103: #ifndef SUNOS4 ! 104: #define tcpInErrs 12 ! 105: #else ! 106: #undef tcpInErrs 12 ! 107: #endif ! 108: #undef tcpOutRsts 13 /* NOT IMPLEMENTED */ ! 109: ! 110: ! 111: static int o_tcp (oi, v, offset) ! 112: OI oi; ! 113: register struct type_SNMP_VarBind *v; ! 114: int offset; ! 115: { ! 116: int ifvar; ! 117: register struct tcpstat *tcps = &tcpstat; ! 118: register OID oid = oi -> oi_name; ! 119: register OT ot = oi -> oi_type; ! 120: static int lastq = -1; ! 121: ! 122: ifvar = (int) ot -> ot_info; ! 123: switch (offset) { ! 124: case type_SNMP_PDUs_get__request: ! 125: if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + 1 ! 126: || oid -> oid_elements[oid -> oid_nelem - 1] != 0) ! 127: return int_SNMP_error__status_noSuchName; ! 128: break; ! 129: ! 130: case type_SNMP_PDUs_get__next__request: ! 131: if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) { ! 132: OID new; ! 133: ! 134: if ((new = oid_extend (oid, 1)) == NULLOID) ! 135: return int_SNMP_error__status_genErr; ! 136: new -> oid_elements[new -> oid_nelem - 1] = 0; ! 137: ! 138: if (v -> name) ! 139: free_SNMP_ObjectName (v -> name); ! 140: v -> name = new; ! 141: } ! 142: else ! 143: return NOTOK; ! 144: break; ! 145: ! 146: default: ! 147: return int_SNMP_error__status_genErr; ! 148: } ! 149: ! 150: switch (ifvar) { ! 151: case tcpCurrEstab: ! 152: if (get_connections () == NOTOK) ! 153: return int_SNMP_error__status_genErr; ! 154: break; ! 155: ! 156: default: ! 157: if (quantum != lastq) { ! 158: lastq = quantum; ! 159: ! 160: if (getkmem (nl + N_TCPSTAT, (caddr_t) tcps, sizeof *tcps) ! 161: == NOTOK) ! 162: return int_SNMP_error__status_genErr; ! 163: } ! 164: break; ! 165: } ! 166: ! 167: switch (ifvar) { ! 168: case tcpRtoAlgorithm: ! 169: #ifdef TCPTV_REXMTMAX ! 170: return o_integer (oi, v, RTOA_VANJ); ! 171: #else ! 172: return o_integer (oi, v, RTOA_OTHER); ! 173: #endif ! 174: ! 175: case tcpRtoMin: ! 176: return o_integer (oi, v, TCPTV_MIN * 100); /* milliseconds */ ! 177: ! 178: #ifdef TCPTV_REXMTMAX ! 179: case tcpRtoMax: ! 180: return o_integer (oi, v, TCPTV_REXMTMAX * 100); /* .. */ ! 181: #endif ! 182: ! 183: case tcpMaxConn: ! 184: return o_integer (oi, v, MXCN_NONE); ! 185: ! 186: #ifdef TCPTV_REXMTMAX ! 187: case tcpActiveOpens: ! 188: return o_integer (oi, v, tcps -> tcps_connattempt); ! 189: ! 190: case tcpPassiveOpens: ! 191: return o_integer (oi, v, tcps -> tcps_accepts); ! 192: ! 193: case tcpAttemptFails: ! 194: return o_integer (oi, v, tcps -> tcps_conndrops); ! 195: ! 196: case tcpEstabResets: ! 197: return o_integer (oi, v, tcps -> tcps_drops); ! 198: #endif ! 199: ! 200: case tcpCurrEstab: ! 201: return o_integer (oi, v, tcpConnections); ! 202: ! 203: #ifdef TCPTV_REXMTMAX ! 204: case tcpInSegs: ! 205: return o_integer (oi, v, tcps -> tcps_rcvtotal); ! 206: ! 207: case tcpOutSegs: ! 208: return o_integer (oi, v, tcps -> tcps_sndtotal ! 209: - tcps -> tcps_sndrexmitpack); ! 210: ! 211: case tcpRetransSegs: ! 212: return o_integer (oi, v, tcps -> tcps_sndrexmitpack); ! 213: #endif ! 214: ! 215: #ifdef tcpInErrs ! 216: case tcpInErrs: ! 217: #ifndef BSD44 ! 218: return o_integer (oi, v, tcps -> tcps_badsegs); ! 219: #else ! 220: return o_integer (oi, v, tcps -> tcps_rcvbadsum ! 221: + tcps -> tcps_rcvbadoff ! 222: + tcps -> tcps_rcvshort); ! 223: #endif ! 224: #endif ! 225: ! 226: default: ! 227: return int_SNMP_error__status_noSuchName; ! 228: } ! 229: } ! 230: ! 231: /* */ ! 232: ! 233: static int tcp_states[TCP_NSTATES]; ! 234: ! 235: ! 236: struct tcptab { ! 237: #define TT_SIZE 10 /* object instance */ ! 238: unsigned int tt_instance[TT_SIZE]; ! 239: ! 240: struct inpcb tt_pcb; /* protocol control block */ ! 241: ! 242: struct socket tt_socb; /* socket info */ ! 243: ! 244: struct tcpcb tt_tcpb; /* TCP info */ ! 245: ! 246: struct tcptab *tt_next; ! 247: }; ! 248: ! 249: static struct tcptab *tts = NULL; ! 250: ! 251: ! 252: struct tcptab *get_tcpent (); ! 253: ! 254: /* */ ! 255: ! 256: #define tcpConnState 0 ! 257: #define tcpConnLocalAddress 1 ! 258: #define tcpConnLocalPort 2 ! 259: #define tcpConnRemAddress 3 ! 260: #define tcpConnRemPort 4 ! 261: #define unixTcpConnSendQ 5 ! 262: #define unixTcpConnRecvQ 6 ! 263: ! 264: ! 265: static int o_tcp_conn (oi, v, offset) ! 266: OI oi; ! 267: register struct type_SNMP_VarBind *v; ! 268: int offset; ! 269: { ! 270: int ifvar; ! 271: register int i; ! 272: register unsigned int *ip, ! 273: *jp; ! 274: register struct tcptab *tt; ! 275: struct sockaddr_in netaddr; ! 276: register OID oid = oi -> oi_name; ! 277: OID new; ! 278: register OT ot = oi -> oi_type; ! 279: ! 280: if (get_connections () == NOTOK) ! 281: return int_SNMP_error__status_genErr; ! 282: ! 283: ifvar = (int) ot -> ot_info; ! 284: switch (offset) { ! 285: case type_SNMP_PDUs_get__request: ! 286: if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + TT_SIZE) ! 287: return int_SNMP_error__status_noSuchName; ! 288: if ((tt = get_tcpent (oid -> oid_elements + oid -> oid_nelem ! 289: - TT_SIZE, 0)) == NULL) ! 290: return int_SNMP_error__status_noSuchName; ! 291: break; ! 292: ! 293: case type_SNMP_PDUs_get__next__request: ! 294: if ((i = oid -> oid_nelem - ot -> ot_name -> oid_nelem) != 0 ! 295: && i < TT_SIZE) { ! 296: for (jp = (ip = oid -> oid_elements + ot -> ot_name -> oid_nelem - 1) + i; ! 297: jp > ip; ! 298: jp--) ! 299: if (*jp != 0) ! 300: break; ! 301: if (jp == ip) ! 302: oid -> oid_nelem = ot -> ot_name -> oid_nelem; ! 303: else { ! 304: if ((new = oid_normalize (oid, TT_SIZE - i, 65536)) ! 305: == NULLOID) ! 306: return int_SNMP_error__status_genErr; ! 307: if (v -> name) ! 308: free_SNMP_ObjectName (v -> name); ! 309: v -> name = oid = new; ! 310: } ! 311: } ! 312: ! 313: if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) { ! 314: if ((tt = tts) == NULL) ! 315: return NOTOK; ! 316: ! 317: if ((new = oid_extend (oid, TT_SIZE)) == NULLOID) ! 318: return int_SNMP_error__status_genErr; ! 319: ip = new -> oid_elements + new -> oid_nelem - TT_SIZE; ! 320: jp = tt -> tt_instance; ! 321: for (i = TT_SIZE; i > 0; i--) ! 322: *ip++ = *jp++; ! 323: ! 324: if (v -> name) ! 325: free_SNMP_ObjectName (v -> name); ! 326: v -> name = new; ! 327: } ! 328: else { ! 329: if ((tt = get_tcpent (ip = oid -> oid_elements ! 330: + oid -> oid_nelem - TT_SIZE, 1)) ! 331: == NULL) ! 332: return NOTOK; ! 333: ! 334: jp = tt -> tt_instance; ! 335: for (i = TT_SIZE; i > 0; i--) ! 336: *ip++ = *jp++; ! 337: } ! 338: break; ! 339: ! 340: default: ! 341: return int_SNMP_error__status_genErr; ! 342: } ! 343: ! 344: switch (ifvar) { ! 345: case tcpConnState: ! 346: if ((i = tt -> tt_tcpb.t_state) < 0 ! 347: || i >= sizeof tcp_states / sizeof tcp_states[0]) ! 348: return int_SNMP_error__status_genErr; ! 349: return o_integer (oi, v, tcp_states[i]); ! 350: ! 351: case tcpConnLocalAddress: ! 352: netaddr.sin_addr = tt -> tt_pcb.inp_laddr; /* struct copy */ ! 353: return o_ipaddr (oi, v, &netaddr); ! 354: ! 355: case tcpConnLocalPort: ! 356: return o_integer (oi, v, ntohs (tt -> tt_pcb.inp_lport) & 0xffff); ! 357: ! 358: case tcpConnRemAddress: ! 359: netaddr.sin_addr = tt -> tt_pcb.inp_faddr; /* struct copy */ ! 360: return o_ipaddr (oi, v, &netaddr); ! 361: ! 362: case tcpConnRemPort: ! 363: return o_integer (oi, v, ntohs (tt -> tt_pcb.inp_fport) & 0xffff); ! 364: ! 365: case unixTcpConnSendQ: ! 366: return o_integer (oi, v, tt -> tt_socb.so_snd.sb_cc); ! 367: ! 368: case unixTcpConnRecvQ: ! 369: return o_integer (oi, v, tt -> tt_socb.so_rcv.sb_cc); ! 370: ! 371: default: ! 372: return int_SNMP_error__status_noSuchName; ! 373: } ! 374: } ! 375: ! 376: /* */ ! 377: ! 378: static int tt_compar (a, b) ! 379: struct tcptab **a, ! 380: **b; ! 381: { ! 382: return elem_cmp ((*a) -> tt_instance, TT_SIZE, ! 383: (*b) -> tt_instance, TT_SIZE); ! 384: } ! 385: ! 386: ! 387: static int get_connections () { ! 388: register int i; ! 389: register unsigned int *cp; ! 390: register struct tcptab *ts, ! 391: *tp, ! 392: **tsp; ! 393: register struct inpcb *ip; ! 394: struct inpcb *head, ! 395: tcb; ! 396: struct nlist nzs; ! 397: register struct nlist *nz = &nzs; ! 398: static int first_time = 1; ! 399: static int lastq = -1; ! 400: ! 401: if (quantum == lastq) ! 402: return OK; ! 403: lastq = quantum; ! 404: ! 405: for (ts = tts; ts; ts = tp) { ! 406: tp = ts -> tt_next; ! 407: ! 408: free ((char *) ts); ! 409: } ! 410: tts = NULL; ! 411: ! 412: if (getkmem (nl + N_TCB, (char *) &tcb, sizeof tcb) == NOTOK) ! 413: return NOTOK; ! 414: head = (struct inpcb *) nl[N_TCB].n_value; ! 415: ! 416: tsp = &tts, i = 0; ! 417: ip = &tcb; ! 418: while (ip -> inp_next != head) { ! 419: if ((ts = (struct tcptab *) calloc (1, sizeof *ts)) == NULL) ! 420: adios (NULLCP, "out of memory"); ! 421: /* no check needed for duplicate connections... */ ! 422: *tsp = ts, tsp = &ts -> tt_next, i++; ! 423: ! 424: nz -> n_name = "struct inpcb", ! 425: nz -> n_value = (unsigned long) ip -> inp_next; ! 426: if (getkmem (nz, (caddr_t) &ts -> tt_pcb, sizeof ts -> tt_pcb) ! 427: == NOTOK) ! 428: return NOTOK; ! 429: ip = &ts -> tt_pcb; ! 430: ! 431: nz ->n_name = "struct socket", ! 432: nz -> n_value = (unsigned long) ip -> inp_socket; ! 433: if (getkmem (nz, (caddr_t) &ts -> tt_socb, sizeof ts -> tt_socb) ! 434: == NOTOK) ! 435: return NOTOK; ! 436: ! 437: nz ->n_name = "struct tcb", ! 438: nz -> n_value = (unsigned long) ip -> inp_ppcb; ! 439: if (getkmem (nz, (caddr_t) &ts -> tt_tcpb, sizeof ts -> tt_tcpb) ! 440: == NOTOK) ! 441: return NOTOK; ! 442: ! 443: cp = ts -> tt_instance; ! 444: cp += ipaddr2oid (cp, &ip -> inp_laddr); ! 445: *cp++ = ntohs (ip -> inp_lport) & 0xffff; ! 446: cp += ipaddr2oid (cp, &ip -> inp_faddr); ! 447: *cp++ = ntohs (ip -> inp_fport) & 0xffff; ! 448: ! 449: if (debug && first_time) { ! 450: OIDentifier oids; ! 451: ! 452: oids.oid_elements = ts -> tt_instance; ! 453: oids.oid_nelem = TT_SIZE; ! 454: advise (LLOG_DEBUG, NULLCP, ! 455: "add connection: %s", sprintoid (&oids)); ! 456: } ! 457: } ! 458: first_time = 0; ! 459: ! 460: if ((tcpConnections = i) > 1) { ! 461: register struct tcptab **base, ! 462: **tse; ! 463: ! 464: if ((base = (struct tcptab **) malloc ((unsigned) (i * sizeof *base))) ! 465: == NULL) ! 466: adios (NULLCP, "out of memory"); ! 467: ! 468: tse = base; ! 469: for (ts = tts; ts; ts = ts -> tt_next) ! 470: *tse++ = ts; ! 471: ! 472: qsort ((char *) base, i, sizeof *base, tt_compar); ! 473: ! 474: tsp = base; ! 475: ts = tts = *tsp++; ! 476: ! 477: while (tsp < tse) { ! 478: ts -> tt_next = *tsp; ! 479: ts = *tsp++; ! 480: } ! 481: ts -> tt_next = NULL; ! 482: ! 483: free ((char *) base); ! 484: } ! 485: ! 486: return OK; ! 487: } ! 488: ! 489: /* */ ! 490: ! 491: static struct tcptab *get_tcpent (ip, isnext) ! 492: register unsigned int *ip; ! 493: int isnext; ! 494: { ! 495: register struct tcptab *tt; ! 496: ! 497: for (tt = tts; tt; tt = tt -> tt_next) ! 498: switch (elem_cmp (tt -> tt_instance, TT_SIZE, ip, TT_SIZE)) { ! 499: case 0: ! 500: return (isnext ? tt -> tt_next : tt); ! 501: ! 502: case 1: ! 503: return (isnext ? tt : NULL); ! 504: } ! 505: ! 506: return NULL; ! 507: } ! 508: ! 509: /* */ ! 510: ! 511: init_tcp () { ! 512: register OT ot; ! 513: ! 514: if (ot = text2obj ("tcpRtoAlgorithm")) ! 515: ot -> ot_getfnx = o_tcp, ! 516: ot -> ot_info = (caddr_t) tcpRtoAlgorithm; ! 517: if (ot = text2obj ("tcpRtoMin")) ! 518: ot -> ot_getfnx = o_tcp, ! 519: ot -> ot_info = (caddr_t) tcpRtoMin; ! 520: #ifdef TCPTV_REXMTMAX ! 521: if (ot = text2obj ("tcpRtoMax")) ! 522: ot -> ot_getfnx = o_tcp, ! 523: ot -> ot_info = (caddr_t) tcpRtoMax; ! 524: #endif ! 525: if (ot = text2obj ("tcpMaxConn")) ! 526: ot -> ot_getfnx = o_tcp, ! 527: ot -> ot_info = (caddr_t) tcpMaxConn; ! 528: #ifdef TCPTV_REXMTMAX ! 529: if (ot = text2obj ("tcpActiveOpens")) ! 530: ot -> ot_getfnx = o_tcp, ! 531: ot -> ot_info = (caddr_t) tcpActiveOpens; ! 532: if (ot = text2obj ("tcpPassiveOpens")) ! 533: ot -> ot_getfnx = o_tcp, ! 534: ot -> ot_info = (caddr_t) tcpPassiveOpens; ! 535: if (ot = text2obj ("tcpAttemptFails")) ! 536: ot -> ot_getfnx = o_tcp, ! 537: ot -> ot_info = (caddr_t) tcpAttemptFails; ! 538: if (ot = text2obj ("tcpEstabResets")) ! 539: ot -> ot_getfnx = o_tcp, ! 540: ot -> ot_info = (caddr_t) tcpEstabResets; ! 541: #endif ! 542: if (ot = text2obj ("tcpCurrEstab")) ! 543: ot -> ot_getfnx = o_tcp, ! 544: ot -> ot_info = (caddr_t) tcpCurrEstab; ! 545: #ifdef TCPTV_REXMTMAX ! 546: if (ot = text2obj ("tcpInSegs")) ! 547: ot -> ot_getfnx = o_tcp, ! 548: ot -> ot_info = (caddr_t) tcpInSegs; ! 549: if (ot = text2obj ("tcpOutSegs")) ! 550: ot -> ot_getfnx = o_tcp, ! 551: ot -> ot_info = (caddr_t) tcpOutSegs; ! 552: if (ot = text2obj ("tcpRetransSegs")) ! 553: ot -> ot_getfnx = o_tcp, ! 554: ot -> ot_info = (caddr_t) tcpRetransSegs; ! 555: #endif ! 556: #ifdef tcpInErrs ! 557: if (ot = text2obj ("tcpInErrs")) ! 558: ot -> ot_getfnx = o_tcp, ! 559: ot -> ot_info = (caddr_t) tcpInErrs; ! 560: #endif ! 561: #ifdef tcpOutRsts ! 562: if (ot = text2obj ("tcpOutRsts")) ! 563: ot -> ot_getfnx = o_tcp, ! 564: ot -> ot_info = (caddr_t) tcpOutRsts; ! 565: #endif ! 566: ! 567: if (ot = text2obj ("tcpConnState")) ! 568: ot -> ot_getfnx = o_tcp_conn, ! 569: ot -> ot_info = (caddr_t) tcpConnState; ! 570: if (ot = text2obj ("tcpConnLocalAddress")) ! 571: ot -> ot_getfnx = o_tcp_conn, ! 572: ot -> ot_info = (caddr_t) tcpConnLocalAddress; ! 573: if (ot = text2obj ("tcpConnLocalPort")) ! 574: ot -> ot_getfnx = o_tcp_conn, ! 575: ot -> ot_info = (caddr_t) tcpConnLocalPort; ! 576: if (ot = text2obj ("tcpConnRemAddress")) ! 577: ot -> ot_getfnx = o_tcp_conn, ! 578: ot -> ot_info = (caddr_t) tcpConnRemAddress; ! 579: if (ot = text2obj ("tcpConnRemPort")) ! 580: ot -> ot_getfnx = o_tcp_conn, ! 581: ot -> ot_info = (caddr_t) tcpConnRemPort; ! 582: ! 583: if (ot = text2obj ("unixTcpConnSendQ")) ! 584: ot -> ot_getfnx = o_tcp_conn, ! 585: ot -> ot_info = (caddr_t) unixTcpConnSendQ; ! 586: if (ot = text2obj ("unixTcpConnRecvQ")) ! 587: ot -> ot_getfnx = o_tcp_conn, ! 588: ot -> ot_info = (caddr_t) unixTcpConnRecvQ; ! 589: ! 590: tcp_states[TCPS_CLOSED] = 1; ! 591: tcp_states[TCPS_LISTEN] = 2; ! 592: tcp_states[TCPS_SYN_SENT] = 3; ! 593: tcp_states[TCPS_SYN_RECEIVED] = 4; ! 594: tcp_states[TCPS_ESTABLISHED] = 5; ! 595: tcp_states[TCPS_CLOSE_WAIT] = 8; ! 596: tcp_states[TCPS_FIN_WAIT_1] = 6; ! 597: tcp_states[TCPS_CLOSING] = 10; ! 598: tcp_states[TCPS_LAST_ACK] = 9; ! 599: tcp_states[TCPS_FIN_WAIT_2] = 7; ! 600: tcp_states[TCPS_TIME_WAIT] = 11; ! 601: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.