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
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.
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]
23 * Copyright (c) 1998,2000 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 #include <arpa/inet.h>
40 /* define VERIFYSLP to enable full message checking in summary mode */
43 /* Globals -- ugly, yes, but fast and easy in macros */
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 */
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);
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);
65 static int slpv2_authblock(int);
67 /* From snoop_rport: */
68 extern int add_transient(int, int (*)());
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.
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);
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);
100 * The dispatch tables for handling individual messages, keyed by
103 typedef int function_handler();
105 #define V2_MAX_FUNCTION 11
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
};
121 #define V1_MAX_FUNCTION 10
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
};
136 /* TCP continuation handling */
137 static boolean_t tcp_continuation
= B_FALSE
;
139 #define MAX_TCPCONT 16
141 static struct tcp_cont
{
146 } *tcp_cont
[MAX_TCPCONT
];
148 static int current_tcp_cont
;
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);
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);
163 * The only external entry point to the SLP interpreter. This function
164 * simply dispatches the packet based on the version.
166 void interpret_slp(int flags
, char *slp
, int fraglen
) {
167 extern int dst_port
, curr_proto
;
168 struct tcp_cont
*tce
= NULL
;
174 /* check if this is a TCP continuation */
175 if (flags
& F_DTAIL
&& curr_proto
== IPPROTO_TCP
) {
176 tce
= find_tcp_cont(dst_port
);
178 if (add_tcp_cont(tce
, slp
, fraglen
)) {
180 fraglen
= tce
->curr_offset
;
181 tcp_continuation
= B_TRUE
;
185 if (*slp
== 2 || tce
)
186 interpret_slp_v2(flags
, (void *)slp
, fraglen
);
188 interpret_slp_v1(flags
, (void *)slp
, fraglen
);
190 tcp_continuation
= B_FALSE
;
194 * Primitives. These are implemented as much as possible as macros for
198 #define FIELD_DEFAULT 0
199 #define FIELD_PREVRESP 1
200 #define FIELD_TYPENA 2
202 static long long netval
= 0; /* need signed 64 bit quantity */
204 /* gets two bytes from p and leaves the result in netval */
206 netval = ((int)(p[0] & 0xff)) << 8; \
207 netval += ((int)(p[1] & 0xff))
209 /* gets four bytes from p and leaves the result in netval */
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))
217 if (msglength >= 1) { \
226 if ((retlength = netval) < 0) \
232 if ((retlength = netval) < 0) \
236 * gets two bytes from p, leaves the result in netval, and updates
239 #define get_short() \
240 if (msglength >= sizeof (unsigned short)) { \
242 p += sizeof (unsigned short); \
243 msglength -= sizeof (unsigned short); \
247 #define GETSHORT(x) \
249 if ((retlength = netval) < 0) \
255 if ((retlength = netval) < 0) \
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))
263 static void slp_prevresp(char *p
) {
266 /* cycle through all entries */
267 for (; p
!= NULL
; p
= p2
) {
272 /* print entry at p */
273 sprintf(get_line(0, 0), " \"%s\"", p
);
277 static int skip_field(int type
) {
278 unsigned short stringlen
;
286 /* special case for NA field in SrvTypeRqst */
287 if (type
== FIELD_TYPENA
&& stringlen
== 0xffff) {
291 if (stringlen
> msglength
) {
295 msglength
-= stringlen
;
301 #define SKIPFIELD(type) \
302 if ((retlength = skip_field(type)) < 0) \
307 if ((retlength = netval) < 0) \
309 strncat(msgbuf, p, (retlength > MAXSUMLEN ? MAXSUMLEN : retlength)); \
311 msglength -= retlength
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.
318 int valid_slp(unsigned char *slphdr
, int len
) {
319 struct slpv1_hdr slp1
;
320 struct slpv2_hdr slp2
;
322 len
-= (8 /* udp */ + 20 /* IP */ + 14 /* ether */);
323 /* a valid version will be 1 or 2 */
326 memcpy(&slp1
, slphdr
, 5);
327 /* valid function? */
328 if (slp1
.function
> V1_MAX_FUNCTION
) {
331 /* valid length heuristic */
332 if (slp1
.length
> len
) {
337 memcpy(&slp2
, slphdr
, 5);
338 /* valid function? */
339 if (slp2
.function
> V2_MAX_FUNCTION
) {
342 /* valid length heuristic */
343 get_int24(&(slp2
.l1
));
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.
358 static int make_utf8(char *outbuf
, size_t outlen
,
359 const char *inbuf
, size_t inlen
) {
363 switch (v1_charset
) {
366 cd
= iconv_open("UTF-8", "8859-1");
369 cd
= iconv_open("UTF-8", "8859-2");
372 cd
= iconv_open("UTF-8", "8859-3");
375 cd
= iconv_open("UTF-8", "8859-4");
378 cd
= iconv_open("UTF-8", "8859-5");
381 cd
= iconv_open("UTF-8", "8859-6");
384 cd
= iconv_open("UTF-8", "8859-7");
387 cd
= iconv_open("UTF-8", "8859-8");
390 cd
= iconv_open("UTF-8", "8859-9");
393 cd
= iconv_open("UTF-8", "8859-10");
396 cd
= iconv_open("UTF-8", "ko_KR-iso2022-7");
399 cd
= iconv_open("UTF-8", "iso2022");
402 cd
= iconv_open("UTF-8", "UCS-2");
405 cd
= iconv_open("UTF-8", "UCS-4");
409 * charset not set, or reserved, or not supported, so
410 * just copy it and hope for the best.
412 converted
= outlen
< inlen
? outlen
: inlen
;
413 memcpy(outbuf
, inbuf
, converted
);
414 outbuf
[converted
] = 0;
418 if (cd
== (iconv_t
)-1) {
422 if ((converted
= iconv(cd
, &inbuf
, &inlen
, &outbuf
, &outlen
))
427 outbuf
[converted
] = 0;
433 static int slp_field(char *tag
, int type
) {
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
);
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]",
458 char *buf
= malloc(length
+ 1);
461 if (!make_utf8(buf
, length
, p
, length
)) {
462 strcpy(buf
, "[Invalid Character Encoding]");
465 memcpy(buf
, p
, length
);
466 buf
[length
] = '\0'; /* ensure null-terminated */
475 sprintf(get_line(0, 0), " \"%s\"", buf
);
489 static int slpv2_url(int cnt
) {
491 int lifetime
, length
, n
;
500 if ((lifetime
= netval
) < 0)
505 if ((length
= netval
) < 0)
509 exp
= time(0) + lifetime
;
511 sprintf(get_line(0, 0),
512 "URL: length = %u, lifetime = %d (%24.24s)",
513 length
, lifetime
, ctime(&exp
));
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
));
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]",
530 char *buf
= malloc(length
+ 1);
532 memcpy(buf
, p
, length
);
533 buf
[length
] = '\0'; /* ensure null-terminated */
534 sprintf(get_line(0, 0), " \"%s\"", buf
);
542 if ((n
= netval
) < 0)
547 sprintf(get_line(0, 0), "%d Authentication Blocks", n
);
548 for (i
= 0; i
< n
; i
++)
549 if ((length
= slpv2_authblock(i
)) < 0)
555 #define DOFIELD(tag, type) \
556 if (slp_field(tag, type) < 0) \
559 #define V2_DOURL(x) \
560 if (slpv2_url(x) < 0) \
563 #define V2_DOERRCODE \
564 if (msglength < sizeof (unsigned short)) \
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); \
573 msglength = 0; /* skip rest of message */ \
577 #define V2_DOAUTH(cnt) \
578 if (slpv2_authblock(cnt) < 0) \
581 #define V2_DOTIMESTAMP \
585 timestamp = netval; \
586 sprintf(get_line(0, 0), "Timestamp = %u, %s", \
587 timestamp, (timestamp ? convert_ts(timestamp) : "0")); \
592 #define SKIPAUTH(auth) \
593 if (auth && ((retlength = skip_v1authblock()) < 0)) \
597 if (msglength < sizeof (unsigned short)) \
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); \
609 if (slpv1_url(url_auth) < 0) \
612 #define DOAUTH(auth) \
613 if (auth && slpv1_authblock() < 0) \
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.
622 static void reg_tcp_cont(char *msg
, int totallen
,
623 int fraglen
, int dst_port
) {
624 struct tcp_cont
*tce
= malloc(sizeof (*tce
));
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
]);
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
;
638 tcp_cont
[current_tcp_cont
++] = tce
;
639 if (current_tcp_cont
== MAX_TCPCONT
)
640 current_tcp_cont
= 0;
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
)
648 memcpy(tce
->msg
+ tce
->curr_offset
, msg
, fraglen
);
649 tce
->curr_offset
+= fraglen
;
653 static struct tcp_cont
*find_tcp_cont(int dst_port
) {
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
]);
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
]);
666 static void remove_tcp_cont(int dst_port
) {
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
);
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
);
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];
694 msgbuf
= msgbuf_real
;
697 * Somewhat of a hack to decode traffic from a server that does
698 * not send udp replies from its SLP src port.
701 if (curr_proto
== IPPROTO_UDP
&&
704 add_transient(src_port
, (int (*)())interpret_slp
);
707 /* parse the header */
708 if (v2_header(flags
, slp
, &totallen
, fraglen
)) {
710 if (slp
->function
<= V2_MAX_FUNCTION
&& slp
->function
> 0) {
712 /* Parse the message body */
713 if ((v2_functions
[slp
->function
])(flags
)) {
715 /* finish any remaining tasks */
716 v2_finish(slp
, flags
);
724 /* summary error check */
727 if (curr_proto
== IPPROTO_TCP
)
728 sprintf(get_sum_line(),
729 "%s [partial TCP message]", msgbuf
);
731 sprintf(get_sum_line(), "%s [OVERFLOW]", msgbuf
);
733 sprintf(get_sum_line(), "%s [CORRUPTED MESSAGE]", msgbuf
);
736 else if (msglength
> 0)
737 sprintf(get_sum_line(), "%s +%d", msgbuf
, msglength
);
740 sprintf(get_sum_line(), "%s", msgbuf
);
741 } else if (flags
& F_DTAIL
) {
742 /* detailed error check */
744 if (tcp_continuation
) {
745 sprintf(get_line(0, 0),
746 "[TCP Continuation, %d bytes remaining]",
749 sprintf(get_line(0, 0),
750 "[%d extra bytes at end of SLP message]", msglength
);
755 if (tcp_continuation
&& msglength
== 0)
756 remove_tcp_cont(dst_port
);
762 static int v2_header(int flags
,
763 struct slpv2_hdr
*slp
,
766 extern int curr_proto
, dst_port
;
767 char *prototag
= (curr_proto
== IPPROTO_TCP
? "/tcp" : "");
769 if ((slp
->flags
& V2_OVERFLOW
) == V2_OVERFLOW
)
772 /* summary mode header parsing */
775 /* make sure we have at least a header */
776 if (msglength
< sizeof (*slp
)) {
777 sprintf(get_sum_line(), "SLP V2 [Incomplete Header]");
781 sprintf(msgbuf
, "SLP V2 %s [%d%s] ",
782 slpv2_func(slp
->function
, B_TRUE
),
783 ntohs(slp
->xid
), prototag
);
785 /* skip to end of header */
786 msgend
= msgbuf
+ strlen(msgbuf
);
787 msglength
-= sizeof (*slp
);
790 /* skip language tag */
791 SKIPFIELD(FIELD_DEFAULT
);
792 } else if (flags
& F_DTAIL
) {
796 /* detailed mode header parsing */
797 show_header("SLP: ", "Service Location Protocol (v2)", fraglen
);
800 if (msglength
< sizeof (*slp
)) {
801 sprintf(get_line(0, 0), "==> Incomplete SLP header");
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
));
810 sprintf(get_line(0, 0), "Message length = %u", *totallen
);
811 /* check for TCP continuation */
812 if (curr_proto
== IPPROTO_TCP
&&
813 *totallen
> msglength
&&
815 tcp_continuation
= B_TRUE
;
816 reg_tcp_cont((char *)slp
, *totallen
, msglength
, dst_port
);
819 if (!tcp_continuation
&& *totallen
!= msglength
) {
820 sprintf(get_line(0, 0),
821 " (Stated and on-the-wire lengths differ)");
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)",
843 p
= (char *)slp
+ sizeof (*slp
);
844 msglength
-= sizeof (*slp
);
846 if (len
> msglength
) {
847 sprintf(get_line(0, 0),
848 "Language Tag Length = %u [CORRUPT MESSAGE]",
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
));
858 /* set msglength to remaining length of SLP message */
866 static int v2_finish(struct slpv2_hdr
*slp
, int flags
) {
867 unsigned int firstop
;
869 if (!(flags
& F_DTAIL
))
872 /* check for options */
873 get_int24(&(slp
->o1
));
877 unsigned short op_id
;
878 unsigned short nextop
;
882 unsigned short real_oplen
;
885 sprintf(get_line(0, 0),
886 "Option expected but not present");
892 p
+= sizeof (unsigned short);
893 msglength
-= sizeof (unsigned short);
896 p
+= sizeof (unsigned short);
897 msglength
-= sizeof (unsigned short);
899 real_oplen
= nextop
? nextop
: msglength
;
904 sprintf(get_line(0, 0),
905 "Option: Required Attribute Missing");
906 DOFIELD("Template IDVer", FIELD_DEFAULT
);
907 DOFIELD("Required Attrs", FIELD_DEFAULT
);
910 sprintf(get_line(0, 0), "Option: Unknown");
911 p
+= (real_oplen
- 4);
912 msglength
-= (real_oplen
- 4);
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",
927 ((nextop
- 4) > msglength
) &&
929 sprintf(get_line(0, 0),
930 "[Framing error: remaining pkt length = %u]",
935 sprintf(get_line(0, 0), "Option Length = %u", real_oplen
);
946 static int skip_v2authblock() {
947 unsigned short length
, slen
;
953 /* block descriptor: 2 bytes */
954 p
+= sizeof (unsigned short);
958 p
+= sizeof (unsigned short);
961 /* SPI String length */
964 p
+= sizeof (unsigned short);
967 if (slen
> msglength
|| length
> (msglength
+ 10))
973 /* structured auth block */
974 p
+= (length
- 10 - slen
);
975 msglength
-= (length
- 10 - slen
);
980 static char *display_bsd(unsigned short 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");
989 static char *slpv2_func(int t
, boolean_t s
) {
990 static char buf
[128];
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";
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";
1008 sprintf(buf
, "(func %d)", t
);
1009 return (s
? buf
: "unknown function");
1012 static char *slpv2_error(unsigned short code
) {
1013 static char buf
[128];
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";
1032 sprintf(buf
, "error %d", code
);
1036 static char *convert_ts(unsigned int timestamp
) {
1037 /* timestamp is in UNIX time */
1038 static char buff
[128];
1040 strcpy(buff
, ctime((time_t *)×tamp
));
1041 buff
[strlen(buff
) - 1] = '\0';
1045 static int slpv2_authblock(int cnt
) {
1046 unsigned short bsd
, length
, slen
;
1048 unsigned int timestamp
;
1050 if (msglength
< 10) {
1051 sprintf(get_line(0, 0),
1052 " [no room for auth block header: remaining msg length = %u]",
1060 p
+= sizeof (unsigned short);
1065 p
+= sizeof (unsigned short);
1072 /* SPI String length */
1075 p
+= sizeof (unsigned short);
1078 if (slen
> msglength
) {
1079 sprintf(get_line(0, 0),
1080 " [no room for auth block scopes: remaining msg length = %u]",
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]",
1098 sprintf(get_line(0, 0),
1099 "Auth block %d: timestamp = %s", cnt
,
1100 (timestamp
) ? convert_ts(timestamp
) : "0");
1102 pp
= get_line(0, 0);
1103 strcpy(pp
, " SPI = ");
1104 strncat(pp
, scopes
, slen
);
1106 sprintf(get_line(0, 0),
1107 " block desc = 0x%04x: %s", bsd
, display_bsd(bsd
));
1109 sprintf(get_line(0, 0), " length = %u", length
);
1111 p
+= (length
- 10 - slen
);
1112 msglength
-= (length
- 10 - slen
);
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
);
1136 static int v2_srv_rply(int flags
) {
1137 unsigned short itemcnt
, errcode
;
1140 if (flags
& F_SUM
) {
1144 if (errcode
!= OK
) {
1145 strcat(msgbuf
, slpv2_error(errcode
));
1146 msglength
= 0; /* skip rest of message */
1150 sprintf(msgend
, "%d URL entries", itemcnt
);
1152 for (n
= 0; n
< itemcnt
; n
++) {
1153 SKIPBYTE
; /* reserved */
1154 SKIPSHORT
; /* lifetime */
1155 SKIPFIELD(FIELD_DEFAULT
); /* URL */
1157 for (i
= 0; i
< auth_cnt
; auth_cnt
++)
1158 if (skip_v2authblock() < 0)
1163 } else if (flags
& F_DTAIL
) {
1166 sprintf(get_line(0, 0), "URL entry count = %d", itemcnt
);
1167 for (n
= 0; n
< itemcnt
; n
++) {
1175 static int v2_srv_reg(int flags
) {
1178 if (flags
& F_SUM
) {
1179 SKIPBYTE
; /* reserved */
1180 SKIPSHORT
; /* lifetime */
1184 for (i
= 0; i
< auth_cnt
; i
++)
1185 if (skip_v2authblock() < 0)
1187 SKIPFIELD(FIELD_DEFAULT
); /* type */
1188 SKIPFIELD(FIELD_DEFAULT
); /* scopes */
1189 SKIPFIELD(FIELD_DEFAULT
); /* attrs */
1191 for (i
= 0; i
< auth_cnt
; i
++)
1192 if (skip_v2authblock() < 0)
1195 } if (flags
& F_DTAIL
) {
1197 DOFIELD("Service type", FIELD_DEFAULT
);
1198 DOFIELD("Scopes", FIELD_DEFAULT
);
1199 DOFIELD("Attribute list", FIELD_DEFAULT
);
1202 for (i
= 0; i
< auth_cnt
; i
++)
1209 static int v2_srv_dereg(int flags
) {
1210 if (flags
& F_SUM
) {
1213 SKIPFIELD(FIELD_DEFAULT
); /* scopes */
1214 SKIPBYTE
; /* reserved */
1215 SKIPSHORT
; /* lifetime */
1220 for (i
= 0; i
< auth_cnt
; i
++)
1221 if (skip_v2authblock() < 0)
1223 SKIPFIELD(FIELD_DEFAULT
); /* attrs */
1225 } else if (flags
& F_DTAIL
) {
1226 DOFIELD("Scopes", FIELD_DEFAULT
);
1228 DOFIELD("Tag list", FIELD_DEFAULT
);
1234 static int v2_srv_ack(int flags
) {
1235 unsigned short errcode
;
1236 if (flags
& F_SUM
) {
1238 strcat(msgbuf
, slpv2_error(errcode
));
1239 } else if (flags
& F_DTAIL
) {
1246 static int v2_attr_rqst(int flags
) {
1247 if (flags
& F_SUM
) {
1248 SKIPFIELD(FIELD_DEFAULT
); /* PR list */
1250 SKIPFIELD(FIELD_DEFAULT
); /* scopes */
1251 strcat(msgend
, " [");
1252 GETFIELD
; /* attrs */
1253 strcat(msgend
, "]");
1256 SKIPFIELD(FIELD_DEFAULT
); /* SPI */
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
);
1269 static int v2_attr_rply(int flags
) {
1271 unsigned short errcode
;
1273 if (flags
& F_SUM
) {
1275 if (errcode
!= OK
) {
1276 strcat(msgbuf
, slpv2_error(errcode
));
1277 msglength
= 0; /* skip rest of message */
1280 GETFIELD
; /* attr list */
1284 for (i
= 0; i
< auth_cnt
; i
++)
1285 if (skip_v2authblock() < 0)
1289 } else if (flags
& F_DTAIL
) {
1291 DOFIELD("Attribute list", FIELD_DEFAULT
);
1294 for (i
= 0; i
< auth_cnt
; i
++)
1301 static int v2_daadvert(int flags
) {
1303 unsigned short errcode
;
1304 unsigned int timestamp
;
1306 if (flags
& F_SUM
) {
1307 SKIPSHORT
; /* error code */
1308 SKIPSHORT
; SKIPSHORT
; /* timestamp */
1312 SKIPFIELD(FIELD_DEFAULT
); /* scopes */
1313 SKIPFIELD(FIELD_DEFAULT
); /* attrs */
1314 SKIPFIELD(FIELD_DEFAULT
); /* SPIs */
1317 for (i
= 0; i
< auth_cnt
; i
++)
1318 if (skip_v2authblock() < 0)
1321 } else if (flags
& F_DTAIL
) {
1324 DOFIELD("URL", FIELD_DEFAULT
);
1325 DOFIELD("Scope list", FIELD_DEFAULT
);
1326 DOFIELD("Attribute list", FIELD_DEFAULT
);
1327 DOFIELD("Configured SPIs", FIELD_DEFAULT
);
1330 for (i
= 0; i
< auth_cnt
; i
++)
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
);
1351 static int v2_srv_type_rply(int flags
) {
1352 unsigned short errcode
;
1354 if (flags
& F_SUM
) {
1357 strcat(msgbuf
, slpv2_error(errcode
));
1360 } else if (flags
& F_DTAIL
) {
1362 DOFIELD("Service types", FIELD_DEFAULT
);
1368 static int v2_saadvert(int flags
) {
1371 if (flags
& F_SUM
) {
1375 SKIPFIELD(FIELD_DEFAULT
); /* scopes */
1376 SKIPFIELD(FIELD_DEFAULT
); /* attrs */
1379 for (i
= 0; i
< auth_cnt
; i
++)
1380 if (skip_v2authblock() < 0)
1383 } else if (flags
& F_DTAIL
) {
1384 DOFIELD("URL", FIELD_DEFAULT
);
1385 DOFIELD("Scopes", FIELD_DEFAULT
);
1386 DOFIELD("Attribute list", FIELD_DEFAULT
);
1389 for (i
= 0; i
< auth_cnt
; i
++)
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
;
1405 msgbuf
= msgbuf_real
;
1407 if (msglength
>= sizeof (*slp
)) {
1408 if ((slp
->flags
& V1_URL_AUTH
) == V1_URL_AUTH
)
1410 if ((slp
->flags
& V1_ATTR_AUTH
) == V1_ATTR_AUTH
)
1412 if ((slp
->flags
& V1_FRESH_REG
) == V1_FRESH_REG
)
1414 if ((slp
->flags
& V1_OVERFLOW
) == V1_OVERFLOW
)
1419 * Somewhat of a hack to decode traffic from a server that does
1420 * not send udp replies from its SLP src port.
1422 if (curr_proto
== IPPROTO_UDP
&&
1425 add_transient(src_port
, (int (*)())interpret_slp
);
1427 /* parse the header */
1428 if (v1_header(flags
, slp
, fraglen
)) {
1430 if (slp
->function
<= V1_MAX_FUNCTION
&& slp
->function
> 0) {
1432 /* Parse the message body */
1433 (v1_functions
[slp
->function
])(flags
);
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]",
1447 sprintf(get_sum_line(), "%s [OVERFLOW]", msgbuf
);
1449 sprintf(get_sum_line(), "%s [CORRUPTED MESSAGE]", msgbuf
);
1452 else if (msglength
> 0)
1453 sprintf(get_sum_line(), "%s +%d", msgbuf
, msglength
);
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
);
1473 static int v1_header(int flags
,
1474 struct slpv1_hdr
*slp
,
1476 extern int src_port
, dst_port
, curr_proto
;
1477 char *prototag
= (curr_proto
== IPPROTO_TCP
? "/tcp" : "");
1479 if (flags
& F_SUM
) {
1480 char portflag
= ' ';
1482 if (msglength
< sizeof (*slp
)) {
1483 sprintf(msgbuf
, "SLP V1 [incomplete header]");
1487 if (slp
->vers
!= 1) {
1488 if (curr_proto
== IPPROTO_TCP
)
1489 sprintf(msgbuf
, "SLP [TCP Continuation]");
1491 sprintf(msgbuf
, "SLP [unknown version %d]", slp
->vers
);
1495 if (src_port
!= 427 && dst_port
!= 427)
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
);
1504 } else if (flags
& F_DTAIL
) {
1505 show_header("SLP: ", "Service Location Protocol (v1)", fraglen
);
1508 if (msglength
< sizeof (*slp
)) {
1509 sprintf(get_line(0, 0), "==> Incomplete SLP header");
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");
1518 sprintf(get_line(0, 0), "==> Unexpected version number");
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
));
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)",
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",
1557 slpv1_charset(v1_charset
));
1558 sprintf(get_line(0, 0), "XID = %u", ntohs(slp
->xid
));
1560 /* set msglength to remaining length of SLP message */
1561 msglength
-= sizeof (*slp
);
1568 static char *slpv1_func(int t
, boolean_t s
) {
1569 static char buf
[128];
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";
1583 sprintf(buf
, "(func %d)", t
);
1584 return (s
? buf
: "unknown function");
1587 static char *slpv1_error(unsigned short code
) {
1588 static char buf
[128];
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";
1608 sprintf(buf
, "error %d", code
);
1613 * Character set info from
1614 * www.isi.edu/in-notes/iana/assignments/character-sets
1616 * Assigned MIB enum Numbers
1617 * -------------------------
1620 * 3-106 Set By Standards Organizations
1621 * 1000-1010 Unicode / 10646
1626 * Alias: US-ASCII (preferred MIME name)
1627 * Source: ECMA registry [RFC1345]
1634 static char *slpv1_charset(unsigned short code
) {
1636 return ("Reserved");
1638 return ("US-ASCII");
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");
1655 static int skip_v1authblock() {
1656 unsigned short length
;
1658 /* auth header: 12 bytes total */
1662 /* timestamp: 8 bytes */
1663 p
+= 8; /* timestamp: 8 bytes */
1664 p
+= sizeof (short); /* block descriptor: 2 bytes */
1667 p
+= sizeof (short);
1670 if (length
> msglength
) {
1671 /* framing error: message is not long enough to contain data */
1676 msglength
-= length
;
1681 static int slpv1_authblock() {
1682 unsigned short bsd
, length
;
1686 if (msglength
< 12) {
1687 sprintf(get_line(0, 0),
1688 " [no room for auth block: remaining msg length = %u]",
1693 /* timestamp: 8 bytes */
1695 for (n
= 0; n
< 8; n
++, p
+= 1) {
1697 sprintf(tmp
, "%02x", (unsigned char)(*p
));
1698 strcat(msgbuf
, tmp
);
1703 p
+= sizeof (short);
1706 p
+= sizeof (short);
1709 sprintf(get_line(0, 0),
1710 " Auth block: timestamp = %s",
1712 sprintf(get_line(0, 0),
1713 " block desc = 0x%04x, length = %u",
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
);
1723 msglength
-= length
;
1727 static int slpv1_url(boolean_t auth_present
) {
1729 int lifetime
, length
;
1732 if ((lifetime
= netval
) < 0)
1735 if ((length
= netval
) < 0)
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
);
1749 char *buf
= malloc(length
+ 1);
1751 if (!make_utf8(buf
, length
, p
, length
)) {
1752 strcpy(buf
, "[Invalid Character Encoding]");
1754 sprintf(get_line(0, 0), " \"%s\"", buf
);
1758 msglength
-= length
;
1762 return (slpv1_authblock());
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
);
1779 static int v1_srv_rply(int flags
) {
1780 unsigned short errcode
, itemcnt
;
1783 if (flags
& F_SUM
) {
1785 if (errcode
!= OK
) {
1786 strcat(msgbuf
, slpv1_error(errcode
));
1789 sprintf(msgend
, "%d URL entries", itemcnt
);
1791 for (n
= 0; n
< itemcnt
; n
++) {
1792 SKIPSHORT
; /* lifetime */
1793 SKIPFIELD(FIELD_DEFAULT
); /* URL */
1794 SKIPAUTH(url_auth
); /* URL auth */
1798 } else if (flags
& F_DTAIL
) {
1801 sprintf(get_line(0, 0), "URL entry count = %d", itemcnt
);
1802 for (n
= 0; n
< itemcnt
; n
++) {
1810 static int v1_srv_reg(int flags
) {
1811 if (flags
& F_SUM
) {
1812 SKIPSHORT
; /* lifetime */
1815 SKIPAUTH(url_auth
); /* URL auth */
1816 SKIPFIELD(FIELD_DEFAULT
); /* attribute list */
1817 SKIPAUTH(attr_auth
); /* attr auth */
1819 } else if (flags
& F_DTAIL
) {
1821 DOFIELD("Attribute list", FIELD_DEFAULT
);
1828 static int v1_srv_ack(int flags
) {
1829 unsigned short errcode
;
1831 if (flags
& F_SUM
) {
1833 strcat(msgbuf
, slpv1_error(errcode
));
1834 if (errcode
== OK
&& fresh
) {
1835 strcat(msgbuf
, " [Fresh]");
1837 } else if (flags
& F_DTAIL
) {
1844 static int v1_srv_dereg(int flags
) {
1845 if (flags
& F_SUM
) {
1849 SKIPFIELD(FIELD_DEFAULT
); /* tag spec */
1851 } else if (flags
& F_DTAIL
) {
1852 DOFIELD("URL", FIELD_DEFAULT
);
1854 DOFIELD("Tag spec", FIELD_DEFAULT
);
1860 static int v1_attr_rqst(int flags
) {
1861 if (flags
& F_SUM
) {
1862 SKIPFIELD(FIELD_PREVRESP
); /* prev responders */
1865 SKIPFIELD(FIELD_DEFAULT
); /* scope */
1866 SKIPFIELD(FIELD_DEFAULT
); /* select list */
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
);
1878 static int v1_attr_rply(int flags
) {
1879 unsigned short errcode
;
1881 if (flags
& F_SUM
) {
1883 if (errcode
!= OK
) {
1884 strcat(msgbuf
, slpv1_error(errcode
));
1886 GETFIELD
; /* attr list */
1888 SKIPAUTH(attr_auth
);
1891 } else if (flags
& F_DTAIL
) {
1893 DOFIELD("Attribute list", FIELD_DEFAULT
);
1900 static int v1_daadvert(int flags
) {
1901 unsigned short errcode
;
1903 if (flags
& F_SUM
) {
1905 if (errcode
!= OK
) {
1906 strcat(msgbuf
, slpv1_error(errcode
));
1910 SKIPFIELD(FIELD_DEFAULT
); /* scope list */
1913 } else if (flags
& F_DTAIL
) {
1915 DOFIELD("URL", FIELD_DEFAULT
);
1916 DOFIELD("Scope list", FIELD_DEFAULT
);
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
);
1936 static int v1_srv_type_rply(int flags
) {
1937 unsigned short errcode
, itemcnt
;
1940 if (flags
& F_SUM
) {
1942 if (errcode
!= OK
) {
1943 strcat(msgbuf
, slpv1_error(errcode
));
1946 sprintf(msgend
, "%d type entries", itemcnt
);
1948 for (n
= 0; n
< itemcnt
; n
++) {
1949 SKIPFIELD(FIELD_DEFAULT
); /* Service type item */
1953 } else if (flags
& F_DTAIL
) {
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
);