Home | History | Annotate | Download | only in snoop
      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 (c) 1998,2000 by Sun Microsystems, Inc.
     24  * All rights reserved.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdio.h>
     30 #include <arpa/inet.h>
     31 #include <stdlib.h>
     32 #include <string.h>
     33 #include <sys/time.h>
     34 #include <iconv.h>
     35 #include "snoop.h"
     36 #include "slp.h"
     37 
     38 #define	MAXSUMLEN 30
     39 
     40 /* define VERIFYSLP to enable full message checking in summary mode */
     41 #define	VERIFYSLP
     42 
     43 /* Globals -- ugly, yes, but fast and easy in macros */
     44 static int msglength;
     45 static int retlength;
     46 static char *msgend;	/* the end of the summary message buffer */
     47 static char *p;		/* current position in the packet */
     48 static char *msgbuf;	/* message buffer for summary mode */
     49 static boolean_t url_auth	= B_FALSE;
     50 static boolean_t attr_auth	= B_FALSE;
     51 static boolean_t fresh		= B_FALSE;
     52 static boolean_t overflow	= B_FALSE;
     53 static int v1_charset		= 0;	/* character set; only in V1 */
     54 
     55 /* Entry points for parsing the protocol */
     56 static int interpret_slp_v1(int, struct slpv1_hdr *, int);
     57 static int interpret_slp_v2(int, struct slpv2_hdr *, int);
     58 
     59 /* header parsing */
     60 static int v1_header(int, struct slpv1_hdr *, int);
     61 static int v2_header(int, struct slpv2_hdr *, int *, int);
     62 static int v2_finish(struct slpv2_hdr *, int);
     63 
     64 /* V2 auth blocks */
     65 static int slpv2_authblock(int);
     66 
     67 /* From snoop_rport: */
     68 extern int add_transient(int, int (*)());
     69 
     70 /*
     71  * Functions for parsing each protocol message
     72  * Each function takes the interpreter's flags argument as its input
     73  * parameter, and returns 1 on success, or 0 on message corruption.
     74  * retlength is set as a side-effect in summary mode.
     75  */
     76 static int v2_srv_rqst(int);
     77 static int v2_srv_rply(int);
     78 static int v2_srv_reg(int);
     79 static int v2_srv_dereg(int);
     80 static int v2_srv_ack(int);
     81 static int v2_attr_rqst(int);
     82 static int v2_attr_rply(int);
     83 static int v2_daadvert(int);
     84 static int v2_srv_type_rqst(int);
     85 static int v2_srv_type_rply(int);
     86 static int v2_saadvert(int);
     87 
     88 static int v1_srv_rqst(int);
     89 static int v1_srv_rply(int);
     90 static int v1_srv_reg(int);
     91 static int v1_srv_dereg(int);
     92 static int v1_srv_ack(int);
     93 static int v1_attr_rqst(int);
     94 static int v1_attr_rply(int);
     95 static int v1_daadvert(int);
     96 static int v1_srv_type_rqst(int);
     97 static int v1_srv_type_rply(int);
     98 
     99 /*
    100  * The dispatch tables for handling individual messages, keyed by
    101  * function number.
    102  */
    103 typedef int function_handler();
    104 
    105 #define	V2_MAX_FUNCTION	11
    106 
    107 static function_handler *v2_functions[V2_MAX_FUNCTION + 1] = {
    108 	(function_handler *) NULL,
    109 	(function_handler *) v2_srv_rqst,
    110 	(function_handler *) v2_srv_rply,
    111 	(function_handler *) v2_srv_reg,
    112 	(function_handler *) v2_srv_dereg,
    113 	(function_handler *) v2_srv_ack,
    114 	(function_handler *) v2_attr_rqst,
    115 	(function_handler *) v2_attr_rply,
    116 	(function_handler *) v2_daadvert,
    117 	(function_handler *) v2_srv_type_rqst,
    118 	(function_handler *) v2_srv_type_rply,
    119 	(function_handler *) v2_saadvert };
    120 
    121 #define	V1_MAX_FUNCTION	10
    122 
    123 static function_handler *v1_functions[V1_MAX_FUNCTION + 1] = {
    124 	(function_handler *) NULL,
    125 	(function_handler *) v1_srv_rqst,
    126 	(function_handler *) v1_srv_rply,
    127 	(function_handler *) v1_srv_reg,
    128 	(function_handler *) v1_srv_dereg,
    129 	(function_handler *) v1_srv_ack,
    130 	(function_handler *) v1_attr_rqst,
    131 	(function_handler *) v1_attr_rply,
    132 	(function_handler *) v1_daadvert,
    133 	(function_handler *) v1_srv_type_rqst,
    134 	(function_handler *) v1_srv_type_rply };
    135 
    136 /* TCP continuation handling */
    137 static boolean_t tcp_continuation = B_FALSE;
    138 
    139 #define	MAX_TCPCONT	16
    140 
    141 static struct tcp_cont {
    142 	int dst_port;
    143 	char *msg;
    144 	int totallen;
    145 	int curr_offset;
    146 } *tcp_cont[MAX_TCPCONT];
    147 
    148 static int current_tcp_cont;
    149 
    150 static void reg_tcp_cont(char *, int, int, int);
    151 static int add_tcp_cont(struct tcp_cont *, char *, int);
    152 static struct tcp_cont *find_tcp_cont(int);
    153 static void remove_tcp_cont(int);
    154 
    155 /* Conversions from numbers to strings */
    156 static char *slpv2_func(int, boolean_t);
    157 static char *slpv2_error(unsigned short);
    158 static char *slpv1_func(int, boolean_t);
    159 static char *slpv1_error(unsigned short);
    160 static char *slpv1_charset(unsigned short);
    161 
    162 /*
    163  * The only external entry point to the SLP interpreter. This function
    164  * simply dispatches the packet based on the version.
    165  */
    166 void interpret_slp(int flags, char *slp, int fraglen) {
    167 	extern int dst_port, curr_proto;
    168 	struct tcp_cont *tce = NULL;
    169 
    170 	msglength = fraglen;
    171 	retlength = 0;
    172 	p = slp;
    173 
    174 	/* check if this is a TCP continuation */
    175 	if (flags & F_DTAIL && curr_proto == IPPROTO_TCP) {
    176 	    tce = find_tcp_cont(dst_port);
    177 	    if (tce) {
    178 		if (add_tcp_cont(tce, slp, fraglen)) {
    179 		    slp = tce->msg;
    180 		    fraglen = tce->curr_offset;
    181 		    tcp_continuation = B_TRUE;
    182 		}
    183 	    }
    184 	}
    185 	if (*slp == 2 || tce)
    186 	    interpret_slp_v2(flags, (void *)slp, fraglen);
    187 	else
    188 	    interpret_slp_v1(flags, (void *)slp, fraglen);
    189 
    190 	tcp_continuation = B_FALSE;
    191 }
    192 
    193 /*
    194  * Primitives. These are implemented as much as possible as macros for
    195  * speed.
    196  */
    197 
    198 #define	FIELD_DEFAULT	0
    199 #define	FIELD_PREVRESP	1
    200 #define	FIELD_TYPENA	2
    201 
    202 static long long netval = 0;	/* need signed 64 bit quantity */
    203 
    204 /* gets two bytes from p and leaves the result in netval */
    205 #define	nbtohs() \
    206 	netval = ((int)(p[0] & 0xff)) << 8; \
    207 	netval += ((int)(p[1] & 0xff))
    208 
    209 /* gets four bytes from p and leaves the result in netval */
    210 #define	nbtohl() \
    211 	netval = ((int)(p[0] & 0xff)) << 24; \
    212 	netval += ((int)(p[1] & 0xff)) << 16; \
    213 	netval += ((int)(p[2] & 0xff)) << 8; \
    214 	netval += ((int)(p[3] & 0xff))
    215 
    216 #define	get_byte() \
    217 	if (msglength >= 1) { \
    218 		netval = *p; \
    219 		p++; \
    220 		msglength--; \
    221 	} else \
    222 		netval = -1
    223 
    224 #define	GETBYTE(x) \
    225 	get_byte(); \
    226 	if ((retlength = netval) < 0) \
    227 		return (0); \
    228 	x = netval
    229 
    230 #define	SKIPBYTE \
    231 	get_byte(); \
    232 	if ((retlength = netval) < 0) \
    233 		return (0); \
    234 
    235 /*
    236  * gets two bytes from p, leaves the result in netval, and updates
    237  * msglength and p.
    238  */
    239 #define	get_short() \
    240 	if (msglength >= sizeof (unsigned short)) { \
    241 		nbtohs(); \
    242 		p += sizeof (unsigned short); \
    243 		msglength -= sizeof (unsigned short); \
    244 	} else \
    245 		netval = -1
    246 
    247 #define	GETSHORT(x) \
    248 	get_short(); \
    249 	if ((retlength = netval) < 0) \
    250 		return (0); \
    251 	x = netval
    252 
    253 #define	SKIPSHORT \
    254 	get_short(); \
    255 	if ((retlength = netval) < 0) \
    256 		return (0)
    257 
    258 #define	get_int24(pp) \
    259 	netval = ((int)((pp)[0] & 0xff)) << 16; \
    260 	netval += ((int)((pp)[1] & 0xff)) << 8; \
    261 	netval += ((int)((pp)[2] & 0xff))
    262 
    263 static void slp_prevresp(char *p) {
    264 	char *p2;
    265 
    266 	/* cycle through all entries */
    267 	for (; p != NULL; p = p2) {
    268 	    p2 = strchr(p, ',');
    269 	    if (p2 != NULL)
    270 		*p2++ = '\0';
    271 
    272 	    /* print entry at p */
    273 	    sprintf(get_line(0, 0), "  \"%s\"", p);
    274 	}
    275 }
    276 
    277 static int skip_field(int type) {
    278 	unsigned short stringlen;
    279 
    280 	get_short();
    281 	if (netval < 0) {
    282 	    return (-1);
    283 	}
    284 	stringlen = netval;
    285 
    286 	/* special case for NA field in SrvTypeRqst */
    287 	if (type == FIELD_TYPENA && stringlen == 0xffff) {
    288 	    stringlen = 0;
    289 	}
    290 
    291 	if (stringlen > msglength) {
    292 	    return (-1);
    293 	}
    294 
    295 	msglength -= stringlen;
    296 	p += stringlen;
    297 
    298 	return (stringlen);
    299 }
    300 
    301 #define	SKIPFIELD(type) \
    302 	if ((retlength = skip_field(type)) < 0) \
    303 		return (0)
    304 
    305 #define	GETFIELD \
    306 	get_short(); \
    307 	if ((retlength = netval) < 0) \
    308 		return (0); \
    309 	strncat(msgbuf, p, (retlength > MAXSUMLEN ? MAXSUMLEN : retlength)); \
    310 	p += retlength; \
    311 	msglength -= retlength
    312 
    313 /*
    314  * Determines from the first five bytes of a potential SLP header
    315  * if the following message is really an SLP message. Returns 1 if
    316  * it is a real SLP message, 0 if not.
    317  */
    318 int valid_slp(unsigned char *slphdr, int len) {
    319 	struct slpv1_hdr slp1;
    320 	struct slpv2_hdr slp2;
    321 
    322 	len -= (8 /* udp */ + 20 /* IP */ + 14 /* ether */);
    323 	/* a valid version will be 1 or 2 */
    324 	switch (*slphdr) {
    325 	case 1:
    326 	    memcpy(&slp1, slphdr, 5);
    327 	    /* valid function? */
    328 	    if (slp1.function > V1_MAX_FUNCTION) {
    329 		return (0);
    330 	    }
    331 	    /* valid length heuristic */
    332 	    if (slp1.length > len) {
    333 		return (0);
    334 	    }
    335 	    return (1);
    336 	case 2:
    337 	    memcpy(&slp2, slphdr, 5);
    338 	    /* valid function? */
    339 	    if (slp2.function > V2_MAX_FUNCTION) {
    340 		return (0);
    341 	    }
    342 	    /* valid length heuristic */
    343 	    get_int24(&(slp2.l1));
    344 	    if (netval > len) {
    345 		return (0);
    346 	    }
    347 	    return (1);
    348 	default:
    349 	    return (0);
    350 	}
    351 }
    352 
    353 /*
    354  * Converts a V1 char encoding to UTF8. If this fails, returns 0,
    355  * otherwise, 1. This function is the union of iconv UTF-8
    356  * modules and character sets registered with IANA.
    357  */
    358 static int make_utf8(char *outbuf, size_t outlen,
    359 			const char *inbuf, size_t inlen) {
    360 	iconv_t cd;
    361 	size_t converted;
    362 
    363 	switch (v1_charset) {
    364 	case 4:
    365 	case 1004:
    366 	    cd = iconv_open("UTF-8", "8859-1");
    367 	    break;
    368 	case 5:
    369 	    cd = iconv_open("UTF-8", "8859-2");
    370 	    break;
    371 	case 6:
    372 	    cd = iconv_open("UTF-8", "8859-3");
    373 	    break;
    374 	case 7:
    375 	    cd = iconv_open("UTF-8", "8859-4");
    376 	    break;
    377 	case 8:
    378 	    cd = iconv_open("UTF-8", "8859-5");
    379 	    break;
    380 	case 9:
    381 	    cd = iconv_open("UTF-8", "8859-6");
    382 	    break;
    383 	case 10:
    384 	    cd = iconv_open("UTF-8", "8859-7");
    385 	    break;
    386 	case 11:
    387 	    cd = iconv_open("UTF-8", "8859-8");
    388 	    break;
    389 	case 12:
    390 	    cd = iconv_open("UTF-8", "8859-9");
    391 	    break;
    392 	case 13:
    393 	    cd = iconv_open("UTF-8", "8859-10");
    394 	    break;
    395 	case 37:
    396 	    cd = iconv_open("UTF-8", "ko_KR-iso2022-7");
    397 	    break;
    398 	case 104:
    399 	    cd = iconv_open("UTF-8", "iso2022");
    400 	    break;
    401 	case 1000:
    402 	    cd = iconv_open("UTF-8", "UCS-2");
    403 	    break;
    404 	case 1001:
    405 	    cd = iconv_open("UTF-8", "UCS-4");
    406 	    break;
    407 	default:
    408 		/*
    409 		 * charset not set, or reserved, or not supported, so
    410 		 * just copy it and hope for the best.
    411 		 */
    412 	    converted = outlen < inlen ? outlen : inlen;
    413 	    memcpy(outbuf, inbuf, converted);
    414 	    outbuf[converted] = 0;
    415 	    return (1);
    416 	}
    417 
    418 	if (cd == (iconv_t)-1) {
    419 	    return (0);
    420 	}
    421 
    422 	if ((converted = iconv(cd, &inbuf, &inlen, &outbuf, &outlen))
    423 	    == (size_t)-1) {
    424 	    return (0);
    425 	}
    426 
    427 	outbuf[converted] = 0;
    428 	iconv_close(cd);
    429 
    430 	return (1);
    431 }
    432 
    433 static int slp_field(char *tag, int type) {
    434 	int length;
    435 
    436 	get_short();
    437 	if (netval < 0) {
    438 	    return (-1);
    439 	}
    440 	length = netval;
    441 
    442 	/* special case for NA field in SrvTypeRqst */
    443 	if (type == FIELD_TYPENA && length == 0xffff) {
    444 	    sprintf(get_line(0, 0), "%s: length = -1: Use all NAs", tag);
    445 	    return (0);
    446 	}
    447 
    448 	sprintf(get_line(0, 0), "%s: length = %d", tag, length);
    449 	if (length > msglength) {
    450 	    /* framing error: message is not long enough to contain data */
    451 	    sprintf(get_line(0, 0),
    452 		    "  [Framing error: remaining pkt length = %u]",
    453 		    msglength);
    454 	    return (-1);
    455 	}
    456 
    457 	if (length > 0) {
    458 	    char *buf = malloc(length + 1);
    459 	    if (buf != NULL) {
    460 		if (v1_charset) {
    461 		    if (!make_utf8(buf, length, p, length)) {
    462 			strcpy(buf, "[Invalid Character Encoding]");
    463 		    }
    464 		} else {
    465 		    memcpy(buf, p, length);
    466 		    buf[length] = '\0';		/* ensure null-terminated */
    467 		}
    468 
    469 		switch (type) {
    470 		    case FIELD_PREVRESP:
    471 			slp_prevresp(buf);
    472 			break;
    473 
    474 		    default:
    475 			sprintf(get_line(0, 0), "  \"%s\"", buf);
    476 			break;
    477 		}
    478 		free(buf);
    479 	    }
    480 
    481 	    p += length;
    482 	    msglength -= length;
    483 	}
    484 
    485 	/* return ok */
    486 	return (0);
    487 }
    488 
    489 static int slpv2_url(int cnt) {
    490 	time_t exp;
    491 	int lifetime, length, n;
    492 
    493 	/* reserved */
    494 	get_byte();
    495 	if (netval < 0)
    496 	    return (-1);
    497 
    498 	/* lifetime */
    499 	get_short();
    500 	if ((lifetime = netval) < 0)
    501 	    return (-1);
    502 
    503 	/* length */
    504 	get_short();
    505 	if ((length = netval) < 0)
    506 	    return (-1);
    507 
    508 	/* time */
    509 	exp = time(0) + lifetime;
    510 	if (cnt == -1)
    511 	    sprintf(get_line(0, 0),
    512 		    "URL: length = %u, lifetime = %d (%24.24s)",
    513 		    length, lifetime, ctime(&exp));
    514 	else
    515 	    /* number the URLs to make it easier to parse them */
    516 	    sprintf(get_line(0, 0),
    517 		    "URL %d: length = %u, lifetime = %d (%24.24s)",
    518 		    cnt, length, lifetime, ctime(&exp));
    519 
    520 	if (length > msglength) {
    521 	    if (!tcp_continuation)
    522 		/* framing error: message is not long enough to contain data */
    523 		sprintf(get_line(0, 0),
    524 			"  [Framing error: remaining pkt length = %u]",
    525 			msglength);
    526 	    return (-1);
    527 	}
    528 
    529 	if (length > 0) {
    530 	    char *buf = malloc(length + 1);
    531 	    if (buf != NULL) {
    532 		memcpy(buf, p, length);
    533 		buf[length] = '\0';		/* ensure null-terminated */
    534 		sprintf(get_line(0, 0), "  \"%s\"", buf);
    535 		free(buf);
    536 	    }
    537 	}
    538 	msglength -= length;
    539 	p += length;
    540 
    541 	get_byte();
    542 	if ((n = netval) < 0)
    543 	    return (-1);
    544 
    545 	if (n > 0) {
    546 	    int i;
    547 	    sprintf(get_line(0, 0), "%d Authentication Blocks", n);
    548 	    for (i = 0; i < n; i++)
    549 		if ((length = slpv2_authblock(i)) < 0)
    550 		    return (-1);
    551 	}
    552 	return (0);
    553 }
    554 
    555 #define	DOFIELD(tag, type) \
    556 	if (slp_field(tag, type) < 0) \
    557 		return (0)
    558 
    559 #define	V2_DOURL(x) \
    560 	if (slpv2_url(x) < 0) \
    561 		return (0)
    562 
    563 #define	V2_DOERRCODE \
    564 	if (msglength < sizeof (unsigned short)) \
    565 		return (0); \
    566 	nbtohs(); \
    567 	errcode = netval; \
    568 	sprintf(get_line(0, 0), "Error code = %d, %s", \
    569 				errcode, slpv2_error(errcode)); \
    570 	p += sizeof (unsigned short); \
    571 	msglength -= sizeof (unsigned short); \
    572 	if (errcode != OK) \
    573 		msglength = 0;	/* skip rest of message */ \
    574 	if (errcode != OK) \
    575 		return (0)
    576 
    577 #define	V2_DOAUTH(cnt) \
    578 	if (slpv2_authblock(cnt) < 0) \
    579 		return (0)
    580 
    581 #define	V2_DOTIMESTAMP \
    582 	if (msglength < 4) \
    583 		return (0); \
    584 	nbtohl(); \
    585 	timestamp = netval; \
    586 	sprintf(get_line(0, 0), "Timestamp = %u, %s", \
    587 		timestamp, (timestamp ? convert_ts(timestamp) : "0")); \
    588 	p += 4; \
    589 	msglength -= 4
    590 
    591 /* some V1 macros */
    592 #define	SKIPAUTH(auth) \
    593 	if (auth && ((retlength = skip_v1authblock()) < 0)) \
    594 		return (0)
    595 
    596 #define	DOERRCODE \
    597 	if (msglength < sizeof (unsigned short)) \
    598 		return (0); \
    599 	nbtohs(); \
    600 	errcode = netval; \
    601 	sprintf(get_line(0, 0), "Error code = %d, %s", errcode, \
    602 				slpv1_error(errcode)); \
    603 	p += sizeof (unsigned short); \
    604 	msglength -= sizeof (unsigned short); \
    605 	if (errcode != OK) \
    606 		return (0)
    607 
    608 #define	DOURL \
    609 	if (slpv1_url(url_auth) < 0) \
    610 		return (0)
    611 
    612 #define	DOAUTH(auth) \
    613 	if (auth && slpv1_authblock() < 0) \
    614 		return (0)
    615 
    616 /*
    617  * TCP Continuation handling
    618  * We keep track of continuations in a fixed size cache, so as to prevent
    619  * memory leaks if some continuations are never finished. The continuations
    620  * are indexed by their destination ports.
    621  */
    622 static void reg_tcp_cont(char *msg, int totallen,
    623 			    int fraglen, int dst_port) {
    624 	struct tcp_cont *tce = malloc(sizeof (*tce));
    625 
    626 	/* always overwrite the entry at current_tcp_cont */
    627 	if (tcp_cont[current_tcp_cont]) {
    628 	    free(tcp_cont[current_tcp_cont]->msg);
    629 	    free(tcp_cont[current_tcp_cont]);
    630 	}
    631 
    632 	tce->dst_port = dst_port;
    633 	tce->msg = malloc(totallen);
    634 	memcpy(tce->msg, msg, fraglen);
    635 	tce->totallen = totallen;
    636 	tce->curr_offset = fraglen;
    637 
    638 	tcp_cont[current_tcp_cont++] = tce;
    639 	if (current_tcp_cont == MAX_TCPCONT)
    640 	    current_tcp_cont = 0;
    641 }
    642 
    643 /* returns 0 if there is a mismatch error, 1 on success */
    644 static int add_tcp_cont(struct tcp_cont *tce, char *msg, int fraglen) {
    645 	if ((fraglen + tce->curr_offset) > tce->totallen)
    646 	    return (0);
    647 
    648 	memcpy(tce->msg + tce->curr_offset, msg, fraglen);
    649 	tce->curr_offset += fraglen;
    650 	return (1);
    651 }
    652 
    653 static struct tcp_cont *find_tcp_cont(int dst_port) {
    654 	int i;
    655 	for (i = current_tcp_cont; i >= 0; i--)
    656 	    if (tcp_cont[i] && tcp_cont[i]->dst_port == dst_port)
    657 		return (tcp_cont[i]);
    658 
    659 	for (i = MAX_TCPCONT -1; i > current_tcp_cont; i--)
    660 	    if (tcp_cont[i] && tcp_cont[i]->dst_port == dst_port)
    661 		return (tcp_cont[i]);
    662 
    663 	return (NULL);
    664 }
    665 
    666 static void remove_tcp_cont(int dst_port) {
    667 	int i;
    668 	for (i = current_tcp_cont; i >= 0; i--)
    669 	    if (tcp_cont[i] && tcp_cont[i]->dst_port == dst_port) {
    670 		free(tcp_cont[i]->msg);
    671 		free(tcp_cont[i]);
    672 		tcp_cont[i] = NULL;
    673 		return;
    674 	    }
    675 
    676 	for (i = MAX_TCPCONT -1; i > current_tcp_cont; i--)
    677 	    if (tcp_cont[i] && tcp_cont[i]->dst_port == dst_port) {
    678 		free(tcp_cont[i]->msg);
    679 		free(tcp_cont[i]);
    680 		tcp_cont[i] = NULL;
    681 		return;
    682 	    }
    683 }
    684 
    685 /*
    686  * V2 interpreter
    687  */
    688 
    689 static int interpret_slp_v2(int flags, struct slpv2_hdr *slp, int fraglen) {
    690 	extern int src_port, dst_port, curr_proto;
    691 	char msgbuf_real[256];
    692 	int totallen = 0;
    693 
    694 	msgbuf = msgbuf_real;
    695 
    696 	/*
    697 	 * Somewhat of a hack to decode traffic from a server that does
    698 	 * not send udp replies from its SLP src port.
    699 	 */
    700 
    701 	if (curr_proto == IPPROTO_UDP &&
    702 	    dst_port == 427 &&
    703 	    src_port != 427) {
    704 	    add_transient(src_port, (int (*)())interpret_slp);
    705 	}
    706 
    707 	/* parse the header */
    708 	if (v2_header(flags, slp, &totallen, fraglen)) {
    709 
    710 	    if (slp->function <= V2_MAX_FUNCTION && slp->function > 0) {
    711 
    712 		/* Parse the message body */
    713 		if ((v2_functions[slp->function])(flags)) {
    714 
    715 		    /* finish any remaining tasks */
    716 		    v2_finish(slp, flags);
    717 
    718 		}
    719 
    720 	    }
    721 
    722 	}
    723 
    724 	/* summary error check */
    725 	if (flags & F_SUM) {
    726 	    if (retlength < 0) {
    727 		if (curr_proto == IPPROTO_TCP)
    728 		    sprintf(get_sum_line(),
    729 			    "%s [partial TCP message]", msgbuf);
    730 		else if (overflow)
    731 		    sprintf(get_sum_line(), "%s [OVERFLOW]", msgbuf);
    732 		else
    733 		    sprintf(get_sum_line(), "%s [CORRUPTED MESSAGE]", msgbuf);
    734 	    }
    735 #ifdef VERIFYSLP
    736 	    else if (msglength > 0)
    737 		sprintf(get_sum_line(), "%s +%d", msgbuf, msglength);
    738 #endif
    739 	    else
    740 		sprintf(get_sum_line(), "%s", msgbuf);
    741 	} else if (flags & F_DTAIL) {
    742 	    /* detailed error check */
    743 	    if (msglength > 0) {
    744 		if (tcp_continuation) {
    745 		    sprintf(get_line(0, 0),
    746 			    "[TCP Continuation, %d bytes remaining]",
    747 			    totallen - fraglen);
    748 		} else
    749 		    sprintf(get_line(0, 0),
    750 			"[%d extra bytes at end of SLP message]", msglength);
    751 	    }
    752 
    753 	    show_trailer();
    754 
    755 	    if (tcp_continuation && msglength == 0)
    756 		remove_tcp_cont(dst_port);
    757 	}
    758 
    759 	return (0);
    760 }
    761 
    762 static int v2_header(int flags,
    763 			struct slpv2_hdr *slp,
    764 			int *totallen,
    765 			int fraglen) {
    766 	extern int curr_proto, dst_port;
    767 	char *prototag = (curr_proto == IPPROTO_TCP ? "/tcp" : "");
    768 
    769 	if ((slp->flags & V2_OVERFLOW) == V2_OVERFLOW)
    770 	    overflow = B_TRUE;
    771 
    772 	/* summary mode header parsing */
    773 	if (flags & F_SUM) {
    774 
    775 	    /* make sure we have at least a header */
    776 	    if (msglength < sizeof (*slp)) {
    777 		sprintf(get_sum_line(), "SLP V2 [Incomplete Header]");
    778 		return (0);
    779 	    }
    780 
    781 	    sprintf(msgbuf, "SLP V2 %s [%d%s] ",
    782 		    slpv2_func(slp->function, B_TRUE),
    783 		    ntohs(slp->xid), prototag);
    784 
    785 	    /* skip to end of header */
    786 	    msgend = msgbuf + strlen(msgbuf);
    787 	    msglength -= sizeof (*slp);
    788 	    p += sizeof (*slp);
    789 
    790 	    /* skip language tag */
    791 	    SKIPFIELD(FIELD_DEFAULT);
    792 	} else if (flags & F_DTAIL) {
    793 	    char *lang;
    794 	    int len;
    795 
    796 	    /* detailed mode header parsing */
    797 	    show_header("SLP:  ", "Service Location Protocol (v2)", fraglen);
    798 	    show_space();
    799 
    800 	    if (msglength < sizeof (*slp)) {
    801 		sprintf(get_line(0, 0), "==> Incomplete SLP header");
    802 		return (0);
    803 	    }
    804 
    805 	    sprintf(get_line(0, 0), "Version = %d", slp->vers);
    806 	    sprintf(get_line(0, 0), "Function = %d, %s",
    807 		    slp->function, slpv2_func(slp->function, B_FALSE));
    808 	    get_int24(&(slp->l1));
    809 	    *totallen = netval;
    810 	    sprintf(get_line(0, 0), "Message length = %u", *totallen);
    811 	    /* check for TCP continuation */
    812 	    if (curr_proto == IPPROTO_TCP &&
    813 		*totallen > msglength &&
    814 		!tcp_continuation) {
    815 		tcp_continuation = B_TRUE;
    816 		reg_tcp_cont((char *)slp, *totallen, msglength, dst_port);
    817 	    }
    818 
    819 	    if (!tcp_continuation && *totallen != msglength) {
    820 		sprintf(get_line(0, 0),
    821 			"  (Stated and on-the-wire lengths differ)");
    822 	    }
    823 	    /* flags */
    824 	    sprintf(get_line(0, 0), "Flags = 0x%02x", slp->flags);
    825 	    sprintf(get_line(0, 0), "      %s",
    826 		    getflag(slp->flags, V2_OVERFLOW,
    827 			    "overflow", "no overflow"));
    828 	    sprintf(get_line(0, 0), "      %s",
    829 		    getflag(slp->flags, V2_FRESH,
    830 			    "fresh registration", "no fresh registration"));
    831 	    sprintf(get_line(0, 0), "      %s",
    832 		    getflag(slp->flags, V2_MCAST,
    833 			    "request multicast / broadcast", "unicast"));
    834 	    /* check reserved flags that must be zero */
    835 	    if ((slp->flags & 7) != 0) {
    836 		sprintf(get_line(0, 0),
    837 			"      .... .xxx = %d (reserved flags nonzero)",
    838 			slp->flags & 7);
    839 	    }
    840 	    /* end of flags */
    841 
    842 	    /* language tag */
    843 	    p = (char *)slp + sizeof (*slp);
    844 	    msglength -= sizeof (*slp);
    845 	    GETSHORT(len);
    846 	    if (len > msglength) {
    847 		sprintf(get_line(0, 0),
    848 			"Language Tag Length = %u [CORRUPT MESSAGE]",
    849 			len);
    850 		return (0);
    851 	    }
    852 
    853 	    lang = get_line(0, 0);
    854 	    strcpy(lang, "Language Tag = ");
    855 	    strncat(lang,  p, len);
    856 	    sprintf(get_line(0, 0), "XID = %u", ntohs(slp->xid));
    857 
    858 	    /* set msglength to remaining length of SLP message */
    859 	    p += len;
    860 	    msglength -= len;
    861 	}
    862 
    863 	return (1);
    864 }
    865 
    866 static int v2_finish(struct slpv2_hdr *slp, int flags) {
    867 	unsigned int firstop;
    868 
    869 	if (!(flags & F_DTAIL))
    870 	    return (1);
    871 
    872 	/* check for options */
    873 	get_int24(&(slp->o1));
    874 	firstop = netval;
    875 
    876 	if (firstop) {
    877 	    unsigned short op_id;
    878 	    unsigned short nextop;
    879 	    char *op_class;
    880 
    881 	    for (;;) {
    882 		unsigned short real_oplen;
    883 
    884 		if (msglength < 4) {
    885 		    sprintf(get_line(0, 0),
    886 			    "Option expected but not present");
    887 		    return (0);
    888 		}
    889 
    890 		nbtohs();
    891 		op_id = netval;
    892 		p += sizeof (unsigned short);
    893 		msglength -= sizeof (unsigned short);
    894 		nbtohs();
    895 		nextop = netval;
    896 		p += sizeof (unsigned short);
    897 		msglength -= sizeof (unsigned short);
    898 
    899 		real_oplen = nextop ? nextop : msglength;
    900 
    901 		/* known options */
    902 		switch (op_id) {
    903 		case 1:
    904 		    sprintf(get_line(0, 0),
    905 			    "Option: Required Attribute Missing");
    906 		    DOFIELD("Template IDVer", FIELD_DEFAULT);
    907 		    DOFIELD("Required Attrs", FIELD_DEFAULT);
    908 		    break;
    909 		default:
    910 		    sprintf(get_line(0, 0), "Option: Unknown");
    911 		    p += (real_oplen - 4);
    912 		    msglength -= (real_oplen - 4);
    913 		    break;
    914 		}
    915 
    916 		if (op_id < 0x3fff)
    917 		    op_class = "Standardized, optional";
    918 		else if (op_id < 0x7fff)
    919 		    op_class = "Standardized, mandatory";
    920 		else if (op_id < 0x8fff)
    921 		    op_class = "Not standardized, private";
    922 		else if (op_id < 0xffff)
    923 		    op_class = "Reserved";
    924 		sprintf(get_line(0, 0), "Option ID = 0x%04x, %s",
    925 			op_id, op_class);
    926 		if (nextop &&
    927 		    ((nextop - 4) > msglength) &&
    928 		    !tcp_continuation) {
    929 		    sprintf(get_line(0, 0),
    930 			    "[Framing error: remaining pkt length = %u]",
    931 			    msglength);
    932 		    return (0);
    933 		}
    934 
    935 		sprintf(get_line(0, 0), "Option Length = %u", real_oplen);
    936 
    937 		if (!nextop)
    938 		    break;
    939 	    }
    940 	}
    941 
    942 	return (1);
    943 }
    944 
    945 #ifdef VERIFYSLP
    946 static int skip_v2authblock() {
    947 	unsigned short length, slen;
    948 
    949 	/* auth header */
    950 	if (msglength < 10)
    951 	    return (-1);
    952 
    953 	/* block descriptor: 2 bytes */
    954 	p += sizeof (unsigned short);
    955 	/* length */
    956 	nbtohs();
    957 	length = netval;
    958 	p += sizeof (unsigned short);
    959 	/* timestamp */
    960 	p += 4;
    961 	/* SPI String length */
    962 	nbtohs();
    963 	slen = netval;
    964 	p += sizeof (unsigned short);
    965 
    966 	msglength -= 10;
    967 	if (slen > msglength || length > (msglength + 10))
    968 	    return (-1);
    969 
    970 	p += slen;
    971 	msglength -= slen;
    972 
    973 	/* structured auth block */
    974 	p += (length - 10 - slen);
    975 	msglength -= (length - 10 - slen);
    976 	return (0);
    977 }
    978 #endif
    979 
    980 static char *display_bsd(unsigned short bsd) {
    981 	switch (bsd) {
    982 	case 1: return ("MD5 with RSA");
    983 	case 2: return ("DSA with SHA-1");
    984 	case 3: return ("Keyed HMAC with MD5");
    985 	default: return ("Unknown BSD");
    986 	}
    987 }
    988 
    989 static char *slpv2_func(int t, boolean_t s) {
    990 	static char buf[128];
    991 
    992 	switch (t) {
    993 	case V2_SRVRQST:	return s? "SrvRqst"  : "Service Request";
    994 	case V2_SRVRPLY:	return s? "SrvRply"  : "Service Reply";
    995 	case V2_SRVREG:		return s? "SrvReg"   : "Service Registration";
    996 	case V2_SRVDEREG:
    997 	    return (s ? "SrvDereg" : "Service Deregistration");
    998 	case V2_SRVACK:		return s? "SrvAck"   : "Service Acknowledge";
    999 	case V2_ATTRRQST:	return s? "AttrRqst" : "Attribute Request";
   1000 	case V2_ATTRRPLY:	return s? "AttrRply" : "Attribute Reply";
   1001 	case V2_DAADVERT:	return s? "DAAdvert" : "DA advertisement";
   1002 	case V2_SRVTYPERQST:
   1003 	    return (s ? "SrvTypeRqst" : "Service Type Request");
   1004 	case V2_SRVTYPERPLY:
   1005 	    return (s ? "SrvTypeRply" : "Service Type Reply");
   1006 	case V2_SAADVERT:	return s? "SAAdvert" : "SA advertisement";
   1007 	}
   1008 	sprintf(buf, "(func %d)", t);
   1009 	return (s ? buf : "unknown function");
   1010 }
   1011 
   1012 static char *slpv2_error(unsigned short code) {
   1013 	static char buf[128];
   1014 
   1015 	switch (code) {
   1016 	case OK:			return "ok";
   1017 	case LANG_NOT_SUPPORTED:	return "language not supported";
   1018 	case PROTOCOL_PARSE_ERR:	return "protocol parse error";
   1019 	case INVALID_REGISTRATION:	return "invalid registration";
   1020 	case SCOPE_NOT_SUPPORTED:	return "scope not supported";
   1021 	case AUTHENTICATION_UNKNOWN:	return "authentication unknown";
   1022 	case V2_AUTHENTICATION_ABSENT:	return "authentication absent";
   1023 	case V2_AUTHENTICATION_FAILED:	return "authentication failed";
   1024 	case V2_VER_NOT_SUPPORTED:	return "version not supported";
   1025 	case V2_INTERNAL_ERROR:		return "internal error";
   1026 	case V2_DA_BUSY_NOW:		return "DA busy";
   1027 	case V2_OPTION_NOT_UNDERSTOOD:	return "option not understood";
   1028 	case V2_INVALID_UPDATE:		return "invalid update";
   1029 	case V2_RQST_NOT_SUPPORTED:	return "request not supported";
   1030 	case INVALID_LIFETIME:		return "invalid lifetime";
   1031 	}
   1032 	sprintf(buf, "error %d", code);
   1033 	return (buf);
   1034 }
   1035 
   1036 static char *convert_ts(unsigned int timestamp) {
   1037 	/* timestamp is in UNIX time */
   1038 	static char buff[128];
   1039 
   1040 	strcpy(buff, ctime((time_t *)&timestamp));
   1041 	buff[strlen(buff) - 1] = '\0';
   1042 	return (buff);
   1043 }
   1044 
   1045 static int slpv2_authblock(int cnt) {
   1046 	unsigned short bsd, length, slen;
   1047 	char *pp, *scopes;
   1048 	unsigned int timestamp;
   1049 
   1050 	if (msglength < 10) {
   1051 	    sprintf(get_line(0, 0),
   1052 		"  [no room for auth block header: remaining msg length = %u]",
   1053 		    msglength);
   1054 	    return (-1);
   1055 	}
   1056 
   1057 	/* bsd */
   1058 	nbtohs();
   1059 	bsd = netval;
   1060 	p += sizeof (unsigned short);
   1061 
   1062 	/* length */
   1063 	nbtohs();
   1064 	length = netval;
   1065 	p += sizeof (unsigned short);
   1066 
   1067 	/* timestamp */
   1068 	nbtohl();
   1069 	timestamp = netval;
   1070 	p += 4;
   1071 
   1072 	/* SPI String length */
   1073 	nbtohs();
   1074 	slen = netval;
   1075 	p += sizeof (unsigned short);
   1076 
   1077 	msglength -= 10;
   1078 	if (slen > msglength) {
   1079 	    sprintf(get_line(0, 0),
   1080 		"  [no room for auth block scopes: remaining msg length = %u]",
   1081 		    msglength);
   1082 	    return (-1);
   1083 	}
   1084 
   1085 	if (length > (msglength + 10)) {
   1086 	    if (!tcp_continuation)
   1087 		/* framing error: message is not long enough to contain data */
   1088 		sprintf(get_line(0, 0),
   1089 			"  [Framing error: remaining pkt length = %u]",
   1090 			msglength);
   1091 	    return (-1);
   1092 	}
   1093 
   1094 	scopes = p;
   1095 	p += slen;
   1096 	msglength -= slen;
   1097 
   1098 	sprintf(get_line(0, 0),
   1099 	    "Auth block %d: timestamp = %s", cnt,
   1100 	    (timestamp) ? convert_ts(timestamp) : "0");
   1101 
   1102 	pp = get_line(0, 0);
   1103 	strcpy(pp, "              SPI = ");
   1104 	strncat(pp, scopes, slen);
   1105 
   1106 	sprintf(get_line(0, 0),
   1107 	    "              block desc = 0x%04x: %s", bsd, display_bsd(bsd));
   1108 
   1109 	sprintf(get_line(0, 0), "              length = %u", length);
   1110 
   1111 	p += (length - 10 - slen);
   1112 	msglength -= (length - 10 - slen);
   1113 	return (0);
   1114 }
   1115 
   1116 static int v2_srv_rqst(int flags) {
   1117 	if (flags & F_SUM) {
   1118 		SKIPFIELD(FIELD_DEFAULT);	/* PR list */
   1119 		GETFIELD;			/* service type */
   1120 		SKIPFIELD(FIELD_DEFAULT);	/* scopes */
   1121 		strcat(msgend, " [");
   1122 		GETFIELD;			/* predicate */
   1123 		strcat(msgend, "]");
   1124 		SKIPFIELD(FIELD_DEFAULT);	/* SPI */
   1125 	} else if (flags & F_DTAIL) {
   1126 		DOFIELD("Previous responders", FIELD_DEFAULT);
   1127 		DOFIELD("Service type",  FIELD_DEFAULT);
   1128 		DOFIELD("Scopes",  FIELD_DEFAULT);
   1129 		DOFIELD("Predicate string",  FIELD_DEFAULT);
   1130 		DOFIELD("Requested SPI", FIELD_DEFAULT);
   1131 	}
   1132 
   1133 	return (1);
   1134 }
   1135 
   1136 static int v2_srv_rply(int flags) {
   1137 	unsigned short itemcnt, errcode;
   1138 	int n;
   1139 
   1140 	if (flags & F_SUM) {
   1141 	    int i, auth_cnt;
   1142 
   1143 	    GETSHORT(errcode);
   1144 	    if (errcode != OK) {
   1145 		strcat(msgbuf, slpv2_error(errcode));
   1146 		msglength = 0;	/* skip rest of message */
   1147 		return (0);
   1148 	    } else {
   1149 		GETSHORT(itemcnt);
   1150 		sprintf(msgend, "%d URL entries", itemcnt);
   1151 #ifdef VERIFYSLP
   1152 		for (n = 0; n < itemcnt; n++) {
   1153 		    SKIPBYTE;			/* reserved */
   1154 		    SKIPSHORT;			/* lifetime */
   1155 		    SKIPFIELD(FIELD_DEFAULT);	/* URL */
   1156 		    GETBYTE(auth_cnt);
   1157 		    for (i = 0; i < auth_cnt; auth_cnt++)
   1158 			if (skip_v2authblock() < 0)
   1159 			    return (0);
   1160 		}
   1161 #endif
   1162 	    }
   1163 	} else if (flags & F_DTAIL) {
   1164 	    V2_DOERRCODE;
   1165 	    GETSHORT(itemcnt);
   1166 	    sprintf(get_line(0, 0), "URL entry count = %d", itemcnt);
   1167 	    for (n = 0; n < itemcnt; n++) {
   1168 		V2_DOURL(n);
   1169 	    }
   1170 	}
   1171 
   1172 	return (1);
   1173 }
   1174 
   1175 static int v2_srv_reg(int flags) {
   1176 	int i, auth_cnt;
   1177 
   1178 	if (flags & F_SUM) {
   1179 	    SKIPBYTE;			/* reserved */
   1180 	    SKIPSHORT;			/* lifetime */
   1181 	    GETFIELD;			/* URL */
   1182 #ifdef VERIFYSLP
   1183 	    GETBYTE(auth_cnt);
   1184 	    for (i = 0; i < auth_cnt; i++)
   1185 		if (skip_v2authblock() < 0)
   1186 		    return (0);
   1187 	    SKIPFIELD(FIELD_DEFAULT);	/* type */
   1188 	    SKIPFIELD(FIELD_DEFAULT);	/* scopes */
   1189 	    SKIPFIELD(FIELD_DEFAULT);	/* attrs */
   1190 	    GETBYTE(auth_cnt);
   1191 	    for (i = 0; i < auth_cnt; i++)
   1192 		if (skip_v2authblock() < 0)
   1193 		    return (0);
   1194 #endif
   1195 	} if (flags & F_DTAIL) {
   1196 	    V2_DOURL(-1);
   1197 	    DOFIELD("Service type", FIELD_DEFAULT);
   1198 	    DOFIELD("Scopes", FIELD_DEFAULT);
   1199 	    DOFIELD("Attribute list", FIELD_DEFAULT);
   1200 	    /* auth */
   1201 	    GETBYTE(auth_cnt);
   1202 	    for (i = 0; i < auth_cnt; i++)
   1203 		V2_DOAUTH(i);
   1204 	}
   1205 
   1206 	return (1);
   1207 }
   1208 
   1209 static int v2_srv_dereg(int flags) {
   1210 	if (flags & F_SUM) {
   1211 	    int i, auth_cnt;
   1212 
   1213 	    SKIPFIELD(FIELD_DEFAULT);	/* scopes */
   1214 	    SKIPBYTE;			/* reserved */
   1215 	    SKIPSHORT;			/* lifetime */
   1216 	    GETFIELD;			/* URL */
   1217 
   1218 #ifdef VERIFYSLP
   1219 	    GETBYTE(auth_cnt);
   1220 	    for (i = 0; i < auth_cnt; i++)
   1221 		if (skip_v2authblock() < 0)
   1222 		    return (0);
   1223 	    SKIPFIELD(FIELD_DEFAULT);	/* attrs */
   1224 #endif
   1225 	} else if (flags & F_DTAIL) {
   1226 	    DOFIELD("Scopes", FIELD_DEFAULT);
   1227 	    V2_DOURL(-1);
   1228 	    DOFIELD("Tag list",  FIELD_DEFAULT);
   1229 	}
   1230 
   1231 	return (1);
   1232 }
   1233 
   1234 static int v2_srv_ack(int flags) {
   1235 	unsigned short errcode;
   1236 	if (flags & F_SUM) {
   1237 	    GETSHORT(errcode);
   1238 	    strcat(msgbuf, slpv2_error(errcode));
   1239 	} else if (flags & F_DTAIL) {
   1240 	    V2_DOERRCODE;
   1241 	}
   1242 
   1243 	return (1);
   1244 }
   1245 
   1246 static int v2_attr_rqst(int flags) {
   1247 	if (flags  & F_SUM) {
   1248 	    SKIPFIELD(FIELD_DEFAULT);	/* PR list */
   1249 	    GETFIELD;			/* URL */
   1250 	    SKIPFIELD(FIELD_DEFAULT);	/* scopes */
   1251 	    strcat(msgend, " [");
   1252 	    GETFIELD;			/* attrs */
   1253 	    strcat(msgend, "]");
   1254 
   1255 #ifdef VERIFYSLP
   1256 	    SKIPFIELD(FIELD_DEFAULT);	/* SPI */
   1257 #endif
   1258 	} else if (flags & F_DTAIL) {
   1259 	    DOFIELD("Previous responders", FIELD_DEFAULT);
   1260 	    DOFIELD("URL",  FIELD_DEFAULT);
   1261 	    DOFIELD("Scopes",  FIELD_DEFAULT);
   1262 	    DOFIELD("Tag list",  FIELD_DEFAULT);
   1263 	    DOFIELD("Requested SPI", FIELD_DEFAULT);
   1264 	}
   1265 
   1266 	return (1);
   1267 }
   1268 
   1269 static int v2_attr_rply(int flags) {
   1270 	int auth_cnt, i;
   1271 	unsigned short errcode;
   1272 
   1273 	if (flags & F_SUM) {
   1274 	    GETSHORT(errcode);
   1275 	    if (errcode != OK) {
   1276 		strcat(msgbuf, slpv2_error(errcode));
   1277 		msglength = 0;	/* skip rest of message */
   1278 		return (0);
   1279 	    } else {
   1280 		GETFIELD;			/* attr list */
   1281 
   1282 #ifdef VERIFYSLP
   1283 		GETBYTE(auth_cnt);
   1284 		for (i = 0; i < auth_cnt; i++)
   1285 		    if (skip_v2authblock() < 0)
   1286 			return (0);
   1287 #endif
   1288 	    }
   1289 	} else if (flags & F_DTAIL) {
   1290 	    V2_DOERRCODE;
   1291 	    DOFIELD("Attribute list", FIELD_DEFAULT);
   1292 	    /* auth */
   1293 	    GETBYTE(auth_cnt);
   1294 	    for (i = 0; i < auth_cnt; i++)
   1295 		V2_DOAUTH(i);
   1296 	}
   1297 
   1298 	return (1);
   1299 }
   1300 
   1301 static int v2_daadvert(int flags) {
   1302 	int auth_cnt, i;
   1303 	unsigned short errcode;
   1304 	unsigned int timestamp;
   1305 
   1306 	if (flags & F_SUM) {
   1307 	    SKIPSHORT;			/* error code */
   1308 	    SKIPSHORT; SKIPSHORT;	/* timestamp */
   1309 	    GETFIELD;			/* URL */
   1310 
   1311 #ifdef VERIFYSLP
   1312 	    SKIPFIELD(FIELD_DEFAULT);	/* scopes */
   1313 	    SKIPFIELD(FIELD_DEFAULT);	/* attrs */
   1314 	    SKIPFIELD(FIELD_DEFAULT);	/* SPIs */
   1315 
   1316 	    GETBYTE(auth_cnt);
   1317 	    for (i = 0; i < auth_cnt; i++)
   1318 		if (skip_v2authblock() < 0)
   1319 		    return (0);
   1320 #endif
   1321 	} else if (flags & F_DTAIL) {
   1322 	    V2_DOERRCODE;
   1323 	    V2_DOTIMESTAMP;
   1324 	    DOFIELD("URL", FIELD_DEFAULT);
   1325 	    DOFIELD("Scope list", FIELD_DEFAULT);
   1326 	    DOFIELD("Attribute list", FIELD_DEFAULT);
   1327 	    DOFIELD("Configured SPIs", FIELD_DEFAULT);
   1328 	    /* auth */
   1329 	    GETBYTE(auth_cnt);
   1330 	    for (i = 0; i < auth_cnt; i++)
   1331 		V2_DOAUTH(i);
   1332 	}
   1333 
   1334 	return (1);
   1335 }
   1336 
   1337 static int v2_srv_type_rqst(int flags) {
   1338 	if (flags & F_SUM) {
   1339 	    SKIPFIELD(FIELD_DEFAULT);	/* prev responders */
   1340 	    SKIPFIELD(FIELD_TYPENA);	/* naming authority */
   1341 	    GETFIELD;			/* scope */
   1342 	} else if (flags & F_DTAIL) {
   1343 	    DOFIELD("Previous responders", FIELD_DEFAULT);
   1344 	    DOFIELD("Naming authority", FIELD_TYPENA);
   1345 	    DOFIELD("Scopes",  FIELD_DEFAULT);
   1346 	}
   1347 
   1348 	return (1);
   1349 }
   1350 
   1351 static int v2_srv_type_rply(int flags) {
   1352 	unsigned short errcode;
   1353 
   1354 	if (flags & F_SUM) {
   1355 	    GETSHORT(errcode);
   1356 	    if (errcode != OK)
   1357 		strcat(msgbuf, slpv2_error(errcode));
   1358 	    else
   1359 		GETFIELD;
   1360 	} else if (flags & F_DTAIL) {
   1361 		V2_DOERRCODE;
   1362 		DOFIELD("Service types", FIELD_DEFAULT);
   1363 	}
   1364 
   1365 	return (1);
   1366 }
   1367 
   1368 static int v2_saadvert(int flags) {
   1369 	int auth_cnt, i;
   1370 
   1371 	if (flags & F_SUM) {
   1372 	    GETFIELD;			/* URL */
   1373 
   1374 #ifdef VERIFYSLP
   1375 	    SKIPFIELD(FIELD_DEFAULT);	/* scopes */
   1376 	    SKIPFIELD(FIELD_DEFAULT);	/* attrs */
   1377 
   1378 	    GETBYTE(auth_cnt);
   1379 	    for (i = 0; i < auth_cnt; i++)
   1380 		if (skip_v2authblock() < 0)
   1381 		    return (0);
   1382 #endif
   1383 	} else if (flags & F_DTAIL) {
   1384 	    DOFIELD("URL", FIELD_DEFAULT);
   1385 	    DOFIELD("Scopes",  FIELD_DEFAULT);
   1386 	    DOFIELD("Attribute list", FIELD_DEFAULT);
   1387 	    /* auth */
   1388 	    GETBYTE(auth_cnt);
   1389 	    for (i = 0; i < auth_cnt; i++)
   1390 		V2_DOAUTH(i);
   1391 	}
   1392 
   1393 	return (1);
   1394 }
   1395 
   1396 /*
   1397  * V1 Interpreter
   1398  */
   1399 
   1400 static int interpret_slp_v1(int flags, struct slpv1_hdr *slp, int fraglen) {
   1401 	char msgbuf_real[256];
   1402 	extern int src_port, dst_port, curr_proto;
   1403 	boolean_t overflow	= B_FALSE;
   1404 
   1405 	msgbuf = msgbuf_real;
   1406 
   1407 	if (msglength >= sizeof (*slp)) {
   1408 	    if ((slp->flags & V1_URL_AUTH) == V1_URL_AUTH)
   1409 		url_auth = B_TRUE;
   1410 	    if ((slp->flags & V1_ATTR_AUTH) == V1_ATTR_AUTH)
   1411 		attr_auth = B_TRUE;
   1412 	    if ((slp->flags & V1_FRESH_REG) == V1_FRESH_REG)
   1413 		fresh = B_TRUE;
   1414 	    if ((slp->flags & V1_OVERFLOW) == V1_OVERFLOW)
   1415 		overflow = B_TRUE;
   1416 	}
   1417 
   1418 	/*
   1419 	 * Somewhat of a hack to decode traffic from a server that does
   1420 	 * not send udp replies from its SLP src port.
   1421 	 */
   1422 	if (curr_proto == IPPROTO_UDP &&
   1423 	    dst_port == 427 &&
   1424 	    src_port != 427)
   1425 		add_transient(src_port, (int (*)())interpret_slp);
   1426 
   1427 	/* parse the header */
   1428 	if (v1_header(flags, slp, fraglen)) {
   1429 
   1430 	    if (slp->function <= V1_MAX_FUNCTION && slp->function > 0) {
   1431 
   1432 		/* Parse the message body */
   1433 		(v1_functions[slp->function])(flags);
   1434 
   1435 	    }
   1436 
   1437 	}
   1438 
   1439 	/* summary error check */
   1440 	if (flags & F_SUM) {
   1441 	    if (retlength < 0) {
   1442 		if (curr_proto == IPPROTO_TCP)
   1443 		    sprintf(get_sum_line(),
   1444 			    "%s [partial TCP message]",
   1445 			    msgbuf);
   1446 		else if (overflow)
   1447 		    sprintf(get_sum_line(), "%s [OVERFLOW]", msgbuf);
   1448 		else
   1449 		    sprintf(get_sum_line(), "%s [CORRUPTED MESSAGE]", msgbuf);
   1450 	    }
   1451 #ifdef VERIFYSLP
   1452 	    else if (msglength > 0)
   1453 		sprintf(get_sum_line(), "%s +%d", msgbuf, msglength);
   1454 #endif
   1455 	    else
   1456 		sprintf(get_sum_line(), "%s", msgbuf);
   1457 	} else if (flags & F_DTAIL) {
   1458 	    /* detail error check */
   1459 	    if (msglength > 0) {
   1460 		sprintf(get_line(0, 0),
   1461 			"[%d extra bytes at end of SLP message]", msglength);
   1462 	    }
   1463 
   1464 	    show_trailer();
   1465 
   1466 	}
   1467 
   1468 	v1_charset = 0;
   1469 
   1470 	return (0);
   1471 }
   1472 
   1473 static int v1_header(int flags,
   1474 			struct slpv1_hdr *slp,
   1475 			int fraglen) {
   1476 	extern int src_port, dst_port, curr_proto;
   1477 	char *prototag = (curr_proto == IPPROTO_TCP? "/tcp" : "");
   1478 
   1479 	if (flags & F_SUM) {
   1480 	    char portflag = ' ';
   1481 
   1482 	    if (msglength < sizeof (*slp)) {
   1483 		sprintf(msgbuf, "SLP V1 [incomplete header]");
   1484 		return (0);
   1485 	    }
   1486 
   1487 	    if (slp->vers != 1) {
   1488 		if (curr_proto == IPPROTO_TCP)
   1489 		    sprintf(msgbuf, "SLP [TCP Continuation]");
   1490 		else
   1491 		    sprintf(msgbuf, "SLP [unknown version %d]", slp->vers);
   1492 		return (0);
   1493 	    }
   1494 
   1495 	    if (src_port != 427 && dst_port != 427)
   1496 		portflag = '-';
   1497 
   1498 	    sprintf(msgbuf, "SLP V1%c%s [%d%s] ", portflag,
   1499 		    slpv1_func(slp->function, B_TRUE),
   1500 		    ntohs(slp->xid), prototag);
   1501 	    msgend = msgbuf + strlen(msgbuf);
   1502 	    msglength -= sizeof (*slp);
   1503 	    p += sizeof (*slp);
   1504 	} else if (flags & F_DTAIL) {
   1505 	    show_header("SLP:  ", "Service Location Protocol (v1)", fraglen);
   1506 	    show_space();
   1507 
   1508 	    if (msglength < sizeof (*slp)) {
   1509 		sprintf(get_line(0, 0), "==> Incomplete SLP header");
   1510 		return (0);
   1511 	    }
   1512 
   1513 	    sprintf(get_line(0, 0), "Version = %d", slp->vers);
   1514 	    if (slp->vers != 1) {
   1515 		if (curr_proto == IPPROTO_TCP)
   1516 		    sprintf(get_line(0, 0), "==> TCP continuation");
   1517 		else
   1518 		    sprintf(get_line(0, 0), "==> Unexpected version number");
   1519 		return (0);
   1520 	    }
   1521 	    sprintf(get_line(0, 0), "Function = %d, %s",
   1522 		slp->function, slpv1_func(slp->function, B_FALSE));
   1523 	    sprintf(get_line(0, 0), "Message length = %u", ntohs(slp->length));
   1524 
   1525 	    /* flags */
   1526 	    sprintf(get_line(0, 0), "Flags = 0x%02x", slp->flags);
   1527 	    sprintf(get_line(0, 0), "      %s",
   1528 		    getflag(slp->flags, V1_OVERFLOW,
   1529 			    "overflow", "no overflow"));
   1530 	    sprintf(get_line(0, 0), "      %s",
   1531 		    getflag(slp->flags, V1_MONOLINGUAL,
   1532 			    "monolingual", "not monolingual"));
   1533 	    sprintf(get_line(0, 0), "      %s",
   1534 		    getflag(slp->flags, V1_URL_AUTH,
   1535 			    "url authentication", "no url authentication"));
   1536 	    sprintf(get_line(0, 0), "      %s",
   1537 		    getflag(slp->flags, V1_ATTR_AUTH,
   1538 		"attribute authentication", "no attribute authentication"));
   1539 	    sprintf(get_line(0, 0), "      %s",
   1540 		    getflag(slp->flags, V1_FRESH_REG,
   1541 			    "fresh registration", "no fresh registration"));
   1542 	    /* check reserved flags that must be zero */
   1543 	    if ((slp->flags & 7) != 0) {
   1544 		sprintf(get_line(0, 0),
   1545 			"      .... .xxx = %d (reserved flags nonzero)",
   1546 			slp->flags & 7);
   1547 	    }
   1548 	    /* end of flags */
   1549 
   1550 	    sprintf(get_line(0, 0), "Dialect = %u", slp->dialect);
   1551 	    sprintf(get_line(0, 0), "Language = 0x%02x%02x, %c%c",
   1552 		    slp->language[0], slp->language[1],
   1553 		    slp->language[0], slp->language[1]);
   1554 	    v1_charset = ntohs(slp->charset);
   1555 	    sprintf(get_line(0, 0), "Character encoding = %u, %s",
   1556 		    v1_charset,
   1557 		    slpv1_charset(v1_charset));
   1558 	    sprintf(get_line(0, 0), "XID = %u", ntohs(slp->xid));
   1559 
   1560 	    /* set msglength to remaining length of SLP message */
   1561 	    msglength -= sizeof (*slp);
   1562 	    p += sizeof (*slp);
   1563 	}
   1564 
   1565 	return (1);
   1566 }
   1567 
   1568 static char *slpv1_func(int t, boolean_t s) {
   1569 	static char buf[128];
   1570 	switch (t) {
   1571 	case V1_SRVREQ:	return s? "SrvRqst"  : "Service Request";
   1572 	case V1_SRVRPLY:	return s? "SrvRply"  : "Service Reply";
   1573 	case V1_SRVREG:	return s? "SrvReg"   : "Service Registration";
   1574 	case V1_SRVDEREG:	return s?
   1575 					"SrvDereg" : "Service Deregistration";
   1576 	case V1_SRVACK:	return s? "SrvAck"   : "Service Acknowledge";
   1577 	case V1_ATTRRQST:	return s? "AttrRqst" : "Attribute Request";
   1578 	case V1_ATTRRPLY:	return s? "AttrRply" : "Attribute Reply";
   1579 	case V1_DAADVERT:	return s? "DAAdvert" : "DA advertisement";
   1580 	case V1_SRVTYPERQST:return s? "SrvTypeRqst" : "Service Type Request";
   1581 	case V1_SRVTYPERPLY:return s? "SrvTypeRply" : "Service Type Reply";
   1582 	}
   1583 	sprintf(buf, "(func %d)", t);
   1584 	return (s ? buf : "unknown function");
   1585 }
   1586 
   1587 static char *slpv1_error(unsigned short code) {
   1588 	static char buf[128];
   1589 
   1590 	switch (code) {
   1591 	    case OK:			return "ok";
   1592 	    case LANG_NOT_SUPPORTED:	return "language not supported";
   1593 	    case PROTOCOL_PARSE_ERR:	return "protocol parse error";
   1594 	    case INVALID_REGISTRATION:	return "invalid registration";
   1595 	    case SCOPE_NOT_SUPPORTED:	return "scope not supported";
   1596 	    case CHARSET_NOT_UNDERSTOOD:return "character set not understood";
   1597 	    case AUTHENTICATION_INVALID:return "invalid authentication";
   1598 	    case NOT_SUPPORTED_YET:	return "not yet supported";
   1599 	    case REQUEST_TIMED_OUT:	return "request timed out";
   1600 	    case COULD_NOT_INIT_NET_RESOURCES:
   1601 				return ("could not initialize net resources");
   1602 	    case COULD_NOT_ALLOCATE_MEMORY:
   1603 					return ("could not allocate memory");
   1604 	    case PARAMETER_BAD:		return "bad parameter";
   1605 	    case INTERNAL_NET_ERROR:	return "internal network error";
   1606 	    case INTERNAL_SYSTEM_ERROR:	return "internal system error";
   1607 	}
   1608 	sprintf(buf, "error %d", code);
   1609 	return (buf);
   1610 }
   1611 
   1612 /*
   1613  *  Character set info from
   1614  *    www.isi.edu/in-notes/iana/assignments/character-sets
   1615  *
   1616  *	Assigned MIB enum Numbers
   1617  *	-------------------------
   1618  *	0               Reserved
   1619  *	1               Reserved
   1620  *	3-106           Set By Standards Organizations
   1621  *	1000-1010       Unicode / 10646
   1622  *	2000-2087       Vendor
   1623  *	2250-2258       Vendor
   1624  *
   1625  *	MIBenum: 3
   1626  *	Alias: US-ASCII (preferred MIME name)
   1627  *	Source: ECMA registry [RFC1345]
   1628  *
   1629  *	MIBenum: 106
   1630  *	Name: UTF-8
   1631  *	Source: RFC 2044
   1632  */
   1633 
   1634 static char *slpv1_charset(unsigned short code) {
   1635 	if (code <= 1)
   1636 	    return ("Reserved");
   1637 	if (code == 3)
   1638 	    return ("US-ASCII");
   1639 	if (code == 4)
   1640 	    return ("latin1");
   1641 	if (code == 106)
   1642 	    return ("UTF-8");
   1643 	if (code >= 3 && code <= 106)
   1644 	    return ("set by standards organization");
   1645 	if (code >= 1000 && code <= 1010)
   1646 	    return ("Unicode variant");
   1647 	if ((code >= 2000 && code <= 2087) ||
   1648 	    (code >= 2250 && code <= 2258))
   1649 	    return ("Vendor assigned");
   1650 
   1651 	return ("unknown");
   1652 }
   1653 
   1654 #ifdef VERIFYSLP
   1655 static int skip_v1authblock() {
   1656 	unsigned short length;
   1657 
   1658 	/* auth header: 12 bytes total */
   1659 	if (msglength < 12)
   1660 	    return (-1);
   1661 
   1662 	/* timestamp: 8 bytes */
   1663 	p += 8;			/* timestamp: 8 bytes */
   1664 	p += sizeof (short);		/* block descriptor: 2 bytes */
   1665 	nbtohs();
   1666 	length = netval;
   1667 	p += sizeof (short);
   1668 	msglength -= 12;
   1669 
   1670 	if (length > msglength) {
   1671 	    /* framing error: message is not long enough to contain data */
   1672 	    return (-1);
   1673 	}
   1674 
   1675 	p += length;
   1676 	msglength -= length;
   1677 	return (0);
   1678 }
   1679 #endif
   1680 
   1681 static int slpv1_authblock() {
   1682 	unsigned short bsd, length;
   1683 	char msgbuf[128];
   1684 	int n;
   1685 
   1686 	if (msglength < 12) {
   1687 	    sprintf(get_line(0, 0),
   1688 		    "  [no room for auth block: remaining msg length = %u]",
   1689 		    msglength);
   1690 	    return (-1);
   1691 	}
   1692 
   1693 	/* timestamp: 8 bytes */
   1694 	*msgbuf = '\0';
   1695 	for (n = 0; n < 8; n++, p += 1) {
   1696 	    char tmp[16];
   1697 	    sprintf(tmp, "%02x", (unsigned char)(*p));
   1698 	    strcat(msgbuf, tmp);
   1699 	}
   1700 
   1701 	nbtohs();
   1702 	bsd = netval;
   1703 	p += sizeof (short);
   1704 	nbtohs();
   1705 	length = netval;
   1706 	p += sizeof (short);
   1707 	msglength -= 12;
   1708 
   1709 	sprintf(get_line(0, 0),
   1710 		"  Auth block: timestamp = %s",
   1711 		msgbuf);
   1712 	sprintf(get_line(0, 0),
   1713 		"              block desc = 0x%04x, length = %u",
   1714 		bsd, length);
   1715 	if (length > msglength) {
   1716 	    /* framing error: message is not long enough to contain data */
   1717 	    sprintf(get_line(0, 0),
   1718 		"  [Framing error: remaining pkt length = %u]",  msglength);
   1719 	    return (-1);
   1720 	}
   1721 
   1722 	p += length;
   1723 	msglength -= length;
   1724 	return (0);
   1725 }
   1726 
   1727 static int slpv1_url(boolean_t auth_present) {
   1728 	time_t exp;
   1729 	int lifetime, length;
   1730 
   1731 	get_short();
   1732 	if ((lifetime = netval) < 0)
   1733 	    return (-1);
   1734 	get_short();
   1735 	if ((length = netval) < 0)
   1736 	    return (-1);
   1737 
   1738 	exp = time(0) + lifetime;
   1739 	sprintf(get_line(0, 0), "URL: length = %u, lifetime = %d (%24.24s)",
   1740 		length, lifetime, ctime(&exp));
   1741 	if (length > msglength) {
   1742 	    /* framing error: message is not long enough to contain data */
   1743 	    sprintf(get_line(0, 0),
   1744 		"  [Framing error: remaining pkt length = %u]",  msglength);
   1745 	    return (-1);
   1746 	}
   1747 
   1748 	if (length > 0) {
   1749 	    char *buf = malloc(length + 1);
   1750 	    if (buf != NULL) {
   1751 		if (!make_utf8(buf, length, p, length)) {
   1752 			strcpy(buf, "[Invalid Character Encoding]");
   1753 		}
   1754 		sprintf(get_line(0, 0), "  \"%s\"", buf);
   1755 		free(buf);
   1756 	    }
   1757 	}
   1758 	msglength -= length;
   1759 	p += length;
   1760 
   1761 	if (auth_present)
   1762 	    return (slpv1_authblock());
   1763 
   1764 	return (0);
   1765 }
   1766 
   1767 static int v1_srv_rqst(int flags) {
   1768 	if (flags & F_SUM) {
   1769 	    SKIPFIELD(FIELD_PREVRESP);	/* prev responders */
   1770 	    GETFIELD;			/* predicate */
   1771 	} else if (flags & F_DTAIL) {
   1772 	    DOFIELD("Previous responders", FIELD_PREVRESP);
   1773 	    DOFIELD("predicate string", FIELD_DEFAULT);
   1774 	}
   1775 
   1776 	return (1);
   1777 }
   1778 
   1779 static int v1_srv_rply(int flags) {
   1780 	unsigned short errcode, itemcnt;
   1781 	int n;
   1782 
   1783 	if (flags & F_SUM) {
   1784 	    GETSHORT(errcode);
   1785 	    if (errcode != OK) {
   1786 		strcat(msgbuf, slpv1_error(errcode));
   1787 	    } else {
   1788 		GETSHORT(itemcnt);
   1789 		sprintf(msgend, "%d URL entries", itemcnt);
   1790 #ifdef VERIFYSLP
   1791 		for (n = 0; n < itemcnt; n++) {
   1792 		    SKIPSHORT;		/* lifetime */
   1793 		    SKIPFIELD(FIELD_DEFAULT);	/* URL */
   1794 		    SKIPAUTH(url_auth);		/* URL auth */
   1795 		}
   1796 #endif
   1797 	    }
   1798 	} else if (flags & F_DTAIL) {
   1799 	    DOERRCODE;
   1800 	    GETSHORT(itemcnt);
   1801 	    sprintf(get_line(0, 0), "URL entry count = %d", itemcnt);
   1802 	    for (n = 0; n < itemcnt; n++) {
   1803 		DOURL;
   1804 	    }
   1805 	}
   1806 
   1807 	return (1);
   1808 }
   1809 
   1810 static int v1_srv_reg(int flags) {
   1811 	if (flags & F_SUM) {
   1812 	    SKIPSHORT;			/* lifetime */
   1813 	    GETFIELD;			/* URL */
   1814 #ifdef VERIFYSLP
   1815 	    SKIPAUTH(url_auth);		/* URL auth */
   1816 	    SKIPFIELD(FIELD_DEFAULT);	/* attribute list */
   1817 	    SKIPAUTH(attr_auth);		/* attr auth */
   1818 #endif
   1819 	} else if (flags & F_DTAIL) {
   1820 	    DOURL;
   1821 	    DOFIELD("Attribute list", FIELD_DEFAULT);
   1822 	    DOAUTH(attr_auth);
   1823 	}
   1824 
   1825 	return (1);
   1826 }
   1827 
   1828 static int v1_srv_ack(int flags) {
   1829 	unsigned short errcode;
   1830 
   1831 	if (flags & F_SUM) {
   1832 	    GETSHORT(errcode);
   1833 	    strcat(msgbuf, slpv1_error(errcode));
   1834 	    if (errcode == OK && fresh) {
   1835 		strcat(msgbuf, " [Fresh]");
   1836 	    }
   1837 	} else if (flags & F_DTAIL) {
   1838 	    DOERRCODE;
   1839 	}
   1840 
   1841 	return (1);
   1842 }
   1843 
   1844 static int v1_srv_dereg(int flags) {
   1845 	if (flags & F_SUM) {
   1846 	    GETFIELD;			/* URL */
   1847 #ifdef VERIFYSLP
   1848 	    SKIPAUTH(url_auth);
   1849 	    SKIPFIELD(FIELD_DEFAULT);	/* tag spec */
   1850 #endif
   1851 	} else if (flags & F_DTAIL) {
   1852 	    DOFIELD("URL", FIELD_DEFAULT);
   1853 	    DOAUTH(url_auth);
   1854 	    DOFIELD("Tag spec", FIELD_DEFAULT);
   1855 	}
   1856 
   1857 	return (1);
   1858 }
   1859 
   1860 static int v1_attr_rqst(int flags) {
   1861 	if (flags & F_SUM) {
   1862 	    SKIPFIELD(FIELD_PREVRESP);	/* prev responders */
   1863 	    GETFIELD;			/* URL */
   1864 #ifdef VERIFYSLP
   1865 	    SKIPFIELD(FIELD_DEFAULT);	/* scope */
   1866 	    SKIPFIELD(FIELD_DEFAULT);	/* select list */
   1867 #endif
   1868 	} else if (flags & F_DTAIL) {
   1869 	    DOFIELD("Previous responders", FIELD_PREVRESP);
   1870 	    DOFIELD("URL", FIELD_DEFAULT);
   1871 	    DOFIELD("Scope", FIELD_DEFAULT);
   1872 	    DOFIELD("Select list", FIELD_DEFAULT);
   1873 	}
   1874 
   1875 	return (1);
   1876 }
   1877 
   1878 static int v1_attr_rply(int flags) {
   1879 	unsigned short errcode;
   1880 
   1881 	if (flags & F_SUM) {
   1882 	    GETSHORT(errcode);
   1883 	    if (errcode != OK) {
   1884 		strcat(msgbuf, slpv1_error(errcode));
   1885 	    } else {
   1886 		GETFIELD;			/* attr list */
   1887 #ifdef VERIFYSLP
   1888 		SKIPAUTH(attr_auth);
   1889 #endif
   1890 	    }
   1891 	} else if (flags & F_DTAIL) {
   1892 	    DOERRCODE;
   1893 	    DOFIELD("Attribute list", FIELD_DEFAULT);
   1894 	    DOAUTH(attr_auth);
   1895 	}
   1896 
   1897 	return (1);
   1898 }
   1899 
   1900 static int v1_daadvert(int flags) {
   1901 	unsigned short errcode;
   1902 
   1903 	if (flags & F_SUM) {
   1904 	    GETSHORT(errcode);
   1905 	    if (errcode != OK) {
   1906 		strcat(msgbuf, slpv1_error(errcode));
   1907 	    } else {
   1908 		    GETFIELD;			/* URL */
   1909 #ifdef VERIFYSLP
   1910 		    SKIPFIELD(FIELD_DEFAULT);	/* scope list */
   1911 #endif
   1912 	    }
   1913 	} else if (flags & F_DTAIL) {
   1914 	    DOERRCODE;
   1915 	    DOFIELD("URL", FIELD_DEFAULT);
   1916 	    DOFIELD("Scope list", FIELD_DEFAULT);
   1917 	}
   1918 
   1919 	return (1);
   1920 }
   1921 
   1922 static int v1_srv_type_rqst(int flags) {
   1923 	if (flags & F_SUM) {
   1924 	    SKIPFIELD(FIELD_PREVRESP);	/* prev responders */
   1925 	    SKIPFIELD(FIELD_TYPENA);	/* naming authority */
   1926 	    GETFIELD;			/* scope */
   1927 	} else if (flags & F_DTAIL) {
   1928 	    DOFIELD("Previous responders", FIELD_PREVRESP);
   1929 	    DOFIELD("Naming authority", FIELD_TYPENA);
   1930 	    DOFIELD("Scope string", FIELD_DEFAULT);
   1931 	}
   1932 
   1933 	return (1);
   1934 }
   1935 
   1936 static int v1_srv_type_rply(int flags) {
   1937 	unsigned short errcode, itemcnt;
   1938 	int n;
   1939 
   1940 	if (flags & F_SUM) {
   1941 	    GETSHORT(errcode);
   1942 	    if (errcode != OK) {
   1943 		strcat(msgbuf, slpv1_error(errcode));
   1944 	    } else {
   1945 		GETSHORT(itemcnt);
   1946 		sprintf(msgend, "%d type entries", itemcnt);
   1947 #ifdef VERIFYSLP
   1948 		for (n = 0; n < itemcnt; n++) {
   1949 		    SKIPFIELD(FIELD_DEFAULT);  /* Service type item */
   1950 		}
   1951 #endif
   1952 	    }
   1953 	} else if (flags & F_DTAIL) {
   1954 	    DOERRCODE;
   1955 	    GETSHORT(itemcnt);
   1956 	    sprintf(get_line(0, 0), "Service type count = %d", itemcnt);
   1957 	    for (n = 0; n < itemcnt; n++) {
   1958 		DOFIELD("  Service type item", FIELD_DEFAULT);
   1959 	    }
   1960 	}
   1961 
   1962 	return (1);
   1963 }
   1964