]> git.saurik.com Git - apple/network_cmds.git/blame - mptcp_client/mptcp_client.c
network_cmds-606.100.3.tar.gz
[apple/network_cmds.git] / mptcp_client / mptcp_client.c
CommitLineData
342c141e
A
1/*
2 * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright (c) 1997
30 * The Regents of the University of California. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that: (1) source code distributions
34 * retain the above copyright notice and this paragraph in its entirety, (2)
35 * distributions including binary code include the above copyright notice and
36 * this paragraph in its entirety in the documentation or other materials
37 * provided with the distribution, and (3) all advertising materials mentioning
38 * features or use of this software display the following acknowledgement:
39 * ``This product includes software developed by the University of California,
40 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
41 * the University nor the names of its contributors may be used to endorse
42 * or promote products derived from this software without specific prior
43 * written permission.
44 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
45 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
46 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
47 */
48
49//
50// Created by Anumita Biswas on 7/17/12.
51//
52
53#include <stdio.h>
54#include <stdlib.h>
55#include <unistd.h>
56#include <string.h>
57#include <stdint.h>
58#include <sys/types.h>
59#include <sys/socket.h>
60#include <sys/ioctl.h>
61#include <net/if.h>
62#include <netinet/in.h>
63#include <netdb.h>
64#include <errno.h>
65#include <arpa/inet.h>
66#include <err.h>
67#include <sysexits.h>
68#include <getopt.h>
69
70#include "conn_lib.h"
71
72struct so_cordreq socorder;
73static void showmpinfo(int s);
74
75#define MSG_HDR "Message Header"
76#define RESPONSE "I got your message"
77
78static int verbose = 0;
79
80static int32_t thiszone = 0; /* time difference with gmt */
81
d9520f62 82char *setup_buffer1(int bufsz)
342c141e
A
83{
84 int i = 0, j = 1;
d9520f62
A
85 char *buf;
86
87 buf = malloc(bufsz);
88 if (!buf)
89 return NULL;
90
91 bzero(buf, bufsz);
e0b07f2d 92 strlcpy(buf, MSG_HDR, bufsz);
d9520f62 93
342c141e
A
94 for (i = sizeof(MSG_HDR); i < bufsz; i++) {
95 buf[i] = j;
96 j++;
97 if (j >= 255)
98 j = 1;
99 }
100 return buf;
101}
102
d9520f62 103char *setup_buffer2(int bufsz)
342c141e
A
104{
105 int i = 0;
106 char j = 'A';
d9520f62
A
107 char *buf;
108
109 buf = malloc(bufsz);
110 if (!buf)
111 return NULL;
112
113 bzero(buf, bufsz);
e0b07f2d 114 strlcpy(buf, MSG_HDR, bufsz);
d9520f62 115
342c141e
A
116 for (i = sizeof(MSG_HDR); i < bufsz; i++) {
117 buf[i] = j;
118 j++;
119 if (j >= 'z')
120 j = 'A';
121 }
122 return buf;
123}
124
125char *setup_buffer3(int bufsz)
126{
d9520f62
A
127 char *buf;
128
129 buf = malloc(bufsz);
130 if (!buf)
131 return NULL;
132
133 bzero(buf, bufsz);
342c141e
A
134 return buf;
135}
136
137/*
138 * Returns the difference between gmt and local time in seconds.
139 * Use gmtime() and localtime() to keep things simple.
140 * from tcpdump/gmt2local.c
141 */
142static int32_t
143gmt2local(time_t t)
144{
145 int dt, dir;
146 struct tm *gmt, *loc;
147 struct tm sgmt;
d9520f62 148
342c141e
A
149 if (t == 0)
150 t = time(NULL);
151 gmt = &sgmt;
152 *gmt = *gmtime(&t);
153 loc = localtime(&t);
154 dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
155 (loc->tm_min - gmt->tm_min) * 60;
d9520f62 156
342c141e
A
157 /*
158 * If the year or julian day is different, we span 00:00 GMT
159 * and must add or subtract a day. Check the year first to
160 * avoid problems when the julian day wraps.
161 */
162 dir = loc->tm_year - gmt->tm_year;
163 if (dir == 0)
164 dir = loc->tm_yday - gmt->tm_yday;
165 dt += dir * 24 * 60 * 60;
d9520f62 166
342c141e
A
167 return (dt);
168}
169
170/*
171 * Print the timestamp
172 * from tcpdump/util.c
173 */
174static void
175ts_print(void)
176{
177 int s;
178 struct timeval tv;
d9520f62 179
342c141e 180 gettimeofday(&tv, NULL);
d9520f62 181
342c141e
A
182 /* Default */
183 s = (tv.tv_sec + thiszone) % 86400;
184 printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
185 (u_int32_t)tv.tv_usec);
186}
187
188static const char *
189basename(const char * str)
190{
191 const char *last_slash = strrchr(str, '/');
d9520f62 192
342c141e
A
193 if (last_slash == NULL)
194 return (str);
195 else
196 return (last_slash + 1);
197}
198
199struct option_desc {
200 const char *option;
201 const char *description;
202 int required;
203};
204
205struct option_desc option_desc_list[] = {
206 { "--host addr", "address of server to connect to", 1 },
207 { "--port n", "port of server to connect to", 1 },
208 { "--reqlen n", "length of request (256 by default)", 0 },
209 { "--rsplen n", "length of response (256 by default)", 0 },
210 { "--ntimes n", "number of time to send request (1 by default)", 0 },
211 { "--alt_addr addr", "alternate server to connect to", 0 },
342c141e
A
212 { "--verbose", "increase verbosity", 0 },
213 { "--help", "display this help", 0 },
214
215 { NULL, NULL, 0 } /* Mark end of list */
216};
217
218static void
219usage(const char *cmd)
220{
221 struct option_desc *option_desc;
222 char *usage_str = malloc(LINE_MAX);
223 size_t usage_len;
d9520f62 224
342c141e
A
225 if (usage_str == NULL)
226 err(1, "%s: malloc(%d)", __func__, LINE_MAX);
d9520f62 227
342c141e 228 usage_len = snprintf(usage_str, LINE_MAX, "# usage: %s ", basename(cmd));
d9520f62 229
342c141e
A
230 for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
231 int len;
d9520f62 232
342c141e
A
233 if (option_desc->required)
234 len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "%s ", option_desc->option);
235 else
236 len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "[%s] ", option_desc->option);
237 if (len < 0)
238 err(1, "%s: snprintf(", __func__);
d9520f62 239
342c141e
A
240 usage_len += len;
241 if (usage_len > LINE_MAX)
242 break;
243 }
244 printf("%s\n", usage_str);
245 printf("options:\n");
d9520f62 246
342c141e
A
247 for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
248 printf(" %-24s # %s\n", option_desc->option, option_desc->description);
249 }
250 printf("\n");
251 printf("# legacy usage: ");
342c141e
A
252}
253
254static struct option longopts[] = {
d9520f62
A
255 { "host", required_argument, NULL, 'c' },
256 { "port", required_argument, NULL, 'p' },
257 { "reqlen", required_argument, NULL, 'r' },
258 { "rsplen", required_argument, NULL, 'R' },
259 { "ntimes", required_argument, NULL, 'n' },
260 { "alt_addr", required_argument, NULL, 'a' },
261 { "help", no_argument, NULL, 'h' },
262 { "verbose", no_argument, NULL, 'v' },
263 { "quiet", no_argument, NULL, 'q' },
264 { NULL, 0, NULL, 0 }
342c141e
A
265};
266
267static int
268sprint_sockaddr(char *str, socklen_t strlen, struct sockaddr *sa)
269{
270 int retval = 0;
271
272 if (sa->sa_family == AF_INET) {
273 struct sockaddr_in *sin = (struct sockaddr_in*)sa;
274 char str4[INET_ADDRSTRLEN];
d9520f62 275
342c141e 276 inet_ntop(AF_INET, &sin->sin_addr, str4, sizeof(str4));
d9520f62 277
342c141e
A
278 retval = snprintf(str, strlen, "%s:%u", str4, ntohs(sin->sin_port));
279 } else if (sa->sa_family == AF_INET6) {
280 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
281 char str6[INET6_ADDRSTRLEN];
282 char ifname[IF_NAMESIZE];
283 char scopestr[2 + IF_NAMESIZE];
d9520f62 284
342c141e
A
285 inet_ntop(AF_INET6, &sin6->sin6_addr, str6, sizeof(str6));
286
287 if (sin6->sin6_scope_id == 0)
288 *scopestr = '\0';
289 else {
290 if_indextoname(sin6->sin6_scope_id, ifname);
291 snprintf(scopestr, sizeof(scopestr), "%%%s", ifname);
292 }
d9520f62 293
342c141e
A
294 retval = snprintf(str, strlen, "%s%s:%u",
295 str6,
296 scopestr,
297 ntohs(sin6->sin6_port));
298 }
299 return (retval);
300}
301
302int main(int argc, char * const *argv)
303{
d9520f62 304 int sockfd, portno;
342c141e
A
305 ssize_t n;
306 int reqlen = 256;
307 int rsplen = 256;
308 int ntimes = 1;
342c141e
A
309 char *buffer = NULL;
310 char *buffer1;
311 char *buffer2;
312 char *buffer3;
313 struct addrinfo *ares = NULL, ahints;
314 struct addrinfo *altres = NULL;
315 int retval = 0;
316 int which_buf = 0;
89c4ed63 317 sae_connid_t cid1, cid2;
342c141e
A
318 int iter;
319 int bytes_to_rdwr;
342c141e
A
320 int ch;
321 const char *host_arg = NULL;
322 const char *port_arg = NULL;
323 const char *reqlen_arg = "256";
324 const char *rsplen_arg = "256";
325 const char *ntimes_arg = "1";
326 const char *alt_addr_arg = NULL;
327 const char *alt_port_arg = "0";
342c141e
A
328 int gotopt = 0;
329
330 thiszone = gmt2local(0);
d9520f62
A
331
332 while ((ch = getopt_long(argc, argv, "a:c:hn:p:qr:R:v", longopts, NULL)) != -1) {
342c141e
A
333 gotopt = 1;
334 switch (ch) {
335 case 'a':
336 alt_addr_arg = optarg;
337 break;
338 case 'c':
339 host_arg = optarg;
340 break;
342c141e
A
341 case 'n':
342 ntimes_arg = optarg;
343 break;
342c141e
A
344 case 'p':
345 port_arg = optarg;
346 break;
347 case 'q':
348 verbose--;
349 break;
350 case 'r':
351 reqlen_arg = optarg;
352 break;
353 case 'R':
354 rsplen_arg = optarg;
355 break;
356 case 'v':
357 verbose++;
358 break;
342c141e
A
359 default:
360 usage(argv[0]);
361 exit(EX_USAGE);
342c141e
A
362 }
363 }
d9520f62 364
342c141e
A
365 if (gotopt == 0) {
366 if (argc == 12) {
367 host_arg = argv[1];
368 port_arg = argv[2];
369 reqlen_arg = argv[3];
370 rsplen_arg = argv[4];
371 ntimes_arg = argv[5];
372 alt_addr_arg = argv[6];
342c141e
A
373 } else {
374 usage(argv[0]);
375 exit(EX_USAGE);
376 }
377 }
d9520f62 378
342c141e
A
379 if (host_arg == NULL)
380 errx(EX_USAGE, "missing required host option\n");
381
382 if (port_arg == NULL)
383 errx(EX_USAGE, "missing required port option\n");
384 portno = atoi(port_arg);
385 if (portno < 0 || portno > 65535)
386 errx(EX_USAGE, "invalid port %s\n", port_arg);
387
388 if (reqlen_arg != NULL) {
389 reqlen = atoi(reqlen_arg);
d9520f62 390 if (reqlen < 0 || reqlen > 1024 * 1024)
342c141e
A
391 errx(EX_USAGE, "invalid request length %s\n", reqlen_arg);
392 }
393
394 if (rsplen_arg != NULL) {
395 rsplen = atoi(rsplen_arg);
d9520f62 396 if (rsplen < 0 || rsplen > 1024 * 1024)
342c141e
A
397 errx(EX_USAGE, "invalid response length %s\n", rsplen_arg);
398 }
d9520f62 399
342c141e
A
400 if (ntimes_arg != NULL) {
401 ntimes = atoi(ntimes_arg);
402 if (ntimes < 1)
403 errx(EX_USAGE, "invalid ntimes option %s\n", ntimes_arg);
404 }
d9520f62 405
342c141e
A
406 buffer1 = setup_buffer1(reqlen);
407 if (!buffer1) {
408 printf("client: failed to alloc buffer space \n");
409 return -1;
410 }
d9520f62 411
342c141e
A
412 buffer2 = setup_buffer2(reqlen);
413 if (!buffer2) {
414 printf("client: failed to alloc buffer space \n");
415 return -1;
416 }
d9520f62 417
342c141e
A
418 buffer3 = setup_buffer3(rsplen);
419 if (!buffer3) {
420 printf("client: failed to alloc buffer space \n");
421 return -1;
422 }
d9520f62 423
342c141e 424 if (verbose > 0)
d9520f62
A
425 printf("host: %s port: %s reqlen: %d rsplen: %d ntimes: %d alt_addr: %s\n",
426 host_arg, port_arg, reqlen, rsplen, ntimes, alt_addr_arg);
427
342c141e
A
428 sockfd = socket(AF_MULTIPATH, SOCK_STREAM, 0);
429 if (sockfd < 0)
430 err(EX_OSERR, "ERROR opening socket");
d9520f62 431
342c141e
A
432 memset(&ahints, 0, sizeof(struct addrinfo));
433 ahints.ai_family = AF_INET;
434 ahints.ai_socktype = SOCK_STREAM;
435 ahints.ai_protocol = IPPROTO_TCP;
d9520f62 436
342c141e
A
437 retval = getaddrinfo(host_arg, port_arg, &ahints, &ares);
438 if (retval != 0)
439 printf("getaddrinfo(%s, %s) failed %d\n", host_arg, port_arg, retval);
d9520f62 440
342c141e 441 bytes_to_rdwr = reqlen;
d9520f62 442
89c4ed63 443 cid1 = cid2 = SAE_CONNID_ANY;
342c141e
A
444 int ifscope = 0;
445 int error = 0;
d9520f62 446
342c141e
A
447 if (verbose > 0) {
448 char str[2 * INET6_ADDRSTRLEN];
d9520f62 449
342c141e 450 ts_print();
d9520f62 451
342c141e
A
452 sprint_sockaddr(str, sizeof(str), ares->ai_addr);
453 printf("connectx(%s, %d, %d)\n", str, ifscope, cid1);
454 }
89c4ed63
A
455 sa_endpoints_t sa;
456 bzero(&sa, sizeof(sa));
457 sa.sae_dstaddr = ares->ai_addr;
458 sa.sae_dstaddrlen = ares->ai_addrlen;
459 sa.sae_srcif = ifscope;
460
461 error = connectx(sockfd, &sa, SAE_ASSOCID_ANY, 0, NULL, 0, NULL, &cid1);
d9520f62 462 if (error != 0)
342c141e 463 err(EX_OSERR, "ERROR connecting");
d9520f62 464
342c141e 465 iter = 0;
d9520f62 466
342c141e 467 while (ntimes) {
d9520f62 468 if (iter == 0) {
342c141e 469 /* Add alternate path if available */
d9520f62 470
342c141e
A
471 if (alt_addr_arg && alt_addr_arg[0] != 0) {
472 retval = getaddrinfo(alt_addr_arg, alt_port_arg, &ahints, &altres);
d9520f62 473
342c141e
A
474 if (retval != 0)
475 printf("client: alternate address resolution failed. \n");
476 else {
477 printf("client: connecting to alternate address (ifscope %d)\n", ifscope);
478
479 if (verbose > 0) {
480 char str[2 * INET6_ADDRSTRLEN];
481
482 ts_print();
d9520f62 483
342c141e
A
484 sprint_sockaddr(str, sizeof(str), altres->ai_addr);
485 printf("connectx(%s, %d, %d)\n", str, ifscope, cid1);
486 }
89c4ed63
A
487 sa_endpoints_t sa;
488 bzero(&sa, sizeof(sa));
489 sa.sae_srcif = ifscope;
490 sa.sae_srcaddr = altres->ai_addr;
491 sa.sae_srcaddrlen = altres->ai_addrlen;
492 sa.sae_dstaddr = ares->ai_addr;
493 sa.sae_dstaddrlen = ares->ai_addrlen;
d9520f62 494
89c4ed63 495 error = connectx(sockfd, &sa, SAE_ASSOCID_ANY, 0, NULL, 0, NULL, &cid2);
342c141e
A
496 if (error < 0) {
497 err(EX_OSERR, "ERROR setting up alternate path");
498 }
499 }
500 }
342c141e 501 }
d9520f62 502
342c141e
A
503 if (which_buf == 0) {
504 buffer = buffer1;
505 which_buf = 1;
506 } else {
507 buffer = buffer2;
508 which_buf = 0;
509 }
d9520f62 510
342c141e
A
511 while (bytes_to_rdwr) {
512 if (verbose) {
513 ts_print();
514 printf("writing %d bytes\n", bytes_to_rdwr);
515 }
516 n = write(sockfd, buffer, bytes_to_rdwr);
517 if (n <= 0) {
518 err(EX_OSERR, "ERROR writing to socket");
519 }
520 if (n <= bytes_to_rdwr)
521 bytes_to_rdwr -= n;
522 else {
523 errx(EX_DATAERR, "ERROR extra data write %zd %d\n", n, bytes_to_rdwr);
524 }
525 }
526 bytes_to_rdwr = rsplen;
527 while (bytes_to_rdwr) {
528 if (verbose) {
529 ts_print();
530 printf("reading %d bytes\n", rsplen);
531 }
532 n = read(sockfd, buffer3, rsplen);
d9520f62 533
342c141e
A
534 if (n <= 0) {
535 err(EX_OSERR, "ERROR reading from socket");
536 }
537 if (n <= bytes_to_rdwr)
538 bytes_to_rdwr -= n;
539 else {
540 errx(EX_DATAERR, "ERROR extra bytes read n:%zd expected:%d\n", n, bytes_to_rdwr);
541 }
542 }
543 bytes_to_rdwr = reqlen;
544 ntimes--;
545 iter++;
546 }
d9520f62 547
342c141e 548 printf("client: Req size %d Rsp size %d Read/Write %d times \n", reqlen, rsplen, iter);
d9520f62 549
342c141e 550 showmpinfo(sockfd);
d9520f62
A
551
552 if (verbose) {
553 ts_print();
554 printf("close(%d)\n", sockfd);
342c141e 555 }
d9520f62
A
556 close(sockfd);
557
558 freeaddrinfo(ares);
342c141e
A
559 if (altres)
560 freeaddrinfo(altres);
561 return 0;
562}
563
564#define CIF_BITS \
565"\020\1CONNECTING\2CONNECTED\3DISCONNECTING\4DISCONNECTED\5BOUND_IF"\
566"\6BOUND_IP\7BOUND_PORT\10PREFERRED\11MP_CAPABLE\12MP_READY" \
567"\13MP_DEGRADED"
568
569/*
570 * Print a value a la the %b format of the kernel's printf
571 */
572static void
573printb(const char *s, unsigned v, const char *bits)
574{
575 int i, any = 0;
576 char c;
d9520f62 577
342c141e
A
578 if (bits && *bits == 8)
579 printf("%s=%o", s, v);
580 else
581 printf("%s=%x", s, v);
582 bits++;
583 if (bits) {
584 putchar('<');
585 while ((i = *bits++) != '\0') {
586 if (v & (1 << (i-1))) {
587 if (any)
588 putchar(',');
589 any = 1;
590 for (; (c = *bits) > 32; bits++)
591 putchar(c);
592 } else {
593 for (; *bits > 32; bits++)
594 ;
595 }
596 }
597 putchar('>');
598 }
599}
600
601static int
89c4ed63 602showconninfo(int s, sae_connid_t cid)
342c141e
A
603{
604 char buf[INET6_ADDRSTRLEN];
605 conninfo_t *cfo = NULL;
606 int err;
d9520f62 607
342c141e
A
608 err = copyconninfo(s, cid, &cfo);
609 if (err != 0) {
610 printf("getconninfo failed for cid %d\n", cid);
611 goto out;
612 }
d9520f62 613
342c141e
A
614 printf("%6d:\t", cid);
615 printb("flags", cfo->ci_flags, CIF_BITS);
616 printf("\n");
d9520f62 617
342c141e
A
618 if (cfo->ci_src != NULL) {
619 printf("\tsrc %s port %d\n", inet_ntop(cfo->ci_src->sa_family,
620 (cfo->ci_src->sa_family == AF_INET) ?
621 (void *)&((struct sockaddr_in *)cfo->ci_src)->
622 sin_addr.s_addr :
623 (void *)&((struct sockaddr_in6 *)cfo->ci_src)->sin6_addr,
624 buf, sizeof (buf)),
625 (cfo->ci_src->sa_family == AF_INET) ?
626 ntohs(((struct sockaddr_in *)cfo->ci_src)->sin_port) :
627 ntohs(((struct sockaddr_in6 *)cfo->ci_src)->sin6_port));
628 }
629 if (cfo->ci_dst != NULL) {
630 printf("\tdst %s port %d\n", inet_ntop(cfo->ci_dst->sa_family,
631 (cfo->ci_dst->sa_family == AF_INET) ?
632 (void *)&((struct sockaddr_in *)cfo->ci_dst)->
633 sin_addr.s_addr :
634 (void *)&((struct sockaddr_in6 *)cfo->ci_dst)->sin6_addr,
635 buf, sizeof (buf)),
636 (cfo->ci_dst->sa_family == AF_INET) ?
637 ntohs(((struct sockaddr_in *)cfo->ci_dst)->sin_port) :
638 ntohs(((struct sockaddr_in6 *)cfo->ci_dst)->sin6_port));
639 }
640 if (cfo->ci_aux_data != NULL) {
641 switch (cfo->ci_aux_type) {
642 case CIAUX_TCP:
643 printf("\tTCP aux info available\n");
644 break;
645 default:
646 printf("\tUnknown aux type %d\n", cfo->ci_aux_type);
647 break;
648 }
649 }
342c141e
A
650out:
651 if (cfo != NULL)
652 freeconninfo(cfo);
d9520f62 653
342c141e
A
654 return (err);
655}
656
657static void
658showmpinfo(int s)
659{
89c4ed63
A
660 uint32_t aid_cnt = 0, cid_cnt = 0;
661 sae_associd_t *aid = NULL;
662 sae_connid_t *cid = NULL;
663 int i, error = 0;
d9520f62 664
342c141e
A
665 error = copyassocids(s, &aid, &aid_cnt);
666 if (error != 0) {
667 printf("copyassocids failed\n");
668 goto done;
669 } else {
670 printf("found %d associations", aid_cnt);
671 if (aid_cnt > 0) {
672 printf(" with IDs:");
673 for (i = 0; i < aid_cnt; i++)
674 printf(" %d\n", aid[i]);
675 }
676 printf("\n");
677 }
d9520f62 678
342c141e 679 /* just do an association for now */
89c4ed63 680 error = copyconnids(s, SAE_ASSOCID_ANY, &cid, &cid_cnt);
342c141e
A
681 if (error != 0) {
682 warn("getconnids failed\n");
683 goto done;
684 } else {
685 printf("found %d connections", cid_cnt);
686 if (cid_cnt > 0) {
687 printf(":\n");
688 for (i = 0; i < cid_cnt; i++) {
689 if (showconninfo(s, cid[i]) != 0)
690 break;
691 }
692 }
693 printf("\n");
694 }
d9520f62 695
342c141e
A
696done:
697 if (aid != NULL)
698 freeassocids(aid);
699 if (cid != NULL)
700 freeconnids(cid);
701}