1/* 2 * Copyright (c) 2003-2004 3 * Hartmut Brandt 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> 7 * 8 * Redistribution of this software and documentation and use in source and 9 * binary forms, with or without modification, are permitted provided that 10 * the following conditions are met: 11 * 12 * 1. Redistributions of source code or documentation must retain the above 13 * copyright notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR 19 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 * THE AUTHOR OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 25 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * $Begemot: libunimsg/netnatm/api/cc_dump.c,v 1.3 2004/08/05 07:10:56 brandt Exp $ 31 * 32 * ATM API as defined per af-saa-0108 33 */ 34 35#include <netnatm/unimsg.h> 36#include <netnatm/msg/unistruct.h> 37#include <netnatm/msg/unimsglib.h> 38#include <netnatm/api/unisap.h> 39#include <netnatm/sig/unidef.h> 40#include <netnatm/api/atmapi.h> 41#include <netnatm/api/ccatm.h> 42#include <netnatm/api/ccpriv.h> 43 44#ifdef _KERNEL 45#ifdef __FreeBSD__ 46#include <machine/stdarg.h> 47#endif 48#else /* !_KERNEL */ 49#include <stdarg.h> 50#endif 51 52/* 53 * local structure to reduce number of arguments to functions 54 */ 55struct dump { 56 struct ccdata *cc; /* what to dump */ 57 size_t maxsiz; /* size of user buffer */ 58 cc_dump_f func; /* user function */ 59 void *uarg; /* user supplied argument */ 60 char *buf; /* user buffer */ 61 size_t len; /* current string length */ 62 int ret; /* return code */ 63}; 64 65static void cc_dumpf(struct dump *, const char *, ...) __printflike(2, 3); 66 67static void 68cc_dumpf(struct dump *d, const char *fmt, ...) 69{ 70 va_list ap; 71 int n; 72 73 if (d->ret != 0) 74 return; 75 if (d->len >= d->maxsiz - 1) { 76 d->ret = d->func(d->cc, d->uarg, d->buf); 77 if (d->ret != 0) 78 return; 79 d->buf[0] = '\0'; 80 d->len = 0; 81 } 82 va_start(ap, fmt); 83 n = vsnprintf(d->buf + d->len, d->maxsiz - d->len, fmt, ap); 84 va_end(ap); 85 86 if (n < 0) { 87 d->ret = CCGETERRNO(); 88 return; 89 } 90 if ((size_t)n < d->maxsiz - d->len) { 91 d->len += n; 92 return; 93 } 94 95 /* undo the vsnprintf() and flush */ 96 d->buf[d->len] = '\0'; 97 d->ret = d->func(d->cc, d->uarg, d->buf); 98 if (d->ret != 0) 99 return; 100 d->buf[0] = '\0'; 101 d->len = 0; 102 103 va_start(ap, fmt); 104 n = vsnprintf(d->buf, d->maxsiz, fmt, ap); 105 va_end(ap); 106 107 if (n < 0) { 108 d->ret = CCGETERRNO(); 109 return; 110 } 111 if ((size_t)n >= d->maxsiz) { 112 /* ok, truncate */ 113 d->len = d->maxsiz - 1; 114 return; 115 } 116 d->len = n; 117} 118 119/* 120 * Dump a SAP 121 */ 122static void 123cc_dump_sap(struct dump *d, const struct uni_sap *sap) 124{ 125 static const char *const tagtab[] = { 126 [UNISVE_ABSENT] = "absent", 127 [UNISVE_ANY] = "any", 128 [UNISVE_PRESENT] = "present" 129 }; 130 static const char *const plantab[] = { 131 [UNI_ADDR_E164] = "E164", 132 [UNI_ADDR_ATME] = "ATME", 133 }; 134 static const char *const hlitab[] = { 135 [UNI_BHLI_ISO] = "ISO", 136 [UNI_BHLI_VENDOR] = "VENDOR", 137 [UNI_BHLI_USER] = "USER" 138 }; 139 u_int i; 140 141 cc_dumpf(d, " sap(%p):\n", sap); 142 cc_dumpf(d, " addr=%s", tagtab[sap->addr.tag]); 143 if (sap->addr.tag == UNISVE_PRESENT) { 144 cc_dumpf(d, " %s %u ", plantab[sap->addr.plan], sap->addr.len); 145 if (sap->addr.plan == UNI_ADDR_E164) 146 for (i = 0; i < sap->addr.len; i++) 147 cc_dumpf(d, "%c", sap->addr.addr[i]); 148 else 149 for (i = 0; i < sap->addr.len; i++) 150 cc_dumpf(d, "%02x", sap->addr.addr[i]); 151 } 152 cc_dumpf(d, "\n"); 153 154 cc_dumpf(d, " selector=%s", tagtab[sap->selector.tag]); 155 if (sap->selector.tag == UNISVE_PRESENT) 156 cc_dumpf(d, " %02x", sap->selector.selector); 157 cc_dumpf(d, "\n"); 158 159 cc_dumpf(d, " blli_id2=%s", tagtab[sap->blli_id2.tag]); 160 if (sap->blli_id2.tag == UNISVE_PRESENT) 161 cc_dumpf(d, " %02x %02x", sap->blli_id2.proto, 162 sap->blli_id2.user); 163 cc_dumpf(d, "\n"); 164 165 cc_dumpf(d, " blli_id3=%s", tagtab[sap->blli_id3.tag]); 166 if (sap->blli_id3.tag == UNISVE_PRESENT) 167 cc_dumpf(d, " %02x,%02x, %02x(%d),%03x,%02x", 168 sap->blli_id3.proto, sap->blli_id3.user, 169 sap->blli_id3.ipi, sap->blli_id3.noipi, 170 sap->blli_id3.oui, sap->blli_id3.pid); 171 cc_dumpf(d, "\n"); 172 173 cc_dumpf(d, " bhli=%s", tagtab[sap->bhli.tag]); 174 if (sap->bhli.tag == UNISVE_PRESENT) { 175 cc_dumpf(d, " %s ", hlitab[sap->bhli.type]); 176 for (i = 0; i < sap->bhli.len; i++) 177 cc_dumpf(d, "%02x", sap->bhli.info[i]); 178 } 179 cc_dumpf(d, "\n"); 180} 181 182/* 183 * Dump a user. 184 */ 185static void 186cc_dump_user(struct dump *d, const struct ccuser *user) 187{ 188 struct ccconn *conn; 189 190 cc_dumpf(d, "user(%p): %s '%s' %s\n", user, 191 cc_user_state2str(user->state), user->name, 192 (user->config == USER_P2P) ? "p2p" : 193 (user->config == USER_ROOT) ? "root" : 194 (user->config == USER_LEAF) ? "leaf" : "?"); 195 if (user->sap) 196 cc_dump_sap(d, user->sap); 197 198 cc_dumpf(d, " queue=%u/%u accepted=%p aborted=%u\n", user->queue_max, 199 user->queue_act, user->accepted, user->aborted); 200 201 cc_dumpf(d, " connq:"); 202 TAILQ_FOREACH(conn, &user->connq, connq_link) 203 cc_dumpf(d, "%p", conn); 204 cc_dumpf(d, "\n"); 205} 206 207/* 208 * Dump a party 209 */ 210static void 211cc_dump_party(struct dump *d, const struct ccparty *party, const char *pfx) 212{ 213 214 cc_dumpf(d, "%s party(%p): %u.%u %s\n", pfx, party, 215 party->epref.flag, party->epref.epref, 216 cc_party_state2str(party->state)); 217} 218 219/* 220 * Dump a connection 221 */ 222static void 223cc_dump_conn(struct dump *d, const struct ccconn *conn, const char *pfx) 224{ 225 const struct ccparty *party; 226 227 cc_dumpf(d, "%sconn(%p): %s\n", pfx, conn, 228 cc_conn_state2str(conn->state)); 229 cc_dumpf(d, "%s user=%p cref=%u.%u acceptor=%p\n", pfx, 230 conn->user, conn->cref.cref, conn->cref.flag, 231 conn->acceptor); 232 233 cc_dumpf(d, "%s blli_sel=%u\n", pfx, conn->blli_selector); 234 235 LIST_FOREACH(party, &conn->parties, link) 236 cc_dump_party(d, party, pfx); 237} 238 239/* 240 * Dump a port 241 */ 242static void 243cc_dump_port(struct dump *d, const struct ccport *p) 244{ 245 u_int i; 246 const struct ccaddr *a; 247 const struct ccconn *c; 248 const struct ccreq *r; 249 250 static const char *const ttab[] = { 251 [UNI_ADDR_UNKNOWN] = "unknown", 252 [UNI_ADDR_INTERNATIONAL] = "international", 253 [UNI_ADDR_NATIONAL] = "national", 254 [UNI_ADDR_NETWORK] = "network", 255 [UNI_ADDR_SUBSCR] = "subscr", 256 [UNI_ADDR_ABBR] = "abbr", 257 }; 258 static const char *const ptab[] = { 259 [UNI_ADDR_UNKNOWN] = "unknown", 260 [UNI_ADDR_E164] = "e164", 261 [UNI_ADDR_ATME] = "atme", 262 [UNI_ADDR_DATA] = "data", 263 [UNI_ADDR_PRIVATE] = "private", 264 }; 265 266 cc_dumpf(d, "port(%p) %u: %s\n", p, p->param.port, 267 (p->admin == CCPORT_STOPPED) ? "STOPPED" : 268 (p->admin == CCPORT_RUNNING) ? "RUNNING" : "????"); 269 cc_dumpf(d, " pcr=%u bits=%u.%u ids=%u/%u/%u esi=%02x:%02x:" 270 "%02x:%02x:%02x:%02x naddrs=%u\n", p->param.pcr, 271 p->param.max_vpi_bits, p->param.max_vci_bits, p->param.max_svpc_vpi, 272 p->param.max_svcc_vpi, p->param.min_svcc_vci, p->param.esi[0], 273 p->param.esi[1], p->param.esi[2], p->param.esi[3], p->param.esi[4], 274 p->param.esi[5], p->param.num_addrs); 275 276 cc_dumpf(d, " cookies:"); 277 TAILQ_FOREACH(r, &p->cookies, link) 278 cc_dumpf(d, " %u(%p,%u)", r->cookie, r->conn, r->req); 279 cc_dumpf(d, "\n"); 280 281 TAILQ_FOREACH(a, &p->addr_list, port_link) { 282 cc_dumpf(d, " addr(%p): %s %s %u ", a, 283 (a->addr.type < sizeof(ttab) / sizeof(ttab[0]) && 284 ttab[a->addr.type] != NULL) ? ttab[a->addr.type] : "?", 285 (a->addr.plan < sizeof(ptab) / sizeof(ptab[0]) && 286 ptab[a->addr.plan] != NULL) ? ptab[a->addr.plan] : "?", 287 a->addr.len); 288 for (i = 0; i < a->addr.len; i++) 289 cc_dumpf(d, "%02x", a->addr.addr[i]); 290 cc_dumpf(d, "\n"); 291 } 292 LIST_FOREACH(c, &p->conn_list, port_link) 293 cc_dump_conn(d, c, " "); 294} 295 296/* 297 * Produce a textual dump of the state 298 */ 299int 300cc_dump(struct ccdata *cc, size_t maxsiz, cc_dump_f func, void *uarg) 301{ 302 struct dump d; 303 struct ccuser *user; 304 struct ccconn *conn; 305 struct ccport *port; 306 307 d.ret = 0; 308 d.uarg = uarg; 309 d.maxsiz = maxsiz; 310 d.cc = cc; 311 d.func = func; 312 d.buf = CCMALLOC(maxsiz); 313 if (d.buf == NULL) 314 return (ENOMEM); 315 d.len = 0; 316 317 cc_dumpf(&d, "dump of node %p\n", cc); 318 319 TAILQ_FOREACH(port, &cc->port_list, node_link) 320 cc_dump_port(&d, port); 321 322 LIST_FOREACH(user, &cc->user_list, node_link) 323 cc_dump_user(&d, user); 324 325 cc_dumpf(&d, "orphaned conns:\n"); 326 LIST_FOREACH(conn, &cc->orphaned_conns, port_link) 327 cc_dump_conn(&d, conn, ""); 328 329 if (d.len > 0 && d.ret == 0) 330 d.ret = d.func(d.cc, d.uarg, d.buf); 331 332 CCFREE(d.buf); 333 return (d.ret); 334} 335