1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2007 Robert N. M. Watson
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29/*
30 * Debugger routines relating to sockets, protocols, etc, for use in DDB.
31 */
32
33#include <sys/cdefs.h>
34#include "opt_ddb.h"
35
36#include <sys/param.h>
37#include <sys/domain.h>
38#include <sys/kernel.h>
39#include <sys/protosw.h>
40#include <sys/socket.h>
41#include <sys/socketvar.h>
42
43#ifdef DDB
44#include <ddb/ddb.h>
45
46static void
47db_print_sotype(short so_type)
48{
49
50	switch (so_type) {
51	case SOCK_STREAM:
52		db_printf("SOCK_STREAM");
53		break;
54
55	case SOCK_DGRAM:
56		db_printf("SOCK_DGRAM");
57		break;
58
59	case SOCK_RAW:
60		db_printf("SOCK_RAW");
61		break;
62
63	case SOCK_RDM:
64		db_printf("SOCK_RDM");
65		break;
66
67	case SOCK_SEQPACKET:
68		db_printf("SOCK_SEQPACKET");
69		break;
70
71	default:
72		db_printf("unknown");
73		break;
74	}
75}
76
77static void
78db_print_sooptions(int so_options)
79{
80	int comma;
81
82	comma = 0;
83	if (so_options & SO_DEBUG) {
84		db_printf("%sSO_DEBUG", comma ? ", " : "");
85		comma = 1;
86	}
87	if (so_options & SO_ACCEPTCONN) {
88		db_printf("%sSO_ACCEPTCONN", comma ? ", " : "");
89		comma = 1;
90	}
91	if (so_options & SO_REUSEADDR) {
92		db_printf("%sSO_REUSEADDR", comma ? ", " : "");
93		comma = 1;
94	}
95	if (so_options & SO_KEEPALIVE) {
96		db_printf("%sSO_KEEPALIVE", comma ? ", " : "");
97		comma = 1;
98	}
99	if (so_options & SO_DONTROUTE) {
100		db_printf("%sSO_DONTROUTE", comma ? ", " : "");
101		comma = 1;
102	}
103	if (so_options & SO_BROADCAST) {
104		db_printf("%sSO_BROADCAST", comma ? ", " : "");
105		comma = 1;
106	}
107	if (so_options & SO_USELOOPBACK) {
108		db_printf("%sSO_USELOOPBACK", comma ? ", " : "");
109		comma = 1;
110	}
111	if (so_options & SO_LINGER) {
112		db_printf("%sSO_LINGER", comma ? ", " : "");
113		comma = 1;
114	}
115	if (so_options & SO_OOBINLINE) {
116		db_printf("%sSO_OOBINLINE", comma ? ", " : "");
117		comma = 1;
118	}
119	if (so_options & SO_REUSEPORT) {
120		db_printf("%sSO_REUSEPORT", comma ? ", " : "");
121		comma = 1;
122	}
123	if (so_options & SO_REUSEPORT_LB) {
124		db_printf("%sSO_REUSEPORT_LB", comma ? ", " : "");
125		comma = 1;
126	}
127	if (so_options & SO_TIMESTAMP) {
128		db_printf("%sSO_TIMESTAMP", comma ? ", " : "");
129		comma = 1;
130	}
131	if (so_options & SO_NOSIGPIPE) {
132		db_printf("%sSO_NOSIGPIPE", comma ? ", " : "");
133		comma = 1;
134	}
135	if (so_options & SO_ACCEPTFILTER) {
136		db_printf("%sSO_ACCEPTFILTER", comma ? ", " : "");
137		comma = 1;
138	}
139	if (so_options & SO_BINTIME) {
140		db_printf("%sSO_BINTIME", comma ? ", " : "");
141		comma = 1;
142	}
143	if (so_options & SO_NO_OFFLOAD) {
144		db_printf("%sSO_NO_OFFLOAD", comma ? ", " : "");
145		comma = 1;
146	}
147	if (so_options & SO_NO_DDP) {
148		db_printf("%sSO_NO_DDP", comma ? ", " : "");
149		comma = 1;
150	}
151}
152
153static void
154db_print_sostate(short so_state)
155{
156	int comma;
157
158	comma = 0;
159	if (so_state & SS_ISCONNECTED) {
160		db_printf("%sSS_ISCONNECTED", comma ? ", " : "");
161		comma = 1;
162	}
163	if (so_state & SS_ISCONNECTING) {
164		db_printf("%sSS_ISCONNECTING", comma ? ", " : "");
165		comma = 1;
166	}
167	if (so_state & SS_ISDISCONNECTING) {
168		db_printf("%sSS_ISDISCONNECTING", comma ? ", " : "");
169		comma = 1;
170	}
171	if (so_state & SS_NBIO) {
172		db_printf("%sSS_NBIO", comma ? ", " : "");
173		comma = 1;
174	}
175	if (so_state & SS_ASYNC) {
176		db_printf("%sSS_ASYNC", comma ? ", " : "");
177		comma = 1;
178	}
179}
180
181static void
182db_print_soqstate(int so_qstate)
183{
184	int comma;
185
186	comma = 0;
187	if (so_qstate & SQ_INCOMP) {
188		db_printf("%sSQ_INCOMP", comma ? ", " : "");
189		comma = 1;
190	}
191	if (so_qstate & SQ_COMP) {
192		db_printf("%sSQ_COMP", comma ? ", " : "");
193		comma = 1;
194	}
195}
196
197static void
198db_print_sbstate(short sb_state)
199{
200	int comma;
201
202	comma = 0;
203	if (sb_state & SBS_CANTSENDMORE) {
204		db_printf("%sSBS_CANTSENDMORE", comma ? ", " : "");
205		comma = 1;
206	}
207	if (sb_state & SBS_CANTRCVMORE) {
208		db_printf("%sSBS_CANTRCVMORE", comma ? ", " : "");
209		comma = 1;
210	}
211	if (sb_state & SBS_RCVATMARK) {
212		db_printf("%sSBS_RCVATMARK", comma ? ", " : "");
213		comma = 1;
214	}
215}
216
217static void
218db_print_indent(int indent)
219{
220	int i;
221
222	for (i = 0; i < indent; i++)
223		db_printf(" ");
224}
225
226static void
227db_print_domain(struct domain *d, const char *domain_name, int indent)
228{
229
230	db_print_indent(indent);
231	db_printf("%s at %p\n", domain_name, d);
232
233	indent += 2;
234
235	db_print_indent(indent);
236	db_printf("dom_family: %d   ", d->dom_family);
237	db_printf("dom_name: %s\n", d->dom_name);
238
239	db_print_indent(indent);
240	db_printf("dom_externalize: %p   ", d->dom_externalize);
241
242	db_print_indent(indent);
243	db_printf("dom_protosw: %p   ", d->dom_protosw);
244	db_printf("dom_next: %p\n", d->dom_next.sle_next);
245
246	db_print_indent(indent);
247	db_printf("dom_rtattach: %p   ", d->dom_rtattach);
248
249	db_print_indent(indent);
250	db_printf("dom_ifattach: %p   ", d->dom_ifattach);
251	db_printf("dom_ifdetach: %p\n", d->dom_ifdetach);
252}
253
254static void
255db_print_prflags(short pr_flags)
256{
257	int comma;
258
259	comma = 0;
260	if (pr_flags & PR_ATOMIC) {
261		db_printf("%sPR_ATOMIC", comma ? ", " : "");
262		comma = 1;
263	}
264	if (pr_flags & PR_ADDR) {
265		db_printf("%sPR_ADDR", comma ? ", " : "");
266		comma = 1;
267	}
268	if (pr_flags & PR_CONNREQUIRED) {
269		db_printf("%sPR_CONNREQUIRED", comma ? ", " : "");
270		comma = 1;
271	}
272	if (pr_flags & PR_WANTRCVD) {
273		db_printf("%sPR_WANTRCVD", comma ? ", " : "");
274		comma = 1;
275	}
276	if (pr_flags & PR_IMPLOPCL) {
277		db_printf("%sPR_IMPLOPCL", comma ? ", " : "");
278		comma = 1;
279	}
280}
281
282static void
283db_print_protosw(struct protosw *pr, const char *prname, int indent)
284{
285
286	db_print_indent(indent);
287	db_printf("%s at %p\n", prname, pr);
288
289	indent += 2;
290
291	db_print_indent(indent);
292	db_printf("pr_type: %d   ", pr->pr_type);
293	db_printf("pr_domain: %p\n", pr->pr_domain);
294	if (pr->pr_domain != NULL)
295		db_print_domain(pr->pr_domain, "pr_domain", indent);
296
297	db_print_indent(indent);
298	db_printf("pr_protocol: %d\n", pr->pr_protocol);
299
300	db_print_indent(indent);
301	db_printf("pr_flags: %d (", pr->pr_flags);
302	db_print_prflags(pr->pr_flags);
303	db_printf(")\n");
304
305	db_print_indent(indent);
306	db_printf("pr_ctloutput: %p   ", pr->pr_ctloutput);
307}
308
309static void
310db_print_sbflags(short sb_flags)
311{
312	int comma;
313
314	comma = 0;
315	if (sb_flags & SB_WAIT) {
316		db_printf("%sSB_WAIT", comma ? ", " : "");
317		comma = 1;
318	}
319	if (sb_flags & SB_SEL) {
320		db_printf("%sSB_SEL", comma ? ", " : "");
321		comma = 1;
322	}
323	if (sb_flags & SB_ASYNC) {
324		db_printf("%sSB_ASYNC", comma ? ", " : "");
325		comma = 1;
326	}
327	if (sb_flags & SB_UPCALL) {
328		db_printf("%sSB_UPCALL", comma ? ", " : "");
329		comma = 1;
330	}
331	if (sb_flags & SB_NOINTR) {
332		db_printf("%sSB_NOINTR", comma ? ", " : "");
333		comma = 1;
334	}
335	if (sb_flags & SB_AIO) {
336		db_printf("%sSB_AIO", comma ? ", " : "");
337		comma = 1;
338	}
339	if (sb_flags & SB_KNOTE) {
340		db_printf("%sSB_KNOTE", comma ? ", " : "");
341		comma = 1;
342	}
343	if (sb_flags & SB_AUTOSIZE) {
344		db_printf("%sSB_AUTOSIZE", comma ? ", " : "");
345		comma = 1;
346	}
347}
348
349static void
350db_print_sockbuf(struct sockbuf *sb, const char *sockbufname, int indent)
351{
352
353	db_print_indent(indent);
354	db_printf("%s at %p\n", sockbufname, sb);
355
356	indent += 2;
357
358	db_print_indent(indent);
359	db_printf("sb_state: 0x%x (", sb->sb_state);
360	db_print_sbstate(sb->sb_state);
361	db_printf(")\n");
362
363	db_print_indent(indent);
364	db_printf("sb_mb: %p   ", sb->sb_mb);
365	db_printf("sb_mbtail: %p   ", sb->sb_mbtail);
366	db_printf("sb_lastrecord: %p\n", sb->sb_lastrecord);
367
368	db_print_indent(indent);
369	db_printf("sb_sndptr: %p   ", sb->sb_sndptr);
370	db_printf("sb_sndptroff: %u\n", sb->sb_sndptroff);
371
372	db_print_indent(indent);
373	db_printf("sb_acc: %u   ", sb->sb_acc);
374	db_printf("sb_ccc: %u   ", sb->sb_ccc);
375	db_printf("sb_hiwat: %u   ", sb->sb_hiwat);
376	db_printf("sb_mbcnt: %u   ", sb->sb_mbcnt);
377	db_printf("sb_mbmax: %u\n", sb->sb_mbmax);
378
379	db_print_indent(indent);
380	db_printf("sb_ctl: %u   ", sb->sb_ctl);
381	db_printf("sb_lowat: %d   ", sb->sb_lowat);
382	db_printf("sb_timeo: %jd\n", sb->sb_timeo);
383
384	db_print_indent(indent);
385	db_printf("sb_flags: 0x%x (", sb->sb_flags);
386	db_print_sbflags(sb->sb_flags);
387	db_printf(")\n");
388
389	db_print_indent(indent);
390	db_printf("sb_aiojobq first: %p\n", TAILQ_FIRST(&sb->sb_aiojobq));
391}
392
393static void
394db_print_socket(struct socket *so, const char *socketname, int indent)
395{
396
397	db_print_indent(indent);
398	db_printf("%s at %p\n", socketname, so);
399
400	indent += 2;
401
402	db_print_indent(indent);
403	db_printf("so_count: %d   ", so->so_count);
404	db_printf("so_type: %d (", so->so_type);
405	db_print_sotype(so->so_type);
406	db_printf(")\n");
407
408	db_print_indent(indent);
409	db_printf("so_options: 0x%x (", so->so_options);
410	db_print_sooptions(so->so_options);
411	db_printf(")\n");
412
413	db_print_indent(indent);
414	db_printf("so_linger: %d   ", so->so_linger);
415	db_printf("so_state: 0x%x (", so->so_state);
416	db_print_sostate(so->so_state);
417	db_printf(")\n");
418
419	db_print_indent(indent);
420	db_printf("so_pcb: %p   ", so->so_pcb);
421	db_printf("so_proto: %p\n", so->so_proto);
422
423	if (so->so_proto != NULL)
424		db_print_protosw(so->so_proto, "so_proto", indent);
425
426	db_print_indent(indent);
427	if (so->so_options & SO_ACCEPTCONN) {
428		db_printf("sol_incomp first: %p   ",
429		    TAILQ_FIRST(&so->sol_incomp));
430		db_printf("sol_comp first: %p\n", TAILQ_FIRST(&so->sol_comp));
431		db_printf("sol_qlen: %d   ", so->sol_qlen);
432		db_printf("sol_incqlen: %d   ", so->sol_incqlen);
433		db_printf("sol_qlimit: %d   ", so->sol_qlimit);
434	} else {
435		db_printf("so_qstate: 0x%x (", so->so_qstate);
436		db_print_soqstate(so->so_qstate);
437		db_printf(")   ");
438		db_printf("so_listen: %p   ", so->so_listen);
439		/* so_list skipped */
440		db_printf("so_timeo: %d   ", so->so_timeo);
441		db_printf("so_error: %d\n", so->so_error);
442
443		db_print_indent(indent);
444		db_printf("so_sigio: %p   ", so->so_sigio);
445		db_printf("so_oobmark: %lu\n", so->so_oobmark);
446
447		db_print_sockbuf(&so->so_rcv, "so_rcv", indent);
448		db_print_sockbuf(&so->so_snd, "so_snd", indent);
449	}
450}
451
452DB_SHOW_COMMAND(socket, db_show_socket)
453{
454	struct socket *so;
455
456	if (!have_addr) {
457		db_printf("usage: show socket <addr>\n");
458		return;
459	}
460	so = (struct socket *)addr;
461
462	db_print_socket(so, "socket", 0);
463}
464
465DB_SHOW_COMMAND(sockbuf, db_show_sockbuf)
466{
467	struct sockbuf *sb;
468
469	if (!have_addr) {
470		db_printf("usage: show sockbuf <addr>\n");
471		return;
472	}
473	sb = (struct sockbuf *)addr;
474
475	db_print_sockbuf(sb, "sockbuf", 0);
476}
477
478DB_SHOW_COMMAND(protosw, db_show_protosw)
479{
480	struct protosw *pr;
481
482	if (!have_addr) {
483		db_printf("usage: show protosw <addr>\n");
484		return;
485	}
486	pr = (struct protosw *)addr;
487
488	db_print_protosw(pr, "protosw", 0);
489}
490
491DB_SHOW_COMMAND(domain, db_show_domain)
492{
493	struct domain *d;
494
495	if (!have_addr) {
496		db_printf("usage: show protosw <addr>\n");
497		return;
498	}
499	d = (struct domain *)addr;
500
501	db_print_domain(d, "domain", 0);
502}
503#endif
504