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.
28 #include <arpa/inet.h>
38 /* define VERIFYSLP to enable full message checking in summary mode */
41 /* Globals -- ugly, yes, but fast and easy in macros */
44 static char *msgend
; /* the end of the summary message buffer */
45 static char *p
; /* current position in the packet */
46 static char *msgbuf
; /* message buffer for summary mode */
47 static boolean_t url_auth
= B_FALSE
;
48 static boolean_t attr_auth
= B_FALSE
;
49 static boolean_t fresh
= B_FALSE
;
50 static boolean_t overflow
= B_FALSE
;
51 static int v1_charset
= 0; /* character set; only in V1 */
53 /* Entry points for parsing the protocol */
54 static int interpret_slp_v1(int, struct slpv1_hdr
*, int);
55 static int interpret_slp_v2(int, struct slpv2_hdr
*, int);
58 static int v1_header(int, struct slpv1_hdr
*, int);
59 static int v2_header(int, struct slpv2_hdr
*, int *, int);
60 static int v2_finish(struct slpv2_hdr
*, int);
63 static int slpv2_authblock(int);
66 * Functions for parsing each protocol message
67 * Each function takes the interpreter's flags argument as its input
68 * parameter, and returns 1 on success, or 0 on message corruption.
69 * retlength is set as a side-effect in summary mode.
71 static int v2_srv_rqst(int);
72 static int v2_srv_rply(int);
73 static int v2_srv_reg(int);
74 static int v2_srv_dereg(int);
75 static int v2_srv_ack(int);
76 static int v2_attr_rqst(int);
77 static int v2_attr_rply(int);
78 static int v2_daadvert(int);
79 static int v2_srv_type_rqst(int);
80 static int v2_srv_type_rply(int);
81 static int v2_saadvert(int);
83 static int v1_srv_rqst(int);
84 static int v1_srv_rply(int);
85 static int v1_srv_reg(int);
86 static int v1_srv_dereg(int);
87 static int v1_srv_ack(int);
88 static int v1_attr_rqst(int);
89 static int v1_attr_rply(int);
90 static int v1_daadvert(int);
91 static int v1_srv_type_rqst(int);
92 static int v1_srv_type_rply(int);
95 * The dispatch tables for handling individual messages, keyed by
98 typedef int function_handler();
100 #define V2_MAX_FUNCTION 11
102 static function_handler
*v2_functions
[V2_MAX_FUNCTION
+ 1] = {
103 (function_handler
*) NULL
,
104 (function_handler
*) v2_srv_rqst
,
105 (function_handler
*) v2_srv_rply
,
106 (function_handler
*) v2_srv_reg
,
107 (function_handler
*) v2_srv_dereg
,
108 (function_handler
*) v2_srv_ack
,
109 (function_handler
*) v2_attr_rqst
,
110 (function_handler
*) v2_attr_rply
,
111 (function_handler
*) v2_daadvert
,
112 (function_handler
*) v2_srv_type_rqst
,
113 (function_handler
*) v2_srv_type_rply
,
114 (function_handler
*) v2_saadvert
};
116 #define V1_MAX_FUNCTION 10
118 static function_handler
*v1_functions
[V1_MAX_FUNCTION
+ 1] = {
119 (function_handler
*) NULL
,
120 (function_handler
*) v1_srv_rqst
,
121 (function_handler
*) v1_srv_rply
,
122 (function_handler
*) v1_srv_reg
,
123 (function_handler
*) v1_srv_dereg
,
124 (function_handler
*) v1_srv_ack
,
125 (function_handler
*) v1_attr_rqst
,
126 (function_handler
*) v1_attr_rply
,
127 (function_handler
*) v1_daadvert
,
128 (function_handler
*) v1_srv_type_rqst
,
129 (function_handler
*) v1_srv_type_rply
};
131 /* TCP continuation handling */
132 static boolean_t tcp_continuation
= B_FALSE
;
134 #define MAX_TCPCONT 16
136 static struct tcp_cont
{
141 } *tcp_cont
[MAX_TCPCONT
];
143 static int current_tcp_cont
;
145 static void reg_tcp_cont(char *, int, int, int);
146 static int add_tcp_cont(struct tcp_cont
*, char *, int);
147 static struct tcp_cont
*find_tcp_cont(int);
148 static void remove_tcp_cont(int);
150 /* Conversions from numbers to strings */
151 static char *slpv2_func(int, boolean_t
);
152 static char *slpv2_error(unsigned short);
153 static char *slpv1_func(int, boolean_t
);
154 static char *slpv1_error(unsigned short);
155 static char *slpv1_charset(unsigned short);
158 * The only external entry point to the SLP interpreter. This function
159 * simply dispatches the packet based on the version.
161 void interpret_slp(int flags
, void *slp
, int fraglen
) {
162 extern int dst_port
, curr_proto
;
163 struct tcp_cont
*tce
= NULL
;
170 /* check if this is a TCP continuation */
171 if (flags
& F_DTAIL
&& curr_proto
== IPPROTO_TCP
) {
172 tce
= find_tcp_cont(dst_port
);
174 if (add_tcp_cont(tce
, slp
, fraglen
)) {
176 fraglen
= tce
->curr_offset
;
177 tcp_continuation
= B_TRUE
;
181 if (*(char *)slp
== 2 || tce
)
182 interpret_slp_v2(flags
, slp
, fraglen
);
184 interpret_slp_v1(flags
, slp
, fraglen
);
186 tcp_continuation
= B_FALSE
;
190 * Primitives. These are implemented as much as possible as macros for
194 #define FIELD_DEFAULT 0
195 #define FIELD_PREVRESP 1
196 #define FIELD_TYPENA 2
198 static long long netval
= 0; /* need signed 64 bit quantity */
200 /* gets two bytes from p and leaves the result in netval */
202 netval = ((int)(p[0] & 0xff)) << 8; \
203 netval += ((int)(p[1] & 0xff))
205 /* gets four bytes from p and leaves the result in netval */
207 netval = ((int)(p[0] & 0xff)) << 24; \
208 netval += ((int)(p[1] & 0xff)) << 16; \
209 netval += ((int)(p[2] & 0xff)) << 8; \
210 netval += ((int)(p[3] & 0xff))
213 if (msglength >= 1) { \
222 if ((retlength = netval) < 0) \
228 if ((retlength = netval) < 0) \
232 * gets two bytes from p, leaves the result in netval, and updates
235 #define get_short() \
236 if (msglength >= sizeof (unsigned short)) { \
238 p += sizeof (unsigned short); \
239 msglength -= sizeof (unsigned short); \
243 #define GETSHORT(x) \
245 if ((retlength = netval) < 0) \
251 if ((retlength = netval) < 0) \
254 #define get_int24(pp) \
255 netval = ((int)((pp)[0] & 0xff)) << 16; \
256 netval += ((int)((pp)[1] & 0xff)) << 8; \
257 netval += ((int)((pp)[2] & 0xff))
259 static void slp_prevresp(char *p
) {
262 /* cycle through all entries */
263 for (; p
!= NULL
; p
= p2
) {
268 /* print entry at p */
269 sprintf(get_line(0, 0), " \"%s\"", p
);
273 static int skip_field(int type
) {
274 unsigned short stringlen
;
282 /* special case for NA field in SrvTypeRqst */
283 if (type
== FIELD_TYPENA
&& stringlen
== 0xffff) {
287 if (stringlen
> msglength
) {
291 msglength
-= stringlen
;
297 #define SKIPFIELD(type) \
298 if ((retlength = skip_field(type)) < 0) \
303 if ((retlength = netval) < 0) \
305 strncat(msgbuf, p, (retlength > MAXSUMLEN ? MAXSUMLEN : retlength)); \
307 msglength -= retlength
310 * Determines from the first five bytes of a potential SLP header
311 * if the following message is really an SLP message. Returns 1 if
312 * it is a real SLP message, 0 if not.
314 int valid_slp(unsigned char *slphdr
, int len
) {
315 struct slpv1_hdr slp1
;
316 struct slpv2_hdr slp2
;
318 len
-= (8 /* udp */ + 20 /* IP */ + 14 /* ether */);
319 /* a valid version will be 1 or 2 */
322 memcpy(&slp1
, slphdr
, 5);
323 /* valid function? */
324 if (slp1
.function
> V1_MAX_FUNCTION
) {
327 /* valid length heuristic */
328 if (slp1
.length
> len
) {
333 memcpy(&slp2
, slphdr
, 5);
334 /* valid function? */
335 if (slp2
.function
> V2_MAX_FUNCTION
) {
338 /* valid length heuristic */
339 get_int24(&(slp2
.l1
));
350 * Converts a V1 char encoding to UTF8. If this fails, returns 0,
351 * otherwise, 1. This function is the union of iconv UTF-8
352 * modules and character sets registered with IANA.
354 static int make_utf8(char *outbuf
, size_t outlen
,
355 const char *inbuf
, size_t inlen
) {
359 switch (v1_charset
) {
362 cd
= iconv_open("UTF-8", "8859-1");
365 cd
= iconv_open("UTF-8", "8859-2");
368 cd
= iconv_open("UTF-8", "8859-3");
371 cd
= iconv_open("UTF-8", "8859-4");
374 cd
= iconv_open("UTF-8", "8859-5");
377 cd
= iconv_open("UTF-8", "8859-6");
380 cd
= iconv_open("UTF-8", "8859-7");
383 cd
= iconv_open("UTF-8", "8859-8");
386 cd
= iconv_open("UTF-8", "8859-9");
389 cd
= iconv_open("UTF-8", "8859-10");
392 cd
= iconv_open("UTF-8", "ko_KR-iso2022-7");
395 cd
= iconv_open("UTF-8", "iso2022");
398 cd
= iconv_open("UTF-8", "UCS-2");
401 cd
= iconv_open("UTF-8", "UCS-4");
405 * charset not set, or reserved, or not supported, so
406 * just copy it and hope for the best.
408 converted
= outlen
< inlen
? outlen
: inlen
;
409 memcpy(outbuf
, inbuf
, converted
);
410 outbuf
[converted
] = 0;
414 if (cd
== (iconv_t
)-1) {
418 if ((converted
= iconv(cd
, &inbuf
, &inlen
, &outbuf
, &outlen
))
423 outbuf
[converted
] = 0;
429 static int slp_field(char *tag
, int type
) {
438 /* special case for NA field in SrvTypeRqst */
439 if (type
== FIELD_TYPENA
&& length
== 0xffff) {
440 sprintf(get_line(0, 0), "%s: length = -1: Use all NAs", tag
);
444 sprintf(get_line(0, 0), "%s: length = %d", tag
, length
);
445 if (length
> msglength
) {
446 /* framing error: message is not long enough to contain data */
447 sprintf(get_line(0, 0),
448 " [Framing error: remaining pkt length = %u]",
454 char *buf
= malloc(length
+ 1);
457 if (!make_utf8(buf
, length
, p
, length
)) {
458 strcpy(buf
, "[Invalid Character Encoding]");
461 memcpy(buf
, p
, length
);
462 buf
[length
] = '\0'; /* ensure null-terminated */
471 sprintf(get_line(0, 0), " \"%s\"", buf
);
485 static int slpv2_url(int cnt
) {
487 int lifetime
, length
, n
;
496 if ((lifetime
= netval
) < 0)
501 if ((length
= netval
) < 0)
505 exp
= time(0) + lifetime
;
507 sprintf(get_line(0, 0),
508 "URL: length = %u, lifetime = %d (%24.24s)",
509 length
, lifetime
, ctime(&exp
));
511 /* number the URLs to make it easier to parse them */
512 sprintf(get_line(0, 0),
513 "URL %d: length = %u, lifetime = %d (%24.24s)",
514 cnt
, length
, lifetime
, ctime(&exp
));
516 if (length
> msglength
) {
517 if (!tcp_continuation
)
518 /* framing error: message is not long enough to contain data */
519 sprintf(get_line(0, 0),
520 " [Framing error: remaining pkt length = %u]",
526 char *buf
= malloc(length
+ 1);
528 memcpy(buf
, p
, length
);
529 buf
[length
] = '\0'; /* ensure null-terminated */
530 sprintf(get_line(0, 0), " \"%s\"", buf
);
538 if ((n
= netval
) < 0)
543 sprintf(get_line(0, 0), "%d Authentication Blocks", n
);
544 for (i
= 0; i
< n
; i
++)
545 if ((length
= slpv2_authblock(i
)) < 0)
551 #define DOFIELD(tag, type) \
552 if (slp_field(tag, type) < 0) \
555 #define V2_DOURL(x) \
556 if (slpv2_url(x) < 0) \
559 #define V2_DOERRCODE \
560 if (msglength < sizeof (unsigned short)) \
564 sprintf(get_line(0, 0), "Error code = %d, %s", \
565 errcode, slpv2_error(errcode)); \
566 p += sizeof (unsigned short); \
567 msglength -= sizeof (unsigned short); \
569 msglength = 0; /* skip rest of message */ \
573 #define V2_DOAUTH(cnt) \
574 if (slpv2_authblock(cnt) < 0) \
577 #define V2_DOTIMESTAMP \
581 timestamp = netval; \
582 sprintf(get_line(0, 0), "Timestamp = %u, %s", \
583 timestamp, (timestamp ? convert_ts(timestamp) : "0")); \
588 #define SKIPAUTH(auth) \
589 if (auth && ((retlength = skip_v1authblock()) < 0)) \
593 if (msglength < sizeof (unsigned short)) \
597 sprintf(get_line(0, 0), "Error code = %d, %s", errcode, \
598 slpv1_error(errcode)); \
599 p += sizeof (unsigned short); \
600 msglength -= sizeof (unsigned short); \
605 if (slpv1_url(url_auth) < 0) \
608 #define DOAUTH(auth) \
609 if (auth && slpv1_authblock() < 0) \
613 * TCP Continuation handling
614 * We keep track of continuations in a fixed size cache, so as to prevent
615 * memory leaks if some continuations are never finished. The continuations
616 * are indexed by their destination ports.
618 static void reg_tcp_cont(char *msg
, int totallen
,
619 int fraglen
, int dst_port
) {
620 struct tcp_cont
*tce
= malloc(sizeof (*tce
));
622 /* always overwrite the entry at current_tcp_cont */
623 if (tcp_cont
[current_tcp_cont
]) {
624 free(tcp_cont
[current_tcp_cont
]->msg
);
625 free(tcp_cont
[current_tcp_cont
]);
628 tce
->dst_port
= dst_port
;
629 tce
->msg
= malloc(totallen
);
630 memcpy(tce
->msg
, msg
, fraglen
);
631 tce
->totallen
= totallen
;
632 tce
->curr_offset
= fraglen
;
634 tcp_cont
[current_tcp_cont
++] = tce
;
635 if (current_tcp_cont
== MAX_TCPCONT
)
636 current_tcp_cont
= 0;
639 /* returns 0 if there is a mismatch error, 1 on success */
640 static int add_tcp_cont(struct tcp_cont
*tce
, char *msg
, int fraglen
) {
641 if ((fraglen
+ tce
->curr_offset
) > tce
->totallen
)
644 memcpy(tce
->msg
+ tce
->curr_offset
, msg
, fraglen
);
645 tce
->curr_offset
+= fraglen
;
649 static struct tcp_cont
*find_tcp_cont(int dst_port
) {
651 for (i
= current_tcp_cont
; i
>= 0; i
--)
652 if (tcp_cont
[i
] && tcp_cont
[i
]->dst_port
== dst_port
)
653 return (tcp_cont
[i
]);
655 for (i
= MAX_TCPCONT
-1; i
> current_tcp_cont
; i
--)
656 if (tcp_cont
[i
] && tcp_cont
[i
]->dst_port
== dst_port
)
657 return (tcp_cont
[i
]);
662 static void remove_tcp_cont(int dst_port
) {
664 for (i
= current_tcp_cont
; i
>= 0; i
--)
665 if (tcp_cont
[i
] && tcp_cont
[i
]->dst_port
== dst_port
) {
666 free(tcp_cont
[i
]->msg
);
672 for (i
= MAX_TCPCONT
-1; i
> current_tcp_cont
; i
--)
673 if (tcp_cont
[i
] && tcp_cont
[i
]->dst_port
== dst_port
) {
674 free(tcp_cont
[i
]->msg
);
685 static int interpret_slp_v2(int flags
, struct slpv2_hdr
*slp
, int fraglen
) {
686 extern int src_port
, dst_port
, curr_proto
;
687 char msgbuf_real
[256];
690 msgbuf
= msgbuf_real
;
693 * Somewhat of a hack to decode traffic from a server that does
694 * not send udp replies from its SLP src port.
697 if (curr_proto
== IPPROTO_UDP
&&
700 add_transient(src_port
, (int (*)())interpret_slp
);
703 /* parse the header */
704 if (v2_header(flags
, slp
, &totallen
, fraglen
)) {
706 if (slp
->function
<= V2_MAX_FUNCTION
&& slp
->function
> 0) {
708 /* Parse the message body */
709 if ((v2_functions
[slp
->function
])(flags
)) {
711 /* finish any remaining tasks */
712 v2_finish(slp
, flags
);
720 /* summary error check */
723 if (curr_proto
== IPPROTO_TCP
)
724 sprintf(get_sum_line(),
725 "%s [partial TCP message]", msgbuf
);
727 sprintf(get_sum_line(), "%s [OVERFLOW]", msgbuf
);
729 sprintf(get_sum_line(), "%s [CORRUPTED MESSAGE]", msgbuf
);
732 else if (msglength
> 0)
733 sprintf(get_sum_line(), "%s +%d", msgbuf
, msglength
);
736 sprintf(get_sum_line(), "%s", msgbuf
);
737 } else if (flags
& F_DTAIL
) {
738 /* detailed error check */
740 if (tcp_continuation
) {
741 sprintf(get_line(0, 0),
742 "[TCP Continuation, %d bytes remaining]",
745 sprintf(get_line(0, 0),
746 "[%d extra bytes at end of SLP message]", msglength
);
751 if (tcp_continuation
&& msglength
== 0)
752 remove_tcp_cont(dst_port
);
758 static int v2_header(int flags
,
759 struct slpv2_hdr
*slp
,
762 extern int curr_proto
, dst_port
;
763 char *prototag
= (curr_proto
== IPPROTO_TCP
? "/tcp" : "");
765 if ((slp
->flags
& V2_OVERFLOW
) == V2_OVERFLOW
)
768 /* summary mode header parsing */
771 /* make sure we have at least a header */
772 if (msglength
< sizeof (*slp
)) {
773 sprintf(get_sum_line(), "SLP V2 [Incomplete Header]");
777 sprintf(msgbuf
, "SLP V2 %s [%d%s] ",
778 slpv2_func(slp
->function
, B_TRUE
),
779 ntohs(slp
->xid
), prototag
);
781 /* skip to end of header */
782 msgend
= msgbuf
+ strlen(msgbuf
);
783 msglength
-= sizeof (*slp
);
786 /* skip language tag */
787 SKIPFIELD(FIELD_DEFAULT
);
788 } else if (flags
& F_DTAIL
) {
792 /* detailed mode header parsing */
793 show_header("SLP: ", "Service Location Protocol (v2)", fraglen
);
796 if (msglength
< sizeof (*slp
)) {
797 sprintf(get_line(0, 0), "==> Incomplete SLP header");
801 sprintf(get_line(0, 0), "Version = %d", slp
->vers
);
802 sprintf(get_line(0, 0), "Function = %d, %s",
803 slp
->function
, slpv2_func(slp
->function
, B_FALSE
));
804 get_int24(&(slp
->l1
));
806 sprintf(get_line(0, 0), "Message length = %u", *totallen
);
807 /* check for TCP continuation */
808 if (curr_proto
== IPPROTO_TCP
&&
809 *totallen
> msglength
&&
811 tcp_continuation
= B_TRUE
;
812 reg_tcp_cont((char *)slp
, *totallen
, msglength
, dst_port
);
815 if (!tcp_continuation
&& *totallen
!= msglength
) {
816 sprintf(get_line(0, 0),
817 " (Stated and on-the-wire lengths differ)");
820 sprintf(get_line(0, 0), "Flags = 0x%02x", slp
->flags
);
821 sprintf(get_line(0, 0), " %s",
822 getflag(slp
->flags
, V2_OVERFLOW
,
823 "overflow", "no overflow"));
824 sprintf(get_line(0, 0), " %s",
825 getflag(slp
->flags
, V2_FRESH
,
826 "fresh registration", "no fresh registration"));
827 sprintf(get_line(0, 0), " %s",
828 getflag(slp
->flags
, V2_MCAST
,
829 "request multicast / broadcast", "unicast"));
830 /* check reserved flags that must be zero */
831 if ((slp
->flags
& 7) != 0) {
832 sprintf(get_line(0, 0),
833 " .... .xxx = %d (reserved flags nonzero)",
839 p
= (char *)slp
+ sizeof (*slp
);
840 msglength
-= sizeof (*slp
);
842 if (len
> msglength
) {
843 sprintf(get_line(0, 0),
844 "Language Tag Length = %u [CORRUPT MESSAGE]",
849 lang
= get_line(0, 0);
850 strcpy(lang
, "Language Tag = ");
851 strncat(lang
, p
, len
);
852 sprintf(get_line(0, 0), "XID = %u", ntohs(slp
->xid
));
854 /* set msglength to remaining length of SLP message */
862 static int v2_finish(struct slpv2_hdr
*slp
, int flags
) {
863 unsigned int firstop
;
865 if (!(flags
& F_DTAIL
))
868 /* check for options */
869 get_int24(&(slp
->o1
));
873 unsigned short op_id
;
874 unsigned short nextop
;
878 unsigned short real_oplen
;
881 sprintf(get_line(0, 0),
882 "Option expected but not present");
888 p
+= sizeof (unsigned short);
889 msglength
-= sizeof (unsigned short);
892 p
+= sizeof (unsigned short);
893 msglength
-= sizeof (unsigned short);
895 real_oplen
= nextop
? nextop
: msglength
;
900 sprintf(get_line(0, 0),
901 "Option: Required Attribute Missing");
902 DOFIELD("Template IDVer", FIELD_DEFAULT
);
903 DOFIELD("Required Attrs", FIELD_DEFAULT
);
906 sprintf(get_line(0, 0), "Option: Unknown");
907 p
+= (real_oplen
- 4);
908 msglength
-= (real_oplen
- 4);
913 op_class
= "Standardized, optional";
914 else if (op_id
< 0x7fff)
915 op_class
= "Standardized, mandatory";
916 else if (op_id
< 0x8fff)
917 op_class
= "Not standardized, private";
918 else if (op_id
< 0xffff)
919 op_class
= "Reserved";
920 sprintf(get_line(0, 0), "Option ID = 0x%04x, %s",
923 ((nextop
- 4) > msglength
) &&
925 sprintf(get_line(0, 0),
926 "[Framing error: remaining pkt length = %u]",
931 sprintf(get_line(0, 0), "Option Length = %u", real_oplen
);
942 static int skip_v2authblock() {
943 unsigned short length
, slen
;
949 /* block descriptor: 2 bytes */
950 p
+= sizeof (unsigned short);
954 p
+= sizeof (unsigned short);
957 /* SPI String length */
960 p
+= sizeof (unsigned short);
963 if (slen
> msglength
|| length
> (msglength
+ 10))
969 /* structured auth block */
970 p
+= (length
- 10 - slen
);
971 msglength
-= (length
- 10 - slen
);
976 static char *display_bsd(unsigned short bsd
) {
978 case 1: return ("MD5 with RSA");
979 case 2: return ("DSA with SHA-1");
980 case 3: return ("Keyed HMAC with MD5");
981 default: return ("Unknown BSD");
985 static char *slpv2_func(int t
, boolean_t s
) {
986 static char buf
[128];
989 case V2_SRVRQST
: return s
? "SrvRqst" : "Service Request";
990 case V2_SRVRPLY
: return s
? "SrvRply" : "Service Reply";
991 case V2_SRVREG
: return s
? "SrvReg" : "Service Registration";
993 return (s
? "SrvDereg" : "Service Deregistration");
994 case V2_SRVACK
: return s
? "SrvAck" : "Service Acknowledge";
995 case V2_ATTRRQST
: return s
? "AttrRqst" : "Attribute Request";
996 case V2_ATTRRPLY
: return s
? "AttrRply" : "Attribute Reply";
997 case V2_DAADVERT
: return s
? "DAAdvert" : "DA advertisement";
999 return (s
? "SrvTypeRqst" : "Service Type Request");
1000 case V2_SRVTYPERPLY
:
1001 return (s
? "SrvTypeRply" : "Service Type Reply");
1002 case V2_SAADVERT
: return s
? "SAAdvert" : "SA advertisement";
1004 sprintf(buf
, "(func %d)", t
);
1005 return (s
? buf
: "unknown function");
1008 static char *slpv2_error(unsigned short code
) {
1009 static char buf
[128];
1012 case OK
: return "ok";
1013 case LANG_NOT_SUPPORTED
: return "language not supported";
1014 case PROTOCOL_PARSE_ERR
: return "protocol parse error";
1015 case INVALID_REGISTRATION
: return "invalid registration";
1016 case SCOPE_NOT_SUPPORTED
: return "scope not supported";
1017 case AUTHENTICATION_UNKNOWN
: return "authentication unknown";
1018 case V2_AUTHENTICATION_ABSENT
: return "authentication absent";
1019 case V2_AUTHENTICATION_FAILED
: return "authentication failed";
1020 case V2_VER_NOT_SUPPORTED
: return "version not supported";
1021 case V2_INTERNAL_ERROR
: return "internal error";
1022 case V2_DA_BUSY_NOW
: return "DA busy";
1023 case V2_OPTION_NOT_UNDERSTOOD
: return "option not understood";
1024 case V2_INVALID_UPDATE
: return "invalid update";
1025 case V2_RQST_NOT_SUPPORTED
: return "request not supported";
1026 case INVALID_LIFETIME
: return "invalid lifetime";
1028 sprintf(buf
, "error %d", code
);
1032 static char *convert_ts(unsigned int timestamp
) {
1033 /* timestamp is in UNIX time */
1034 static char buff
[128];
1036 strcpy(buff
, ctime((time_t *)×tamp
));
1037 buff
[strlen(buff
) - 1] = '\0';
1041 static int slpv2_authblock(int cnt
) {
1042 unsigned short bsd
, length
, slen
;
1044 unsigned int timestamp
;
1046 if (msglength
< 10) {
1047 sprintf(get_line(0, 0),
1048 " [no room for auth block header: remaining msg length = %u]",
1056 p
+= sizeof (unsigned short);
1061 p
+= sizeof (unsigned short);
1068 /* SPI String length */
1071 p
+= sizeof (unsigned short);
1074 if (slen
> msglength
) {
1075 sprintf(get_line(0, 0),
1076 " [no room for auth block scopes: remaining msg length = %u]",
1081 if (length
> (msglength
+ 10)) {
1082 if (!tcp_continuation
)
1083 /* framing error: message is not long enough to contain data */
1084 sprintf(get_line(0, 0),
1085 " [Framing error: remaining pkt length = %u]",
1094 sprintf(get_line(0, 0),
1095 "Auth block %d: timestamp = %s", cnt
,
1096 (timestamp
) ? convert_ts(timestamp
) : "0");
1098 pp
= get_line(0, 0);
1099 strcpy(pp
, " SPI = ");
1100 strncat(pp
, scopes
, slen
);
1102 sprintf(get_line(0, 0),
1103 " block desc = 0x%04x: %s", bsd
, display_bsd(bsd
));
1105 sprintf(get_line(0, 0), " length = %u", length
);
1107 p
+= (length
- 10 - slen
);
1108 msglength
-= (length
- 10 - slen
);
1112 static int v2_srv_rqst(int flags
) {
1113 if (flags
& F_SUM
) {
1114 SKIPFIELD(FIELD_DEFAULT
); /* PR list */
1115 GETFIELD
; /* service type */
1116 SKIPFIELD(FIELD_DEFAULT
); /* scopes */
1117 strcat(msgend
, " [");
1118 GETFIELD
; /* predicate */
1119 strcat(msgend
, "]");
1120 SKIPFIELD(FIELD_DEFAULT
); /* SPI */
1121 } else if (flags
& F_DTAIL
) {
1122 DOFIELD("Previous responders", FIELD_DEFAULT
);
1123 DOFIELD("Service type", FIELD_DEFAULT
);
1124 DOFIELD("Scopes", FIELD_DEFAULT
);
1125 DOFIELD("Predicate string", FIELD_DEFAULT
);
1126 DOFIELD("Requested SPI", FIELD_DEFAULT
);
1132 static int v2_srv_rply(int flags
) {
1133 unsigned short itemcnt
, errcode
;
1136 if (flags
& F_SUM
) {
1140 if (errcode
!= OK
) {
1141 strcat(msgbuf
, slpv2_error(errcode
));
1142 msglength
= 0; /* skip rest of message */
1146 sprintf(msgend
, "%d URL entries", itemcnt
);
1148 for (n
= 0; n
< itemcnt
; n
++) {
1149 SKIPBYTE
; /* reserved */
1150 SKIPSHORT
; /* lifetime */
1151 SKIPFIELD(FIELD_DEFAULT
); /* URL */
1153 for (i
= 0; i
< auth_cnt
; auth_cnt
++)
1154 if (skip_v2authblock() < 0)
1159 } else if (flags
& F_DTAIL
) {
1162 sprintf(get_line(0, 0), "URL entry count = %d", itemcnt
);
1163 for (n
= 0; n
< itemcnt
; n
++) {
1171 static int v2_srv_reg(int flags
) {
1174 if (flags
& F_SUM
) {
1175 SKIPBYTE
; /* reserved */
1176 SKIPSHORT
; /* lifetime */
1180 for (i
= 0; i
< auth_cnt
; i
++)
1181 if (skip_v2authblock() < 0)
1183 SKIPFIELD(FIELD_DEFAULT
); /* type */
1184 SKIPFIELD(FIELD_DEFAULT
); /* scopes */
1185 SKIPFIELD(FIELD_DEFAULT
); /* attrs */
1187 for (i
= 0; i
< auth_cnt
; i
++)
1188 if (skip_v2authblock() < 0)
1191 } if (flags
& F_DTAIL
) {
1193 DOFIELD("Service type", FIELD_DEFAULT
);
1194 DOFIELD("Scopes", FIELD_DEFAULT
);
1195 DOFIELD("Attribute list", FIELD_DEFAULT
);
1198 for (i
= 0; i
< auth_cnt
; i
++)
1205 static int v2_srv_dereg(int flags
) {
1206 if (flags
& F_SUM
) {
1209 SKIPFIELD(FIELD_DEFAULT
); /* scopes */
1210 SKIPBYTE
; /* reserved */
1211 SKIPSHORT
; /* lifetime */
1216 for (i
= 0; i
< auth_cnt
; i
++)
1217 if (skip_v2authblock() < 0)
1219 SKIPFIELD(FIELD_DEFAULT
); /* attrs */
1221 } else if (flags
& F_DTAIL
) {
1222 DOFIELD("Scopes", FIELD_DEFAULT
);
1224 DOFIELD("Tag list", FIELD_DEFAULT
);
1230 static int v2_srv_ack(int flags
) {
1231 unsigned short errcode
;
1232 if (flags
& F_SUM
) {
1234 strcat(msgbuf
, slpv2_error(errcode
));
1235 } else if (flags
& F_DTAIL
) {
1242 static int v2_attr_rqst(int flags
) {
1243 if (flags
& F_SUM
) {
1244 SKIPFIELD(FIELD_DEFAULT
); /* PR list */
1246 SKIPFIELD(FIELD_DEFAULT
); /* scopes */
1247 strcat(msgend
, " [");
1248 GETFIELD
; /* attrs */
1249 strcat(msgend
, "]");
1252 SKIPFIELD(FIELD_DEFAULT
); /* SPI */
1254 } else if (flags
& F_DTAIL
) {
1255 DOFIELD("Previous responders", FIELD_DEFAULT
);
1256 DOFIELD("URL", FIELD_DEFAULT
);
1257 DOFIELD("Scopes", FIELD_DEFAULT
);
1258 DOFIELD("Tag list", FIELD_DEFAULT
);
1259 DOFIELD("Requested SPI", FIELD_DEFAULT
);
1265 static int v2_attr_rply(int flags
) {
1267 unsigned short errcode
;
1269 if (flags
& F_SUM
) {
1271 if (errcode
!= OK
) {
1272 strcat(msgbuf
, slpv2_error(errcode
));
1273 msglength
= 0; /* skip rest of message */
1276 GETFIELD
; /* attr list */
1280 for (i
= 0; i
< auth_cnt
; i
++)
1281 if (skip_v2authblock() < 0)
1285 } else if (flags
& F_DTAIL
) {
1287 DOFIELD("Attribute list", FIELD_DEFAULT
);
1290 for (i
= 0; i
< auth_cnt
; i
++)
1297 static int v2_daadvert(int flags
) {
1299 unsigned short errcode
;
1300 unsigned int timestamp
;
1302 if (flags
& F_SUM
) {
1303 SKIPSHORT
; /* error code */
1304 SKIPSHORT
; SKIPSHORT
; /* timestamp */
1308 SKIPFIELD(FIELD_DEFAULT
); /* scopes */
1309 SKIPFIELD(FIELD_DEFAULT
); /* attrs */
1310 SKIPFIELD(FIELD_DEFAULT
); /* SPIs */
1313 for (i
= 0; i
< auth_cnt
; i
++)
1314 if (skip_v2authblock() < 0)
1317 } else if (flags
& F_DTAIL
) {
1320 DOFIELD("URL", FIELD_DEFAULT
);
1321 DOFIELD("Scope list", FIELD_DEFAULT
);
1322 DOFIELD("Attribute list", FIELD_DEFAULT
);
1323 DOFIELD("Configured SPIs", FIELD_DEFAULT
);
1326 for (i
= 0; i
< auth_cnt
; i
++)
1333 static int v2_srv_type_rqst(int flags
) {
1334 if (flags
& F_SUM
) {
1335 SKIPFIELD(FIELD_DEFAULT
); /* prev responders */
1336 SKIPFIELD(FIELD_TYPENA
); /* naming authority */
1337 GETFIELD
; /* scope */
1338 } else if (flags
& F_DTAIL
) {
1339 DOFIELD("Previous responders", FIELD_DEFAULT
);
1340 DOFIELD("Naming authority", FIELD_TYPENA
);
1341 DOFIELD("Scopes", FIELD_DEFAULT
);
1347 static int v2_srv_type_rply(int flags
) {
1348 unsigned short errcode
;
1350 if (flags
& F_SUM
) {
1353 strcat(msgbuf
, slpv2_error(errcode
));
1356 } else if (flags
& F_DTAIL
) {
1358 DOFIELD("Service types", FIELD_DEFAULT
);
1364 static int v2_saadvert(int flags
) {
1367 if (flags
& F_SUM
) {
1371 SKIPFIELD(FIELD_DEFAULT
); /* scopes */
1372 SKIPFIELD(FIELD_DEFAULT
); /* attrs */
1375 for (i
= 0; i
< auth_cnt
; i
++)
1376 if (skip_v2authblock() < 0)
1379 } else if (flags
& F_DTAIL
) {
1380 DOFIELD("URL", FIELD_DEFAULT
);
1381 DOFIELD("Scopes", FIELD_DEFAULT
);
1382 DOFIELD("Attribute list", FIELD_DEFAULT
);
1385 for (i
= 0; i
< auth_cnt
; i
++)
1396 static int interpret_slp_v1(int flags
, struct slpv1_hdr
*slp
, int fraglen
) {
1397 char msgbuf_real
[256];
1398 extern int src_port
, dst_port
, curr_proto
;
1399 boolean_t overflow
= B_FALSE
;
1401 msgbuf
= msgbuf_real
;
1403 if (msglength
>= sizeof (*slp
)) {
1404 if ((slp
->flags
& V1_URL_AUTH
) == V1_URL_AUTH
)
1406 if ((slp
->flags
& V1_ATTR_AUTH
) == V1_ATTR_AUTH
)
1408 if ((slp
->flags
& V1_FRESH_REG
) == V1_FRESH_REG
)
1410 if ((slp
->flags
& V1_OVERFLOW
) == V1_OVERFLOW
)
1415 * Somewhat of a hack to decode traffic from a server that does
1416 * not send udp replies from its SLP src port.
1418 if (curr_proto
== IPPROTO_UDP
&&
1421 add_transient(src_port
, (int (*)())interpret_slp
);
1423 /* parse the header */
1424 if (v1_header(flags
, slp
, fraglen
)) {
1426 if (slp
->function
<= V1_MAX_FUNCTION
&& slp
->function
> 0) {
1428 /* Parse the message body */
1429 (v1_functions
[slp
->function
])(flags
);
1435 /* summary error check */
1436 if (flags
& F_SUM
) {
1437 if (retlength
< 0) {
1438 if (curr_proto
== IPPROTO_TCP
)
1439 sprintf(get_sum_line(),
1440 "%s [partial TCP message]",
1443 sprintf(get_sum_line(), "%s [OVERFLOW]", msgbuf
);
1445 sprintf(get_sum_line(), "%s [CORRUPTED MESSAGE]", msgbuf
);
1448 else if (msglength
> 0)
1449 sprintf(get_sum_line(), "%s +%d", msgbuf
, msglength
);
1452 sprintf(get_sum_line(), "%s", msgbuf
);
1453 } else if (flags
& F_DTAIL
) {
1454 /* detail error check */
1455 if (msglength
> 0) {
1456 sprintf(get_line(0, 0),
1457 "[%d extra bytes at end of SLP message]", msglength
);
1469 static int v1_header(int flags
,
1470 struct slpv1_hdr
*slp
,
1472 extern int src_port
, dst_port
, curr_proto
;
1473 char *prototag
= (curr_proto
== IPPROTO_TCP
? "/tcp" : "");
1475 if (flags
& F_SUM
) {
1476 char portflag
= ' ';
1478 if (msglength
< sizeof (*slp
)) {
1479 sprintf(msgbuf
, "SLP V1 [incomplete header]");
1483 if (slp
->vers
!= 1) {
1484 if (curr_proto
== IPPROTO_TCP
)
1485 sprintf(msgbuf
, "SLP [TCP Continuation]");
1487 sprintf(msgbuf
, "SLP [unknown version %d]", slp
->vers
);
1491 if (src_port
!= 427 && dst_port
!= 427)
1494 sprintf(msgbuf
, "SLP V1%c%s [%d%s] ", portflag
,
1495 slpv1_func(slp
->function
, B_TRUE
),
1496 ntohs(slp
->xid
), prototag
);
1497 msgend
= msgbuf
+ strlen(msgbuf
);
1498 msglength
-= sizeof (*slp
);
1500 } else if (flags
& F_DTAIL
) {
1501 show_header("SLP: ", "Service Location Protocol (v1)", fraglen
);
1504 if (msglength
< sizeof (*slp
)) {
1505 sprintf(get_line(0, 0), "==> Incomplete SLP header");
1509 sprintf(get_line(0, 0), "Version = %d", slp
->vers
);
1510 if (slp
->vers
!= 1) {
1511 if (curr_proto
== IPPROTO_TCP
)
1512 sprintf(get_line(0, 0), "==> TCP continuation");
1514 sprintf(get_line(0, 0), "==> Unexpected version number");
1517 sprintf(get_line(0, 0), "Function = %d, %s",
1518 slp
->function
, slpv1_func(slp
->function
, B_FALSE
));
1519 sprintf(get_line(0, 0), "Message length = %u", ntohs(slp
->length
));
1522 sprintf(get_line(0, 0), "Flags = 0x%02x", slp
->flags
);
1523 sprintf(get_line(0, 0), " %s",
1524 getflag(slp
->flags
, V1_OVERFLOW
,
1525 "overflow", "no overflow"));
1526 sprintf(get_line(0, 0), " %s",
1527 getflag(slp
->flags
, V1_MONOLINGUAL
,
1528 "monolingual", "not monolingual"));
1529 sprintf(get_line(0, 0), " %s",
1530 getflag(slp
->flags
, V1_URL_AUTH
,
1531 "url authentication", "no url authentication"));
1532 sprintf(get_line(0, 0), " %s",
1533 getflag(slp
->flags
, V1_ATTR_AUTH
,
1534 "attribute authentication", "no attribute authentication"));
1535 sprintf(get_line(0, 0), " %s",
1536 getflag(slp
->flags
, V1_FRESH_REG
,
1537 "fresh registration", "no fresh registration"));
1538 /* check reserved flags that must be zero */
1539 if ((slp
->flags
& 7) != 0) {
1540 sprintf(get_line(0, 0),
1541 " .... .xxx = %d (reserved flags nonzero)",
1546 sprintf(get_line(0, 0), "Dialect = %u", slp
->dialect
);
1547 sprintf(get_line(0, 0), "Language = 0x%02x%02x, %c%c",
1548 slp
->language
[0], slp
->language
[1],
1549 slp
->language
[0], slp
->language
[1]);
1550 v1_charset
= ntohs(slp
->charset
);
1551 sprintf(get_line(0, 0), "Character encoding = %u, %s",
1553 slpv1_charset(v1_charset
));
1554 sprintf(get_line(0, 0), "XID = %u", ntohs(slp
->xid
));
1556 /* set msglength to remaining length of SLP message */
1557 msglength
-= sizeof (*slp
);
1564 static char *slpv1_func(int t
, boolean_t s
) {
1565 static char buf
[128];
1567 case V1_SRVREQ
: return s
? "SrvRqst" : "Service Request";
1568 case V1_SRVRPLY
: return s
? "SrvRply" : "Service Reply";
1569 case V1_SRVREG
: return s
? "SrvReg" : "Service Registration";
1570 case V1_SRVDEREG
: return s
?
1571 "SrvDereg" : "Service Deregistration";
1572 case V1_SRVACK
: return s
? "SrvAck" : "Service Acknowledge";
1573 case V1_ATTRRQST
: return s
? "AttrRqst" : "Attribute Request";
1574 case V1_ATTRRPLY
: return s
? "AttrRply" : "Attribute Reply";
1575 case V1_DAADVERT
: return s
? "DAAdvert" : "DA advertisement";
1576 case V1_SRVTYPERQST
:return s
? "SrvTypeRqst" : "Service Type Request";
1577 case V1_SRVTYPERPLY
:return s
? "SrvTypeRply" : "Service Type Reply";
1579 sprintf(buf
, "(func %d)", t
);
1580 return (s
? buf
: "unknown function");
1583 static char *slpv1_error(unsigned short code
) {
1584 static char buf
[128];
1587 case OK
: return "ok";
1588 case LANG_NOT_SUPPORTED
: return "language not supported";
1589 case PROTOCOL_PARSE_ERR
: return "protocol parse error";
1590 case INVALID_REGISTRATION
: return "invalid registration";
1591 case SCOPE_NOT_SUPPORTED
: return "scope not supported";
1592 case CHARSET_NOT_UNDERSTOOD
:return "character set not understood";
1593 case AUTHENTICATION_INVALID
:return "invalid authentication";
1594 case NOT_SUPPORTED_YET
: return "not yet supported";
1595 case REQUEST_TIMED_OUT
: return "request timed out";
1596 case COULD_NOT_INIT_NET_RESOURCES
:
1597 return ("could not initialize net resources");
1598 case COULD_NOT_ALLOCATE_MEMORY
:
1599 return ("could not allocate memory");
1600 case PARAMETER_BAD
: return "bad parameter";
1601 case INTERNAL_NET_ERROR
: return "internal network error";
1602 case INTERNAL_SYSTEM_ERROR
: return "internal system error";
1604 sprintf(buf
, "error %d", code
);
1609 * Character set info from
1610 * www.isi.edu/in-notes/iana/assignments/character-sets
1612 * Assigned MIB enum Numbers
1613 * -------------------------
1616 * 3-106 Set By Standards Organizations
1617 * 1000-1010 Unicode / 10646
1622 * Alias: US-ASCII (preferred MIME name)
1623 * Source: ECMA registry [RFC1345]
1630 static char *slpv1_charset(unsigned short code
) {
1632 return ("Reserved");
1634 return ("US-ASCII");
1639 if (code
>= 3 && code
<= 106)
1640 return ("set by standards organization");
1641 if (code
>= 1000 && code
<= 1010)
1642 return ("Unicode variant");
1643 if ((code
>= 2000 && code
<= 2087) ||
1644 (code
>= 2250 && code
<= 2258))
1645 return ("Vendor assigned");
1651 static int skip_v1authblock() {
1652 unsigned short length
;
1654 /* auth header: 12 bytes total */
1658 /* timestamp: 8 bytes */
1659 p
+= 8; /* timestamp: 8 bytes */
1660 p
+= sizeof (short); /* block descriptor: 2 bytes */
1663 p
+= sizeof (short);
1666 if (length
> msglength
) {
1667 /* framing error: message is not long enough to contain data */
1672 msglength
-= length
;
1677 static int slpv1_authblock() {
1678 unsigned short bsd
, length
;
1682 if (msglength
< 12) {
1683 sprintf(get_line(0, 0),
1684 " [no room for auth block: remaining msg length = %u]",
1689 /* timestamp: 8 bytes */
1691 for (n
= 0; n
< 8; n
++, p
+= 1) {
1693 sprintf(tmp
, "%02x", (unsigned char)(*p
));
1694 strcat(msgbuf
, tmp
);
1699 p
+= sizeof (short);
1702 p
+= sizeof (short);
1705 sprintf(get_line(0, 0),
1706 " Auth block: timestamp = %s",
1708 sprintf(get_line(0, 0),
1709 " block desc = 0x%04x, length = %u",
1711 if (length
> msglength
) {
1712 /* framing error: message is not long enough to contain data */
1713 sprintf(get_line(0, 0),
1714 " [Framing error: remaining pkt length = %u]", msglength
);
1719 msglength
-= length
;
1723 static int slpv1_url(boolean_t auth_present
) {
1725 int lifetime
, length
;
1728 if ((lifetime
= netval
) < 0)
1731 if ((length
= netval
) < 0)
1734 exp
= time(0) + lifetime
;
1735 sprintf(get_line(0, 0), "URL: length = %u, lifetime = %d (%24.24s)",
1736 length
, lifetime
, ctime(&exp
));
1737 if (length
> msglength
) {
1738 /* framing error: message is not long enough to contain data */
1739 sprintf(get_line(0, 0),
1740 " [Framing error: remaining pkt length = %u]", msglength
);
1745 char *buf
= malloc(length
+ 1);
1747 if (!make_utf8(buf
, length
, p
, length
)) {
1748 strcpy(buf
, "[Invalid Character Encoding]");
1750 sprintf(get_line(0, 0), " \"%s\"", buf
);
1754 msglength
-= length
;
1758 return (slpv1_authblock());
1763 static int v1_srv_rqst(int flags
) {
1764 if (flags
& F_SUM
) {
1765 SKIPFIELD(FIELD_PREVRESP
); /* prev responders */
1766 GETFIELD
; /* predicate */
1767 } else if (flags
& F_DTAIL
) {
1768 DOFIELD("Previous responders", FIELD_PREVRESP
);
1769 DOFIELD("predicate string", FIELD_DEFAULT
);
1775 static int v1_srv_rply(int flags
) {
1776 unsigned short errcode
, itemcnt
;
1779 if (flags
& F_SUM
) {
1781 if (errcode
!= OK
) {
1782 strcat(msgbuf
, slpv1_error(errcode
));
1785 sprintf(msgend
, "%d URL entries", itemcnt
);
1787 for (n
= 0; n
< itemcnt
; n
++) {
1788 SKIPSHORT
; /* lifetime */
1789 SKIPFIELD(FIELD_DEFAULT
); /* URL */
1790 SKIPAUTH(url_auth
); /* URL auth */
1794 } else if (flags
& F_DTAIL
) {
1797 sprintf(get_line(0, 0), "URL entry count = %d", itemcnt
);
1798 for (n
= 0; n
< itemcnt
; n
++) {
1806 static int v1_srv_reg(int flags
) {
1807 if (flags
& F_SUM
) {
1808 SKIPSHORT
; /* lifetime */
1811 SKIPAUTH(url_auth
); /* URL auth */
1812 SKIPFIELD(FIELD_DEFAULT
); /* attribute list */
1813 SKIPAUTH(attr_auth
); /* attr auth */
1815 } else if (flags
& F_DTAIL
) {
1817 DOFIELD("Attribute list", FIELD_DEFAULT
);
1824 static int v1_srv_ack(int flags
) {
1825 unsigned short errcode
;
1827 if (flags
& F_SUM
) {
1829 strcat(msgbuf
, slpv1_error(errcode
));
1830 if (errcode
== OK
&& fresh
) {
1831 strcat(msgbuf
, " [Fresh]");
1833 } else if (flags
& F_DTAIL
) {
1840 static int v1_srv_dereg(int flags
) {
1841 if (flags
& F_SUM
) {
1845 SKIPFIELD(FIELD_DEFAULT
); /* tag spec */
1847 } else if (flags
& F_DTAIL
) {
1848 DOFIELD("URL", FIELD_DEFAULT
);
1850 DOFIELD("Tag spec", FIELD_DEFAULT
);
1856 static int v1_attr_rqst(int flags
) {
1857 if (flags
& F_SUM
) {
1858 SKIPFIELD(FIELD_PREVRESP
); /* prev responders */
1861 SKIPFIELD(FIELD_DEFAULT
); /* scope */
1862 SKIPFIELD(FIELD_DEFAULT
); /* select list */
1864 } else if (flags
& F_DTAIL
) {
1865 DOFIELD("Previous responders", FIELD_PREVRESP
);
1866 DOFIELD("URL", FIELD_DEFAULT
);
1867 DOFIELD("Scope", FIELD_DEFAULT
);
1868 DOFIELD("Select list", FIELD_DEFAULT
);
1874 static int v1_attr_rply(int flags
) {
1875 unsigned short errcode
;
1877 if (flags
& F_SUM
) {
1879 if (errcode
!= OK
) {
1880 strcat(msgbuf
, slpv1_error(errcode
));
1882 GETFIELD
; /* attr list */
1884 SKIPAUTH(attr_auth
);
1887 } else if (flags
& F_DTAIL
) {
1889 DOFIELD("Attribute list", FIELD_DEFAULT
);
1896 static int v1_daadvert(int flags
) {
1897 unsigned short errcode
;
1899 if (flags
& F_SUM
) {
1901 if (errcode
!= OK
) {
1902 strcat(msgbuf
, slpv1_error(errcode
));
1906 SKIPFIELD(FIELD_DEFAULT
); /* scope list */
1909 } else if (flags
& F_DTAIL
) {
1911 DOFIELD("URL", FIELD_DEFAULT
);
1912 DOFIELD("Scope list", FIELD_DEFAULT
);
1918 static int v1_srv_type_rqst(int flags
) {
1919 if (flags
& F_SUM
) {
1920 SKIPFIELD(FIELD_PREVRESP
); /* prev responders */
1921 SKIPFIELD(FIELD_TYPENA
); /* naming authority */
1922 GETFIELD
; /* scope */
1923 } else if (flags
& F_DTAIL
) {
1924 DOFIELD("Previous responders", FIELD_PREVRESP
);
1925 DOFIELD("Naming authority", FIELD_TYPENA
);
1926 DOFIELD("Scope string", FIELD_DEFAULT
);
1932 static int v1_srv_type_rply(int flags
) {
1933 unsigned short errcode
, itemcnt
;
1936 if (flags
& F_SUM
) {
1938 if (errcode
!= OK
) {
1939 strcat(msgbuf
, slpv1_error(errcode
));
1942 sprintf(msgend
, "%d type entries", itemcnt
);
1944 for (n
= 0; n
< itemcnt
; n
++) {
1945 SKIPFIELD(FIELD_DEFAULT
); /* Service type item */
1949 } else if (flags
& F_DTAIL
) {
1952 sprintf(get_line(0, 0), "Service type count = %d", itemcnt
);
1953 for (n
= 0; n
< itemcnt
; n
++) {
1954 DOFIELD(" Service type item", FIELD_DEFAULT
);