xref: /dragonfly/usr.bin/netstat/if.c (revision 10f4bf95)
1 /*
2  * Copyright (c) 1983, 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)if.c	8.3 (Berkeley) 4/28/95
34  * $FreeBSD: src/usr.bin/netstat/if.c,v 1.32.2.9 2001/09/17 14:35:46 ru Exp $
35  * $DragonFly: src/usr.bin/netstat/if.c,v 1.12 2008/03/07 11:34:21 sephe Exp $
36  */
37 
38 #define _KERNEL_STRUCTURES
39 #include <sys/param.h>
40 #include <sys/protosw.h>
41 #include <sys/socket.h>
42 #include <sys/sysctl.h>
43 #include <sys/time.h>
44 
45 #include <net/if.h>
46 #include <net/if_var.h>
47 #include <net/if_dl.h>
48 #include <net/if_types.h>
49 #include <net/ethernet.h>
50 #include <netinet/in.h>
51 #include <netinet/in_var.h>
52 #include <netproto/ipx/ipx.h>
53 #include <netproto/ipx/ipx_if.h>
54 #ifdef ISO
55 #include <netiso/iso.h>
56 #include <netiso/iso_var.h>
57 #endif
58 #include <arpa/inet.h>
59 
60 #include <signal.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <unistd.h>
65 
66 #include "netstat.h"
67 
68 #define	YES	1
69 #define	NO	0
70 
71 static void sidewaysintpr (u_int, u_long);
72 static void catchalarm (int);
73 
74 #ifdef INET6
75 static char ntop_buf[INET6_ADDRSTRLEN];		/* for inet_ntop() */
76 #endif
77 
78 
79 /*
80  * Display a formatted value, or a '-' in the same space.
81  */
82 static void
83 show_stat(const char *fmt, int width, u_long value, short showvalue)
84 {
85 	char newfmt[32];
86 
87 	/* Construct the format string */
88 	if (showvalue) {
89 		sprintf(newfmt, "%%%d%s", width, fmt);
90 		printf(newfmt, value);
91 	} else {
92 		sprintf(newfmt, "%%%ds", width);
93 		printf(newfmt, "-");
94 	}
95 }
96 
97 
98 
99 /*
100  * Print a description of the network interfaces.
101  */
102 void
103 intpr(int interval1, u_long ifnetaddr, void (*pfunc)(char *))
104 {
105 	struct ifnet ifnet;
106 	struct ifaddr_container ifac;
107 	struct ifnethead ifnethead;
108 	union {
109 		struct ifaddr ifa;
110 		struct in_ifaddr in;
111 #ifdef INET6
112 		struct in6_ifaddr in6;
113 #endif
114 		struct ipx_ifaddr ipx;
115 #ifdef ISO
116 		struct iso_ifaddr iso;
117 #endif
118 	} ifaddr;
119 	u_long ifaddraddr;
120 	u_long ifaddrcont_addr;
121 	u_long ifaddrfound;
122 	u_long ifnetfound;
123 	u_long opackets;
124 	u_long ipackets;
125 	u_long obytes;
126 	u_long ibytes;
127 	u_long oerrors;
128 	u_long ierrors;
129 	u_long collisions;
130 	short timer;
131 	int drops;
132 	struct sockaddr *sa = NULL;
133 	char name[IFNAMSIZ];
134 	short network_layer;
135 	short link_layer;
136 
137 	if (ifnetaddr == 0) {
138 		printf("ifnet: symbol not defined\n");
139 		return;
140 	}
141 	if (interval1) {
142 		sidewaysintpr((unsigned)interval1, ifnetaddr);
143 		return;
144 	}
145 	if (kread(ifnetaddr, (char *)&ifnethead, sizeof ifnethead))
146 		return;
147 	ifnetaddr = (u_long)TAILQ_FIRST(&ifnethead);
148 	if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
149 		return;
150 
151 	if (!pfunc) {
152 		printf("%-7.7s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
153 		       "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
154 		if (bflag)
155 			printf(" %10.10s","Ibytes");
156 		printf(" %8.8s %5.5s", "Opkts", "Oerrs");
157 		if (bflag)
158 			printf(" %10.10s","Obytes");
159 		printf(" %5s", "Coll");
160 		if (tflag)
161 			printf(" %s", "Time");
162 		if (dflag)
163 			printf(" %s", "Drop");
164 		putchar('\n');
165 	}
166 	ifaddraddr = 0;
167 	while (ifnetaddr || ifaddraddr) {
168 		struct sockaddr_in *sin;
169 #ifdef INET6
170 		struct sockaddr_in6 *sin6;
171 #endif
172 		char *cp;
173 		int n, m;
174 
175 		network_layer = 0;
176 		link_layer = 0;
177 
178 		if (ifaddraddr == 0) {
179 			struct ifaddrhead head;
180 
181 			ifnetfound = ifnetaddr;
182 			if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
183 				return;
184 			strlcpy(name, ifnet.if_xname, sizeof(name));
185 			ifnetaddr = (u_long)TAILQ_NEXT(&ifnet, if_link);
186 			if (interface != 0 && (strcmp(name, interface) != 0))
187 				continue;
188 			cp = strchr(name, '\0');
189 
190 			if (pfunc) {
191 				(*pfunc)(name);
192 				continue;
193 			}
194 
195 			if ((ifnet.if_flags&IFF_UP) == 0)
196 				*cp++ = '*';
197 			*cp = '\0';
198 
199 			if (kread((u_long)ifnet.if_addrheads,
200 				  (char *)&head, sizeof(head)))
201 				return;
202 
203 			ifaddrcont_addr =
204 				(u_long)TAILQ_FIRST(&head);
205 			if (ifaddrcont_addr == 0) {
206 				ifaddraddr = 0;
207 			} else {
208 				if (kread(ifaddrcont_addr, (char *)&ifac,
209 					  sizeof(ifac)))
210 					return;
211 				ifaddraddr = (u_long)ifac.ifa;
212 			}
213 		}
214 		ifaddrfound = ifaddraddr;
215 
216 		/*
217 		 * Get the interface stats.  These may get
218 		 * overriden below on a per-interface basis.
219 		 */
220 		opackets = ifnet.if_opackets;
221 		ipackets = ifnet.if_ipackets;
222 		obytes = ifnet.if_obytes;
223 		ibytes = ifnet.if_ibytes;
224 		oerrors = ifnet.if_oerrors;
225 		ierrors = ifnet.if_ierrors;
226 		collisions = ifnet.if_collisions;
227 		timer = ifnet.if_timer;
228 		drops = ifnet.if_snd.ifq_drops;
229 
230 		if (ifaddraddr == 0) {
231 			printf("%-7.7s %-5lu ", name, ifnet.if_mtu);
232 			printf("%-13.13s ", "none");
233 			printf("%-15.15s ", "none");
234 		} else {
235 			if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) {
236 				ifaddraddr = 0;
237 				continue;
238 			}
239 #define CP(x) ((char *)(x))
240 			cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) +
241 				CP(&ifaddr);
242 			sa = (struct sockaddr *)cp;
243 			if (af != AF_UNSPEC && sa->sa_family != af) {
244 				ifaddrcont_addr =
245 					(u_long)TAILQ_NEXT(&ifac, ifa_link);
246 				if (ifaddrcont_addr == 0) {
247 					ifaddraddr = 0;
248 				} else {
249 					if (kread(ifaddrcont_addr,
250 					    (char *)&ifac, sizeof(ifac))) {
251 						ifaddraddr = 0;
252 						continue;
253 					}
254 					ifaddraddr = (u_long)ifac.ifa;
255 				}
256 				continue;
257 			}
258 			printf("%-7.7s %-5lu ", name, ifnet.if_mtu);
259 			switch (sa->sa_family) {
260 			case AF_UNSPEC:
261 				printf("%-13.13s ", "none");
262 				printf("%-15.15s ", "none");
263 				break;
264 			case AF_INET:
265 				sin = (struct sockaddr_in *)sa;
266 #ifdef notdef
267 				/* can't use inet_makeaddr because kernel
268 				 * keeps nets unshifted.
269 				 */
270 				in = inet_makeaddr(ifaddr.in.ia_subnet,
271 					INADDR_ANY);
272 				printf("%-13.13s ", netname(in.s_addr,
273 				    ifaddr.in.ia_subnetmask));
274 #else
275 				printf("%-13.13s ",
276 				    netname(htonl(ifaddr.in.ia_subnet),
277 				    ifaddr.in.ia_subnetmask));
278 #endif
279 				printf("%-15.15s ",
280 				    routename(sin->sin_addr.s_addr));
281 
282 				network_layer = 1;
283 				break;
284 #ifdef INET6
285 			case AF_INET6:
286 				sin6 = (struct sockaddr_in6 *)sa;
287 				printf("%-11.11s ",
288 				       netname6(&ifaddr.in6.ia_addr,
289 						&ifaddr.in6.ia_prefixmask.sin6_addr));
290 				printf("%-17.17s ",
291 				    inet_ntop(AF_INET6,
292 					&sin6->sin6_addr,
293 					ntop_buf, sizeof(ntop_buf)));
294 
295 				network_layer = 1;
296 				break;
297 #endif /*INET6*/
298 			case AF_IPX:
299 				{
300 				struct sockaddr_ipx *sipx =
301 					(struct sockaddr_ipx *)sa;
302 				u_long net;
303 				char netnum[10];
304 
305 				*(union ipx_net *) &net = sipx->sipx_addr.x_net;
306 				sprintf(netnum, "%lx", (u_long)ntohl(net));
307 				printf("ipx:%-8s  ", netnum);
308 /*				printf("ipx:%-8s ", netname(net, 0L)); */
309 				printf("%-15s ",
310 				    ipx_phost((struct sockaddr *)sipx));
311 				}
312 				break;
313 
314 			case AF_APPLETALK:
315 				printf("atalk:%-12.12s ",atalk_print(sa,0x10) );
316 				printf("%-9.9s  ",atalk_print(sa,0x0b) );
317 				break;
318 			case AF_LINK:
319 				{
320 				struct sockaddr_dl *sdl =
321 					(struct sockaddr_dl *)sa;
322 				char linknum[10];
323 				cp = (char *)LLADDR(sdl);
324 				n = sdl->sdl_alen;
325 				sprintf(linknum, "<Link#%d>", sdl->sdl_index);
326 				m = printf("%-11.11s ", linknum);
327 				}
328 				goto hexprint;
329 			default:
330 				m = printf("(%d)", sa->sa_family);
331 				for (cp = sa->sa_len + (char *)sa;
332 					--cp > sa->sa_data && (*cp == 0);) {}
333 				n = cp - sa->sa_data + 1;
334 				cp = sa->sa_data;
335 			hexprint:
336 				while (--n >= 0)
337 					m += printf("%02x%c", *cp++ & 0xff,
338 						    n > 0 ? ':' : ' ');
339 				m = 30 - m;
340 				while (m-- > 0)
341 					putchar(' ');
342 
343 				link_layer = 1;
344 				break;
345 			}
346 
347 			/*
348 			 * Fixup the statistics for interfaces that
349 			 * update stats for their network addresses
350 			 */
351 			if (network_layer) {
352 				opackets = ifaddr.in.ia_ifa.if_opackets;
353 				ipackets = ifaddr.in.ia_ifa.if_ipackets;
354 				obytes = ifaddr.in.ia_ifa.if_obytes;
355 				ibytes = ifaddr.in.ia_ifa.if_ibytes;
356 			}
357 
358 			ifaddrcont_addr =
359 				(u_long)TAILQ_NEXT(&ifac, ifa_link);
360 			if (ifaddrcont_addr == 0) {
361 				ifaddraddr = 0;
362 			} else {
363 				if (kread(ifaddrcont_addr,
364 				    (char *)&ifac, sizeof(ifac))) {
365 					ifaddraddr = 0;
366 				} else {
367 					ifaddraddr = (u_long)ifac.ifa;
368 				}
369 			}
370 		}
371 
372 		show_stat("lu", 8, ipackets, link_layer|network_layer);
373 		printf(" ");
374 		show_stat("lu", 5, ierrors, link_layer);
375 		printf(" ");
376 		if (bflag) {
377 			show_stat("lu", 10, ibytes, link_layer|network_layer);
378 			printf(" ");
379 		}
380 		show_stat("lu", 8, opackets, link_layer|network_layer);
381 		printf(" ");
382 		show_stat("lu", 5, oerrors, link_layer);
383 		printf(" ");
384 		if (bflag) {
385 			show_stat("lu", 10, obytes, link_layer|network_layer);
386 			printf(" ");
387 		}
388 		show_stat("lu", 5, collisions, link_layer);
389 		if (tflag) {
390 			printf(" ");
391 			show_stat("d", 3, timer, link_layer);
392 		}
393 		if (dflag) {
394 			printf(" ");
395 			show_stat("d", 3, drops, link_layer);
396 		}
397 		putchar('\n');
398 		if (aflag && ifaddrfound) {
399 			/*
400 			 * Print family's multicast addresses
401 			 */
402 			struct ifmultiaddr *multiaddr;
403 			struct ifmultiaddr ifma;
404 			union {
405 				struct sockaddr sa;
406 				struct sockaddr_in in;
407 #ifdef INET6
408 				struct sockaddr_in6 in6;
409 #endif /* INET6 */
410 				struct sockaddr_dl dl;
411 			} msa;
412 			const char *fmt;
413 
414 			TAILQ_FOREACH(multiaddr, &ifnet.if_multiaddrs, ifma_link) {
415 				if (kread((u_long)multiaddr, (char *)&ifma,
416 					  sizeof ifma))
417 					break;
418 				multiaddr = &ifma;
419 				if (kread((u_long)ifma.ifma_addr, (char *)&msa,
420 					  sizeof msa))
421 					break;
422 				if (msa.sa.sa_family != sa->sa_family)
423 					continue;
424 
425 				fmt = 0;
426 				switch (msa.sa.sa_family) {
427 				case AF_INET:
428 					fmt = routename(msa.in.sin_addr.s_addr);
429 					break;
430 #ifdef INET6
431 				case AF_INET6:
432 					printf("%23s %-19.19s(refs: %d)\n", "",
433 					       inet_ntop(AF_INET6,
434 							 &msa.in6.sin6_addr,
435 							 ntop_buf,
436 							 sizeof(ntop_buf)),
437 					       ifma.ifma_refcount);
438 					break;
439 #endif /* INET6 */
440 				case AF_LINK:
441 					switch (msa.dl.sdl_type) {
442 					case IFT_ETHER:
443 					case IFT_FDDI:
444 						fmt = ether_ntoa(
445 							(struct ether_addr *)
446 							LLADDR(&msa.dl));
447 						break;
448 					}
449 					break;
450 				}
451 				if (fmt)
452 					printf("%23s %s\n", "", fmt);
453 			}
454 		}
455 	}
456 }
457 
458 struct	iftot {
459 	SLIST_ENTRY(iftot) chain;
460 	char	ift_name[IFNAMSIZ];	/* interface name */
461 	u_long	ift_ip;			/* input packets */
462 	u_long	ift_ie;			/* input errors */
463 	u_long	ift_op;			/* output packets */
464 	u_long	ift_oe;			/* output errors */
465 	u_long	ift_co;			/* collisions */
466 	u_int	ift_dr;			/* drops */
467 	u_long	ift_ib;			/* input bytes */
468 	u_long	ift_ob;			/* output bytes */
469 };
470 
471 u_char	signalled;			/* set if alarm goes off "early" */
472 
473 /*
474  * Print a running summary of interface statistics.
475  * Repeat display every interval1 seconds, showing statistics
476  * collected over that interval.  Assumes that interval1 is non-zero.
477  * First line printed at top of screen is always cumulative.
478  * XXX - should be rewritten to use ifmib(4).
479  */
480 static void
481 sidewaysintpr(unsigned interval1, u_long off)
482 {
483 	struct ifnet ifnet;
484 	u_long firstifnet;
485 	struct ifnethead ifnethead;
486 	struct iftot *iftot, *ip, *ipn, *total, *sum, *interesting;
487 	int line;
488 	int oldmask, first;
489 	u_long interesting_off;
490 
491 	if (kread(off, (char *)&ifnethead, sizeof ifnethead))
492 		return;
493 	firstifnet = (u_long)TAILQ_FIRST(&ifnethead);
494 
495 	if ((iftot = malloc(sizeof(struct iftot))) == NULL) {
496 		printf("malloc failed\n");
497 		exit(1);
498 	}
499 	memset(iftot, 0, sizeof(struct iftot));
500 
501 	interesting = NULL;
502 	interesting_off = 0;
503 	for (off = firstifnet, ip = iftot; off;) {
504 		char name[IFNAMSIZ];
505 
506 		if (kread(off, (char *)&ifnet, sizeof ifnet))
507 			break;
508 		strlcpy(name, ifnet.if_xname, sizeof(name));
509 		if (interface && strcmp(name, interface) == 0) {
510 			interesting = ip;
511 			interesting_off = off;
512 		}
513 		snprintf(ip->ift_name, 16, "(%s)", name);
514 		if ((ipn = malloc(sizeof(struct iftot))) == NULL) {
515 			printf("malloc failed\n");
516 			exit(1);
517 		}
518 		memset(ipn, 0, sizeof(struct iftot));
519 		SLIST_NEXT(ip, chain) = ipn;
520 		ip = ipn;
521 		off = (u_long)TAILQ_NEXT(&ifnet, if_link);
522 	}
523 	if ((total = malloc(sizeof(struct iftot))) == NULL) {
524 		printf("malloc failed\n");
525 		exit(1);
526 	}
527 	memset(total, 0, sizeof(struct iftot));
528 	if ((sum = malloc(sizeof(struct iftot))) == NULL) {
529 		printf("malloc failed\n");
530 		exit(1);
531 	}
532 	memset(sum, 0, sizeof(struct iftot));
533 
534 
535 	(void)signal(SIGALRM, catchalarm);
536 	signalled = NO;
537 	(void)alarm(interval1);
538 	first = 1;
539 banner:
540 	printf("%17s %14s %16s", "input",
541 	    interesting ? interesting->ift_name : "(Total)", "output");
542 	putchar('\n');
543 	printf("%10s %5s %10s %10s %5s %10s %5s",
544 	    "packets", "errs", "bytes", "packets", "errs", "bytes", "colls");
545 	if (dflag)
546 		printf(" %5.5s", "drops");
547 	putchar('\n');
548 	fflush(stdout);
549 	line = 0;
550 loop:
551 	if (interesting != NULL) {
552 		ip = interesting;
553 		if (kread(interesting_off, (char *)&ifnet, sizeof ifnet)) {
554 			printf("???\n");
555 			exit(1);
556 		};
557 		if (!first) {
558 			printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
559 				ifnet.if_ipackets - ip->ift_ip,
560 				ifnet.if_ierrors - ip->ift_ie,
561 				ifnet.if_ibytes - ip->ift_ib,
562 				ifnet.if_opackets - ip->ift_op,
563 				ifnet.if_oerrors - ip->ift_oe,
564 				ifnet.if_obytes - ip->ift_ob,
565 				ifnet.if_collisions - ip->ift_co);
566 			if (dflag)
567 				printf(" %5u", ifnet.if_snd.ifq_drops - ip->ift_dr);
568 		}
569 		ip->ift_ip = ifnet.if_ipackets;
570 		ip->ift_ie = ifnet.if_ierrors;
571 		ip->ift_ib = ifnet.if_ibytes;
572 		ip->ift_op = ifnet.if_opackets;
573 		ip->ift_oe = ifnet.if_oerrors;
574 		ip->ift_ob = ifnet.if_obytes;
575 		ip->ift_co = ifnet.if_collisions;
576 		ip->ift_dr = ifnet.if_snd.ifq_drops;
577 	} else {
578 		sum->ift_ip = 0;
579 		sum->ift_ie = 0;
580 		sum->ift_ib = 0;
581 		sum->ift_op = 0;
582 		sum->ift_oe = 0;
583 		sum->ift_ob = 0;
584 		sum->ift_co = 0;
585 		sum->ift_dr = 0;
586 		for (off = firstifnet, ip = iftot;
587 		     off && SLIST_NEXT(ip, chain) != NULL;
588 		     ip = SLIST_NEXT(ip, chain)) {
589 			if (kread(off, (char *)&ifnet, sizeof ifnet)) {
590 				off = 0;
591 				continue;
592 			}
593 			sum->ift_ip += ifnet.if_ipackets;
594 			sum->ift_ie += ifnet.if_ierrors;
595 			sum->ift_ib += ifnet.if_ibytes;
596 			sum->ift_op += ifnet.if_opackets;
597 			sum->ift_oe += ifnet.if_oerrors;
598 			sum->ift_ob += ifnet.if_obytes;
599 			sum->ift_co += ifnet.if_collisions;
600 			sum->ift_dr += ifnet.if_snd.ifq_drops;
601 			off = (u_long)TAILQ_NEXT(&ifnet, if_link);
602 		}
603 		if (!first) {
604 			printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
605 				sum->ift_ip - total->ift_ip,
606 				sum->ift_ie - total->ift_ie,
607 				sum->ift_ib - total->ift_ib,
608 				sum->ift_op - total->ift_op,
609 				sum->ift_oe - total->ift_oe,
610 				sum->ift_ob - total->ift_ob,
611 				sum->ift_co - total->ift_co);
612 			if (dflag)
613 				printf(" %5u", sum->ift_dr - total->ift_dr);
614 		}
615 		*total = *sum;
616 	}
617 	if (!first)
618 		putchar('\n');
619 	fflush(stdout);
620 	oldmask = sigblock(sigmask(SIGALRM));
621 	if (! signalled) {
622 		sigpause(0);
623 	}
624 	sigsetmask(oldmask);
625 	signalled = NO;
626 	(void)alarm(interval1);
627 	line++;
628 	first = 0;
629 	if (line == 21)
630 		goto banner;
631 	else
632 		goto loop;
633 	/*NOTREACHED*/
634 }
635 
636 /*
637  * Called if an interval expires before sidewaysintpr has completed a loop.
638  * Sets a flag to not wait for the alarm.
639  */
640 static void
641 catchalarm(int signo __unused)
642 {
643 	signalled = YES;
644 }
645