[Midnightbsd-cvs] src: sbin/dmesg: Update dhclient, merge changes to userland (ifconfig)

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Fri Nov 21 09:49:05 EST 2008


Log Message:
-----------
Update dhclient, merge changes to userland (ifconfig)

Modified Files:
--------------
    src/sbin/dhclient:
        alloc.c (r1.1.1.1 -> r1.2)
        bpf.c (r1.2 -> r1.3)
        clparse.c (r1.1.1.1 -> r1.2)
        conflex.c (r1.1.1.1 -> r1.2)
        convert.c (r1.1.1.1 -> r1.2)
        dhclient-script (r1.3 -> r1.4)
        dhclient.8 (r1.1.1.2 -> r1.2)
        dhclient.c (r1.4 -> r1.5)
        dhclient.conf (r1.1.1.1 -> r1.2)
        dhcp-options.5 (r1.1.1.2 -> r1.2)
        dhcp.h (r1.1.1.1 -> r1.2)
        dispatch.c (r1.2 -> r1.3)
        errwarn.c (r1.1.1.1 -> r1.2)
        hash.c (r1.1.1.1 -> r1.2)
        inet.c (r1.1.1.1 -> r1.2)
        options.c (r1.1.1.1 -> r1.2)
        packet.c (r1.1.1.1 -> r1.2)
        parse.c (r1.2 -> r1.3)
        privsep.c (r1.1.1.1 -> r1.2)
        tables.c (r1.1.1.1 -> r1.2)
        tree.c (r1.1.1.1 -> r1.2)
    src/sbin/dmesg:
        Makefile (r1.1.1.1 -> r1.2)
        dmesg.8 (r1.1.1.1 -> r1.2)
        dmesg.c (r1.2 -> r1.3)
    src/sbin/ifconfig:
        Makefile (r1.1.1.1 -> r1.2)
        af_atalk.c (r1.1.1.1 -> r1.2)
        af_inet.c (r1.1.1.1 -> r1.2)
        af_inet6.c (r1.1.1.1 -> r1.2)
        af_ipx.c (r1.1.1.1 -> r1.2)
        af_link.c (r1.1.1.1 -> r1.2)
        ifbridge.c (r1.1.1.2 -> r1.2)
        ifclone.c (r1.1.1.1 -> r1.2)
        ifconfig.8 (r1.2 -> r1.3)
        ifconfig.c (r1.2 -> r1.3)
        ifconfig.h (r1.1.1.1 -> r1.2)
        ifieee80211.c (r1.2 -> r1.3)
        ifmedia.c (r1.2 -> r1.3)
        ifpfsync.c (r1.1.1.1 -> r1.2)
        ifvlan.c (r1.2 -> r1.3)

Added Files:
-----------
    src/sbin/ifconfig:
        ifgroup.c (r1.1)
        iflagg.c (r1.1)

-------------- next part --------------
Index: dhclient-script
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/dhclient-script,v
retrieving revision 1.3
retrieving revision 1.4
diff -L sbin/dhclient/dhclient-script -L sbin/dhclient/dhclient-script -u -r1.3 -r1.4
--- sbin/dhclient/dhclient-script
+++ sbin/dhclient/dhclient-script
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # $OpenBSD: dhclient-script,v 1.6 2004/05/06 18:22:41 claudio Exp $
-# $FreeBSD: src/sbin/dhclient/dhclient-script,v 1.4.2.3 2006/01/24 06:01:59 brooks Exp $
+# $FreeBSD: src/sbin/dhclient/dhclient-script,v 1.17 2007/07/03 17:49:32 thompsa Exp $
 #
 # Copyright (c) 2003 Kenneth R Westerback <krw at openbsd.org>
 #
@@ -22,6 +22,7 @@
 ARP=/usr/sbin/arp
 AWK=/usr/bin/awk
 HOSTNAME=/bin/hostname
+IFCONFIG='/sbin/ifconfig -n'
 NETSTAT=/usr/bin/netstat
 
 LOCALHOST=127.0.0.1
@@ -55,11 +56,11 @@
 }
 
 delete_old_address() {
-	eval "ifconfig $interface inet -alias $old_ip_address $medium"
+	eval "$IFCONFIG $interface inet -alias $old_ip_address $medium"
 }
 
 add_new_address() {
-	eval "ifconfig $interface \
+	eval "$IFCONFIG $interface \
 		inet $new_ip_address \
 		netmask $new_subnet_mask \
 		broadcast $new_broadcast_address \
@@ -73,21 +74,56 @@
 
 delete_old_alias() {
 	if [ -n "$alias_ip_address" ]; then
-		ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1
+		$IFCONFIG $interface inet -alias $alias_ip_address > /dev/null 2>&1
 		#route delete $alias_ip_address $LOCALHOST > /dev/null 2>&1
 	fi
 }
 
 add_new_alias() {
 	if [ -n "$alias_ip_address" ]; then
-		ifconfig $interface inet alias $alias_ip_address netmask \
+		$IFCONFIG $interface inet alias $alias_ip_address netmask \
 		    $alias_subnet_mask
 		#route add $alias_ip_address $LOCALHOST
 	fi
 }
 
+fill_classless_routes() {
+	set $1
+	while [ $# -ge 5 ]; do
+		if [ $1 -eq 0 ]; then
+			route="default"
+		elif [ $1 -le 8 ]; then
+			route="$2.0.0.0/$1"
+			shift
+		elif [ $1 -le 16 ]; then
+			route="$2.$3.0.0/$1"
+			shift; shift
+		elif [ $1 -le 24 ]; then
+			route="$2.$3.$4.0/$1"
+			shift; shift; shift
+		else
+			route="$2.$3.$4.$5/$1"
+			shift; shift; shift; shift
+		fi
+		shift
+		router="$1.$2.$3.$4"
+		classless_routes="$classless_routes $route $router"
+		shift; shift; shift; shift
+	done
+}
+
 delete_old_routes() {
 	#route delete "$old_ip_address" $LOCALHOST >/dev/null 2>&1
+	if [ -n "$old_classless_routes" ]; then
+		fill_classless_routes "$old_classless_routes"
+		set $classless_routes
+		while [ $# -gt 1 ]; do
+			route delete "$1" "$2"
+			shift; shift
+		done
+		return 0;
+	fi
+
 	for router in $old_routers; do
 		if [ $if_defaultroute = x -o $if_defaultroute = $interface ]; then
 			route delete default $route >/dev/null 2>&1
@@ -107,6 +143,31 @@
 
 add_new_routes() {
 	#route add $new_ip_address $LOCALHOST >/dev/null 2>&1
+
+	# RFC 3442: If the DHCP server returns both a Classless Static
+	# Routes option and a Router option, the DHCP client MUST ignore
+	# the Router option.
+	#
+	# DHCP clients that support this option (Classless Static Routes)
+	# MUST NOT install the routes specified in the Static Routes
+	# option (option code 33) if both a Static Routes option and the
+	# Classless Static Routes option are provided.
+
+	if [ -n "$new_classless_routes" ]; then
+		fill_classless_routes "$new_classless_routes"
+		$LOGGER "New Classless Static Routes ($interface): $classless_routes"
+		set $classless_routes
+		while [ $# -gt 1 ]; do
+			if [ "0.0.0.0" = "$2" ]; then
+				route add "$1" -iface "$interface"
+			else
+				route add "$1" "$2"
+			fi
+			shift; shift
+		done
+		return
+	fi
+
 	for router in $new_routers; do
 		if [ "$new_ip_address" = "$router" ]; then
 			route add default -iface $router >/dev/null 2>&1
@@ -216,14 +277,14 @@
 
 case $reason in
 MEDIUM)
-	eval "ifconfig $interface $medium"
-	eval "ifconfig $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1
+	eval "$IFCONFIG $interface $medium"
+	eval "$IFCONFIG $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1
 	sleep 1
 	;;
 
 PREINIT)
 	delete_old_alias
-	ifconfig $interface inet alias 0.0.0.0 netmask 0.0.0.0 broadcast 255.255.255.255 up
+	$IFCONFIG $interface inet 0.0.0.0 netmask 0.0.0.0 broadcast 255.255.255.255 up
 	;;
 
 ARPCHECK|ARPSEND)
@@ -286,7 +347,7 @@
 			fi
 		fi
 	fi
-	eval "ifconfig $interface inet -alias $new_ip_address $medium"
+	eval "$IFCONFIG $interface inet -alias $new_ip_address $medium"
 	delete_old_routes
 	exit_with_hooks 1
 	;;
Index: tables.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/tables.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/tables.c -L sbin/dhclient/tables.c -u -r1.1.1.1 -r1.2
--- sbin/dhclient/tables.c
+++ sbin/dhclient/tables.c
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/tables.c,v 1.1.1.1.2.2 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/tables.c,v 1.4 2007/02/09 17:50:26 emaste Exp $");
 
 #include "dhcpd.h"
 
@@ -186,7 +186,7 @@
 	{ "option-118", "X",				&dhcp_universe, 118 },
 	{ "option-119", "X",				&dhcp_universe, 119 },
 	{ "option-120", "X",				&dhcp_universe, 120 },
-	{ "option-121", "X",				&dhcp_universe, 121 },
+	{ "classless-routes", "BA",			&dhcp_universe, 121 },
 	{ "option-122", "X",				&dhcp_universe, 122 },
 	{ "option-123", "X",				&dhcp_universe, 123 },
 	{ "option-124", "X",				&dhcp_universe, 124 },
@@ -337,6 +337,7 @@
 	DHO_DHCP_CLIENT_IDENTIFIER,
 	DHO_SUBNET_MASK,
 	DHO_TIME_OFFSET,
+	DHO_CLASSLESS_ROUTES,
 	DHO_ROUTERS,
 	DHO_TIME_SERVERS,
 	DHO_NAME_SERVERS,
@@ -392,7 +393,7 @@
 	78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
 	93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
 	107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118,
-	119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
+	119, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130,
 	131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
 	143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
 	155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
Index: alloc.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/alloc.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/alloc.c -L sbin/dhclient/alloc.c -u -r1.1.1.1 -r1.2
--- sbin/dhclient/alloc.c
+++ sbin/dhclient/alloc.c
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/alloc.c,v 1.1.1.1.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/alloc.c,v 1.2 2005/08/23 23:59:55 brooks Exp $");
 
 #include "dhcpd.h"
 
Index: conflex.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/conflex.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/conflex.c -L sbin/dhclient/conflex.c -u -r1.1.1.1 -r1.2
--- sbin/dhclient/conflex.c
+++ sbin/dhclient/conflex.c
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/conflex.c,v 1.1.1.1.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/conflex.c,v 1.4 2005/08/26 01:25:59 brooks Exp $");
 
 #include <ctype.h>
 
Index: clparse.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/clparse.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/clparse.c -L sbin/dhclient/clparse.c -u -r1.1.1.1 -r1.2
--- sbin/dhclient/clparse.c
+++ sbin/dhclient/clparse.c
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/clparse.c,v 1.1.1.1.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/clparse.c,v 1.3 2007/02/09 17:50:26 emaste Exp $");
 
 #include "dhcpd.h"
 #include "dhctoken.h"
@@ -90,6 +90,8 @@
 	top_level_config.requested_options
 	    [top_level_config.requested_option_count++] = DHO_TIME_OFFSET;
 	top_level_config.requested_options
+	    [top_level_config.requested_option_count++] = DHO_CLASSLESS_ROUTES;
+	top_level_config.requested_options
 	    [top_level_config.requested_option_count++] = DHO_ROUTERS;
 	top_level_config.requested_options
 	    [top_level_config.requested_option_count++] = DHO_DOMAIN_NAME;
Index: options.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/options.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/options.c -L sbin/dhclient/options.c -u -r1.1.1.1 -r1.2
--- sbin/dhclient/options.c
+++ sbin/dhclient/options.c
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/options.c,v 1.1.1.1.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/options.c,v 1.2 2005/08/23 23:59:55 brooks Exp $");
 
 #include <ctype.h>
 
Index: inet.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/inet.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/inet.c -L sbin/dhclient/inet.c -u -r1.1.1.1 -r1.2
--- sbin/dhclient/inet.c
+++ sbin/dhclient/inet.c
@@ -43,7 +43,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/inet.c,v 1.1.1.1.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/inet.c,v 1.2 2005/08/23 23:59:55 brooks Exp $");
 
 #include "dhcpd.h"
 
Index: dhclient.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/dhclient.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -L sbin/dhclient/dhclient.c -L sbin/dhclient/dhclient.c -u -r1.4 -r1.5
--- sbin/dhclient/dhclient.c
+++ sbin/dhclient/dhclient.c
@@ -54,7 +54,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/dhclient.c,v 1.6.2.4 2006/01/24 05:59:27 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/dhclient.c,v 1.21 2007/02/09 17:50:26 emaste Exp $");
 
 #include "dhcpd.h"
 #include "privsep.h"
@@ -115,6 +115,7 @@
 void		 routehandler(struct protocol *);
 void		 usage(void);
 int		 check_option(struct client_lease *l, int option);
+int		 check_classless_option(unsigned char *data, int len);
 int		 ipv4addrs(char * buf);
 int		 res_hnok(const char *dn);
 int		 check_search(const char *srch);
@@ -1461,38 +1462,38 @@
 			    ip->client->config->send_options[i].len;
 			options[i]->timeout = 0xFFFFFFFF;
 		}
+		
+	/* send host name if not set via config file. */
+	char hostname[_POSIX_HOST_NAME_MAX+1];
+	if (!options[DHO_HOST_NAME]) {
+		if (gethostname(hostname, sizeof(hostname)) == 0) {
+			size_t len;
+			char* posDot = strchr(hostname, '.');
+			if (posDot != NULL)
+				len = posDot - hostname;
+			else
+				len = strlen(hostname);
+			options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
+			options[DHO_HOST_NAME]->value = hostname;
+			options[DHO_HOST_NAME]->len = len;
+			options[DHO_HOST_NAME]->buf_size = len;
+			options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
+		}
+	}
 
-		/* send host name if not set via config file. */
-  	        char hostname[_POSIX_HOST_NAME_MAX+1];
-  	        if (!options[DHO_HOST_NAME]) {
-  	                 if (gethostname(hostname, sizeof(hostname)) == 0) {
-  	                         size_t len;
-  	                         char* posDot = strchr(hostname, '.');
-  	                         if (posDot != NULL)
-  	                                 len = posDot - hostname;
-  	                         else
-  	                                 len = strlen(hostname);
-  	                         options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
-  	                         options[DHO_HOST_NAME]->value = hostname;
-  	                         options[DHO_HOST_NAME]->len = len;
-  	                         options[DHO_HOST_NAME]->buf_size = len;
-  	                         options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
-  	                 }
-  	        }
-  	 
-  	        /* set unique client identifier */
-  	        char client_ident[sizeof(struct hardware)];
-  	        if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
-  	                 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
-  	                                 ip->hw_address.hlen : sizeof(client_ident)-1;
-  	                 client_ident[0] = ip->hw_address.htype;
-  	                 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
-  	                 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
-  	                 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
-  	                 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
-  	                 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
-  	                 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
-  	         }
+	/* set unique client identifier */
+	char client_ident[sizeof(struct hardware)];
+	if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
+		int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
+				ip->hw_address.hlen : sizeof(client_ident)-1;
+		client_ident[0] = ip->hw_address.htype;
+		memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); 
+		options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
+	}
 
 	/* Set up the option buffer... */
 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
@@ -1585,38 +1586,38 @@
 			    ip->client->config->send_options[i].len;
 			options[i]->timeout = 0xFFFFFFFF;
 		}
+		
+	/* send host name if not set via config file. */
+	char hostname[_POSIX_HOST_NAME_MAX+1];
+	if (!options[DHO_HOST_NAME]) {
+		if (gethostname(hostname, sizeof(hostname)) == 0) {
+			size_t len;
+			char* posDot = strchr(hostname, '.');
+			if (posDot != NULL)
+				len = posDot - hostname;
+			else
+				len = strlen(hostname);
+			options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
+			options[DHO_HOST_NAME]->value = hostname;
+			options[DHO_HOST_NAME]->len = len;
+			options[DHO_HOST_NAME]->buf_size = len;
+			options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
+		}
+	}
 
-	 /* send host name if not set via config file. */
-  	         char hostname[_POSIX_HOST_NAME_MAX+1];
-  	         if (!options[DHO_HOST_NAME]) {
-  	                 if (gethostname(hostname, sizeof(hostname)) == 0) {
-  	                         size_t len;
-  	                         char* posDot = strchr(hostname, '.');
-  	                         if (posDot != NULL)
-  	                                 len = posDot - hostname;
-  	                         else
-  	                                 len = strlen(hostname);
-  	                         options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
-  	                         options[DHO_HOST_NAME]->value = hostname;
-  	                         options[DHO_HOST_NAME]->len = len;
-  	                         options[DHO_HOST_NAME]->buf_size = len;
-  	                         options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
-  	                 }
-  	         }
-  	 
-  	         /* set unique client identifier */
-  	         char client_ident[sizeof(struct hardware)];
-  	         if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
-  	                 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
-  	                                 ip->hw_address.hlen : sizeof(client_ident)-1;
-  	                 client_ident[0] = ip->hw_address.htype;
-  	                 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
-  	                 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
-  	                 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
-  	                 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
-  	                 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
-  	                 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
-  	         }
+	/* set unique client identifier */
+	char client_ident[sizeof(struct hardware)];
+	if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
+		int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
+				ip->hw_address.hlen : sizeof(client_ident)-1;
+		client_ident[0] = ip->hw_address.htype;
+		memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); 
+		options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
+		options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
+	}
 
 	/* Set up the option buffer... */
 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
@@ -2318,7 +2319,6 @@
 			    sbuf, opbuf);
 			l->options[option].len = 0;
 			free(l->options[option].data);
-			return (0);
 		}
 		return (1);
 	case DHO_DOMAIN_NAME:
@@ -2375,12 +2375,79 @@
 	case DHO_DHCP_USER_CLASS_ID:
 	case DHO_END:
 		return (1);
+	case DHO_CLASSLESS_ROUTES:
+		return (check_classless_option(l->options[option].data,
+		    l->options[option].len));
 	default:
 		warning("unknown dhcp option value 0x%x", option);
 		return (unknown_ok);
 	}
 }
 
+/* RFC 3442 The Classless Static Routes option checks */
+int
+check_classless_option(unsigned char *data, int len)
+{
+	int i = 0;
+	unsigned char width;
+	in_addr_t addr, mask;
+
+	if (len < 5) {
+		warning("Too small length: %d", len);
+		return (0);
+	}
+	while(i < len) {
+		width = data[i++];
+		if (width == 0) {
+			i += 4;
+			continue;
+		} else if (width < 9) {
+			addr =  (in_addr_t)(data[i] 	<< 24);
+			i += 1;
+		} else if (width < 17) {
+			addr =  (in_addr_t)(data[i] 	<< 24) +
+				(in_addr_t)(data[i + 1]	<< 16);
+			i += 2;
+		} else if (width < 25) {
+			addr =  (in_addr_t)(data[i] 	<< 24) +
+				(in_addr_t)(data[i + 1]	<< 16) +
+				(in_addr_t)(data[i + 2]	<< 8);
+			i += 3;
+		} else if (width < 33) {
+			addr =  (in_addr_t)(data[i] 	<< 24) +
+				(in_addr_t)(data[i + 1]	<< 16) +
+				(in_addr_t)(data[i + 2]	<< 8)  +
+				data[i + 3];
+			i += 4;
+		} else {
+			warning("Incorrect subnet width: %d", width);
+			return (0);
+		}
+		mask = (in_addr_t)(~0) << (32 - width);
+		addr = ntohl(addr);
+		mask = ntohl(mask);
+
+		/*
+		 * From RFC 3442:
+		 * ... After deriving a subnet number and subnet mask
+		 * from each destination descriptor, the DHCP client
+		 * MUST zero any bits in the subnet number where the
+		 * corresponding bit in the mask is zero...
+		 */
+		if ((addr & mask) != addr) {
+			addr &= mask;
+			data[i - 1] = (unsigned char)(
+				(addr >> (((32 - width)/8)*8)) & 0xFF);
+		} 
+		i += 4;
+	}
+	if (i > len) {
+		warning("Incorrect data length: %d (must be %d)", len, i);
+		return (0);
+	}
+	return (1);
+}
+
 int
 res_hnok(const char *dn)
 {
Index: parse.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/parse.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sbin/dhclient/parse.c -L sbin/dhclient/parse.c -u -r1.2 -r1.3
--- sbin/dhclient/parse.c
+++ sbin/dhclient/parse.c
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/parse.c,v 1.2.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/parse.c,v 1.3 2005/08/23 23:59:55 brooks Exp $");
 
 #include "dhcpd.h"
 #include "dhctoken.h"
@@ -129,10 +129,8 @@
 		error("no memory for string %s.", val);
 	strlcpy(s, val, strlen(val) + 1);
 
-	if (!parse_semi(cfile)) {
-		free(s);
+	if (!parse_semi(cfile))
 		return (NULL);
-	}
 	return (s);
 }
 
Index: dhclient.conf
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/dhclient.conf,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/dhclient.conf -L sbin/dhclient/dhclient.conf -u -r1.1.1.1 -r1.2
--- sbin/dhclient/dhclient.conf
+++ sbin/dhclient/dhclient.conf
@@ -1,10 +1,13 @@
+# $FreeBSD: src/sbin/dhclient/dhclient.conf,v 1.3 2007/02/09 17:50:26 emaste Exp $
+
 send host-name "andare.fugue.com";
 send dhcp-client-identifier 1:0:a0:24:ab:fb:9c;
 send dhcp-lease-time 3600;
 supersede domain-name "fugue.com home.vix.com";
 prepend domain-name-servers 127.0.0.1;
-request subnet-mask, broadcast-address, time-offset, routers,
-	domain-name, domain-name-servers, host-name;
+request subnet-mask, broadcast-address, time-offset,
+	classless-routes, routers, domain-name,
+	domain-name-servers, host-name;
 require subnet-mask, domain-name-servers;
 timeout 60;
 retry 60;
Index: privsep.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/privsep.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/privsep.c -L sbin/dhclient/privsep.c -u -r1.1.1.1 -r1.2
--- sbin/dhclient/privsep.c
+++ sbin/dhclient/privsep.c
@@ -17,7 +17,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/privsep.c,v 1.1.1.1.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/privsep.c,v 1.2 2005/08/23 23:59:55 brooks Exp $");
 
 #include "dhcpd.h"
 #include "privsep.h"
Index: dhcp-options.5
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/dhcp-options.5,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -L sbin/dhclient/dhcp-options.5 -L sbin/dhclient/dhcp-options.5 -u -r1.1.1.2 -r1.2
--- sbin/dhclient/dhcp-options.5
+++ sbin/dhclient/dhcp-options.5
@@ -36,7 +36,7 @@
 .\" see ``http://www.isc.org/isc''.  To learn more about Vixie
 .\" Enterprises, see ``http://www.vix.com''.
 .\"
-.\" $FreeBSD: src/sbin/dhclient/dhcp-options.5,v 1.2.2.1 2006/02/15 14:58:59 jcamou Exp $
+.\" $FreeBSD: src/sbin/dhclient/dhcp-options.5,v 1.3 2006/02/06 19:22:34 jcamou Exp $
 .\"
 .Dd January 1, 1995
 .Dt DHCP-OPTIONS 5
Index: errwarn.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/errwarn.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/errwarn.c -L sbin/dhclient/errwarn.c -u -r1.1.1.1 -r1.2
--- sbin/dhclient/errwarn.c
+++ sbin/dhclient/errwarn.c
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/errwarn.c,v 1.1.1.1.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/errwarn.c,v 1.2 2005/08/23 23:59:55 brooks Exp $");
 
 #include <errno.h>
 
Index: packet.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/packet.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/packet.c -L sbin/dhclient/packet.c -u -r1.1.1.1 -r1.2
--- sbin/dhclient/packet.c
+++ sbin/dhclient/packet.c
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/packet.c,v 1.1.1.1.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/packet.c,v 1.2 2005/08/23 23:59:55 brooks Exp $");
 
 #include "dhcpd.h"
 
Index: convert.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/convert.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/convert.c -L sbin/dhclient/convert.c -u -r1.1.1.1 -r1.2
--- sbin/dhclient/convert.c
+++ sbin/dhclient/convert.c
@@ -44,7 +44,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/convert.c,v 1.1.1.1.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/convert.c,v 1.2 2005/08/23 23:59:55 brooks Exp $");
 
 #include "dhcpd.h"
 
Index: dhcp.h
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/dhcp.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/dhcp.h -L sbin/dhclient/dhcp.h -u -r1.1.1.1 -r1.2
--- sbin/dhclient/dhcp.h
+++ sbin/dhclient/dhcp.h
@@ -1,5 +1,5 @@
 /*	$OpenBSD: dhcp.h,v 1.5 2004/05/04 15:49:49 deraadt Exp $	*/
-/*	$FreeBSD: src/sbin/dhclient/dhcp.h,v 1.2 2005/06/30 05:50:52 brooks Exp $	*/
+/*	$FreeBSD: src/sbin/dhclient/dhcp.h,v 1.3 2007/02/09 17:50:26 emaste Exp $	*/
 
 /* Protocol structures... */
 
@@ -162,6 +162,7 @@
 #define DHO_FINGER_SERVER		73
 #define DHO_IRC_SERVER			74
 #define DHO_DHCP_USER_CLASS_ID		77
+#define DHO_CLASSLESS_ROUTES		121
 #define DHO_END				255
 
 /* DHCP message types. */
Index: bpf.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/bpf.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sbin/dhclient/bpf.c -L sbin/dhclient/bpf.c -u -r1.2 -r1.3
--- sbin/dhclient/bpf.c
+++ sbin/dhclient/bpf.c
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/bpf.c,v 1.2.2.3 2005/12/20 21:11:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/bpf.c,v 1.7 2006/09/26 01:02:02 brooks Exp $");
 
 #include "dhcpd.h"
 #include <sys/ioctl.h>
Index: dispatch.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/dispatch.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sbin/dhclient/dispatch.c -L sbin/dhclient/dispatch.c -u -r1.2 -r1.3
--- sbin/dhclient/dispatch.c
+++ sbin/dhclient/dispatch.c
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/dispatch.c,v 1.1.1.1.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/dispatch.c,v 1.2.2.1 2007/12/10 17:49:16 jkim Exp $");
 
 #include "dhcpd.h"
 
@@ -295,7 +295,7 @@
 	memset(&ifr, 0, sizeof(ifr));
 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
 	if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
-		warning("ioctl(SIOCGIFFLAGS) on %s: %m", ifname);
+		syslog(LOG_ERR, "ioctl(SIOCGIFFLAGS) on %s: %m", ifname);
 		goto inactive;
 	}
 
@@ -313,7 +313,7 @@
 	strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
 	if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
 		if (errno != EINVAL) {
-			debug("ioctl(SIOCGIFMEDIA) on %s: %m",
+			syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m",
 			    ifname);
 
 			ifinfo->noifmedia = 1;
@@ -329,6 +329,7 @@
 	if (ifmr.ifm_status & IFM_AVALID) {
 		switch (ifmr.ifm_active & IFM_NMASK) {
 		case IFM_ETHER:
+		case IFM_IEEE80211:
 			if (ifmr.ifm_status & IFM_ACTIVE)
 				goto active;
 			else
@@ -479,7 +480,7 @@
 	if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
 		/* EINVAL -> link state unknown. treat as active */
 		if (errno != EINVAL)
-			debug("ioctl(SIOCGIFMEDIA) on %s: %m",
+			syslog(LOG_DEBUG, "ioctl(SIOCGIFMEDIA) on %s: %m",
 			    ifname);
 		close(sock);
 		return (1);
@@ -487,7 +488,9 @@
 	close(sock);
 
 	if (ifmr.ifm_status & IFM_AVALID) {
-		if ((ifmr.ifm_active & IFM_NMASK) == IFM_ETHER) {
+		switch (ifmr.ifm_active & IFM_NMASK) {
+		case IFM_ETHER:
+		case IFM_IEEE80211:
 			if (ifmr.ifm_status & IFM_ACTIVE)
 				return (1);
 			else
Index: tree.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/tree.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/tree.c -L sbin/dhclient/tree.c -u -r1.1.1.1 -r1.2
--- sbin/dhclient/tree.c
+++ sbin/dhclient/tree.c
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/tree.c,v 1.1.1.1.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/tree.c,v 1.2 2005/08/23 23:59:55 brooks Exp $");
 
 #include "dhcpd.h"
 
Index: dhclient.8
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/dhclient.8,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -L sbin/dhclient/dhclient.8 -L sbin/dhclient/dhclient.8 -u -r1.1.1.2 -r1.2
--- sbin/dhclient/dhclient.8
+++ sbin/dhclient/dhclient.8
@@ -36,9 +36,9 @@
 .\" see ``http://www.isc.org/isc''.  To learn more about Vixie
 .\" Enterprises, see ``http://www.vix.com''.
 .\"
-.\" $FreeBSD: src/sbin/dhclient/dhclient.8,v 1.2.2.3 2006/01/24 06:03:16 brooks Exp $
+.\" $FreeBSD: src/sbin/dhclient/dhclient.8,v 1.9 2007/09/20 10:46:25 gabor Exp $
 .\"
-.Dd July 22, 2005
+.Dd August 13, 2007
 .Dt DHCLIENT 8
 .Os
 .Sh NAME
@@ -176,10 +176,7 @@
 .Sh SEE ALSO
 .Xr dhclient.conf 5 ,
 .Xr dhclient.leases 5 ,
-.Xr dhclient-script 8 ,
-.Xr dhcp 8 ,
-.Xr dhcpd 8 ,
-.Xr dhcrelay 8
+.Xr dhclient-script 8
 .Sh AUTHORS
 .An -nosplit
 The
Index: hash.c
===================================================================
RCS file: /home/cvs/src/sbin/dhclient/hash.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dhclient/hash.c -L sbin/dhclient/hash.c -u -r1.1.1.1 -r1.2
--- sbin/dhclient/hash.c
+++ sbin/dhclient/hash.c
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sbin/dhclient/hash.c,v 1.1.1.1.2.1 2005/09/10 17:01:16 brooks Exp $");
+__FBSDID("$FreeBSD: src/sbin/dhclient/hash.c,v 1.2 2005/08/23 23:59:55 brooks Exp $");
 
 #include "dhcpd.h"
 
Index: dmesg.c
===================================================================
RCS file: /home/cvs/src/sbin/dmesg/dmesg.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sbin/dmesg/dmesg.c -L sbin/dmesg/dmesg.c -u -r1.2 -r1.3
--- sbin/dmesg/dmesg.c
+++ sbin/dmesg/dmesg.c
@@ -40,6 +40,7 @@
 #endif
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sbin/dmesg/dmesg.c,v 1.27 2005/01/17 13:56:46 delphij Exp $");
+__MBSDID("$MidnightBSD$");
 
 #include <sys/types.h>
 #include <sys/msgbuf.h>
Index: dmesg.8
===================================================================
RCS file: /home/cvs/src/sbin/dmesg/dmesg.8,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dmesg/dmesg.8 -L sbin/dmesg/dmesg.8 -u -r1.1.1.1 -r1.2
--- sbin/dmesg/dmesg.8
+++ sbin/dmesg/dmesg.8
@@ -27,6 +27,7 @@
 .\"
 .\"     @(#)dmesg.8	8.1 (Berkeley) 6/5/93
 .\" $FreeBSD: src/sbin/dmesg/dmesg.8,v 1.19 2004/04/09 19:58:26 markm Exp $
+.\" $MidnightBSD$
 .\"
 .Dd June 5, 1993
 .Dt DMESG 8
Index: Makefile
===================================================================
RCS file: /home/cvs/src/sbin/dmesg/Makefile,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/dmesg/Makefile -L sbin/dmesg/Makefile -u -r1.1.1.1 -r1.2
--- sbin/dmesg/Makefile
+++ sbin/dmesg/Makefile
@@ -1,5 +1,6 @@
 #	@(#)Makefile	8.1 (Berkeley) 6/5/93
 # $FreeBSD: src/sbin/dmesg/Makefile,v 1.8 2005/01/17 13:56:46 delphij Exp $
+# $MidnightBSD$
 
 PROG=	dmesg
 MAN=	dmesg.8
--- /dev/null
+++ sbin/ifconfig/iflagg.c
@@ -0,0 +1,195 @@
+/*-
+ */
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD: src/sbin/ifconfig/iflagg.c,v 1.3 2007/07/05 09:18:56 thompsa Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_lagg.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+char lacpbuf[120];	/* LACP peer '[(a,a,a),(p,p,p)]' */
+
+static void
+setlaggport(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct lagg_reqport rp;
+
+	bzero(&rp, sizeof(rp));
+	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
+	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
+
+	if (ioctl(s, SIOCSLAGGPORT, &rp))
+		err(1, "SIOCSLAGGPORT");
+}
+
+static void
+unsetlaggport(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct lagg_reqport rp;
+
+	bzero(&rp, sizeof(rp));
+	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
+	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
+
+	if (ioctl(s, SIOCSLAGGDELPORT, &rp))
+		err(1, "SIOCSLAGGDELPORT");
+}
+
+static void
+setlaggproto(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct lagg_protos lpr[] = LAGG_PROTOS;
+	struct lagg_reqall ra;
+	int i;
+
+	bzero(&ra, sizeof(ra));
+	ra.ra_proto = LAGG_PROTO_MAX;
+
+	for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
+		if (strcmp(val, lpr[i].lpr_name) == 0) {
+			ra.ra_proto = lpr[i].lpr_proto;
+			break;
+		}
+	}
+	if (ra.ra_proto == LAGG_PROTO_MAX)
+		errx(1, "Invalid aggregation protocol: %s", val);
+
+	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
+	if (ioctl(s, SIOCSLAGG, &ra) != 0)
+		err(1, "SIOCSLAGG");
+}
+
+static char *
+lacp_format_mac(const uint8_t *mac, char *buf, size_t buflen)
+{
+	snprintf(buf, buflen, "%02X-%02X-%02X-%02X-%02X-%02X",
+	    (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3],
+	    (int)mac[4], (int)mac[5]);
+
+	return (buf);
+}
+
+static char *
+lacp_format_peer(struct lacp_opreq *req, const char *sep)
+{
+	char macbuf1[20];
+	char macbuf2[20];
+
+	snprintf(lacpbuf, sizeof(lacpbuf),
+	    "[(%04X,%s,%04X,%04X,%04X),%s(%04X,%s,%04X,%04X,%04X)]",
+	    req->actor_prio,
+	    lacp_format_mac(req->actor_mac, macbuf1, sizeof(macbuf1)),
+	    req->actor_key, req->actor_portprio, req->actor_portno, sep,
+	    req->partner_prio,
+	    lacp_format_mac(req->partner_mac, macbuf2, sizeof(macbuf2)),
+	    req->partner_key, req->partner_portprio, req->partner_portno);
+
+	return(lacpbuf);
+}
+
+static void
+lagg_status(int s)
+{
+	struct lagg_protos lpr[] = LAGG_PROTOS;
+	struct lagg_reqport rp, rpbuf[LAGG_MAX_PORTS];
+	struct lagg_reqall ra;
+	struct lacp_opreq *lp;
+	const char *proto = "<unknown>";
+	int i, isport = 0;
+
+	bzero(&rp, sizeof(rp));
+	bzero(&ra, sizeof(ra));
+
+	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
+	strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname));
+
+	if (ioctl(s, SIOCGLAGGPORT, &rp) == 0)
+		isport = 1;
+
+	strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
+	ra.ra_size = sizeof(rpbuf);
+	ra.ra_port = rpbuf;
+
+	if (ioctl(s, SIOCGLAGG, &ra) == 0) {
+		lp = (struct lacp_opreq *)&ra.ra_lacpreq;
+
+		for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
+			if (ra.ra_proto == lpr[i].lpr_proto) {
+				proto = lpr[i].lpr_name;
+				break;
+			}
+		}
+
+		printf("\tlaggproto %s", proto);
+		if (isport)
+			printf(" laggdev %s", rp.rp_ifname);
+		putchar('\n');
+		if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
+			printf("\tlag id: %s\n",
+			    lacp_format_peer(lp, "\n\t\t "));
+
+		for (i = 0; i < ra.ra_ports; i++) {
+			lp = (struct lacp_opreq *)&rpbuf[i].rp_lacpreq;
+			printf("\tlaggport: %s ", rpbuf[i].rp_portname);
+			printb("flags", rpbuf[i].rp_flags, LAGG_PORT_BITS);
+			if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
+				printf(" state=%X", lp->actor_state);
+			putchar('\n');
+			if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
+				printf("\t\t%s\n",
+				    lacp_format_peer(lp, "\n\t\t "));
+		}
+
+		if (0 /* XXX */) {
+			printf("\tsupported aggregation protocols:\n");
+			for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++)
+				printf("\t\tlaggproto %s\n", lpr[i].lpr_name);
+		}
+	} else if (isport)
+		printf("\tlagg: laggdev %s\n", rp.rp_ifname);
+}
+
+static struct cmd lagg_cmds[] = {
+	DEF_CMD_ARG("laggport",		setlaggport),
+	DEF_CMD_ARG("-laggport",	unsetlaggport),
+	DEF_CMD_ARG("laggproto",	setlaggproto),
+};
+static struct afswtch af_lagg = {
+	.af_name	= "af_lagg",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = lagg_status,
+};
+
+static __constructor void
+lagg_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	int i;
+
+	for (i = 0; i < N(lagg_cmds);  i++)
+		cmd_register(&lagg_cmds[i]);
+	af_register(&af_lagg);
+#undef N
+}
Index: af_inet.c
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/af_inet.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/ifconfig/af_inet.c -L sbin/ifconfig/af_inet.c -u -r1.1.1.1 -r1.2
--- sbin/ifconfig/af_inet.c
+++ sbin/ifconfig/af_inet.c
@@ -29,20 +29,20 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: src/sbin/ifconfig/af_inet.c,v 1.2 2005/06/16 19:37:09 ume Exp $";
+  "$FreeBSD: src/sbin/ifconfig/af_inet.c,v 1.3 2007/02/24 23:55:46 sam Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <net/if.h>
-#include <net/route.h>		/* for RTX_IFA */
 
 #include <err.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <ifaddrs.h>
 
 #include <netinet/in.h>
 #include <net/if_var.h>		/* for struct ifaddr */
@@ -56,35 +56,33 @@
 static struct ifreq in_ridreq;
 
 static void
-in_status(int s __unused, const struct rt_addrinfo * info)
+in_status(int s __unused, const struct ifaddrs *ifa)
 {
 	struct sockaddr_in *sin, null_sin;
 	
 	memset(&null_sin, 0, sizeof(null_sin));
 
-	sin = (struct sockaddr_in *)info->rti_info[RTAX_IFA];
+	sin = (struct sockaddr_in *)ifa->ifa_addr;
 	if (sin == NULL)
 		return;
 
 	printf("\tinet %s ", inet_ntoa(sin->sin_addr));
 
-	if (flags & IFF_POINTOPOINT) {
-		/* note RTAX_BRD overlap with IFF_BROADCAST */
-		sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
-		if (!sin)
+	if (ifa->ifa_flags & IFF_POINTOPOINT) {
+		sin = (struct sockaddr_in *)ifa->ifa_dstaddr;
+		if (sin == NULL)
 			sin = &null_sin;
 		printf("--> %s ", inet_ntoa(sin->sin_addr));
 	}
 
-	sin = (struct sockaddr_in *)info->rti_info[RTAX_NETMASK];
-	if (!sin)
+	sin = (struct sockaddr_in *)ifa->ifa_netmask;
+	if (sin == NULL)
 		sin = &null_sin;
 	printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr));
 
-	if (flags & IFF_BROADCAST) {
-		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
-		sin = (struct sockaddr_in *)info->rti_info[RTAX_BRD];
-		if (sin && sin->sin_addr.s_addr != 0)
+	if (ifa->ifa_flags & IFF_BROADCAST) {
+		sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
+		if (sin != NULL && sin->sin_addr.s_addr != 0)
 			printf("broadcast %s", inet_ntoa(sin->sin_addr));
 	}
 	putchar('\n');
--- /dev/null
+++ sbin/ifconfig/ifgroup.c
@@ -0,0 +1,186 @@
+/*-
+ * Copyright (c) 2006 Max Laier. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+  "$FreeBSD: src/sbin/ifconfig/ifgroup.c,v 1.2 2007/02/17 18:22:20 sam Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+/* ARGSUSED */
+static void
+setifgroup(const char *group_name, int d, int s, const struct afswtch *rafp)
+{
+	struct ifgroupreq ifgr;
+
+	memset(&ifgr, 0, sizeof(ifgr));
+	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
+
+	if (group_name[0] && isdigit(group_name[strlen(group_name) - 1]))
+		errx(1, "setifgroup: group names may not end in a digit");
+
+	if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
+		errx(1, "setifgroup: group name too long");
+	if (ioctl(s, SIOCAIFGROUP, (caddr_t)&ifgr) == -1)
+		err(1," SIOCAIFGROUP");
+}
+
+/* ARGSUSED */
+static void
+unsetifgroup(const char *group_name, int d, int s, const struct afswtch *rafp)
+{
+	struct ifgroupreq ifgr;
+
+	memset(&ifgr, 0, sizeof(ifgr));
+	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
+
+	if (group_name[0] && isdigit(group_name[strlen(group_name) - 1]))
+		errx(1, "unsetifgroup: group names may not end in a digit");
+
+	if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
+		errx(1, "unsetifgroup: group name too long");
+	if (ioctl(s, SIOCDIFGROUP, (caddr_t)&ifgr) == -1)
+		err(1, "SIOCDIFGROUP");
+}
+
+static void
+getifgroups(int s)
+{
+	int			 len, cnt;
+	struct ifgroupreq	 ifgr;
+	struct ifg_req		*ifg;
+
+	if (!verbose)
+		return;
+
+	memset(&ifgr, 0, sizeof(ifgr));
+	strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
+
+	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
+		if (errno == EINVAL || errno == ENOTTY)
+			return;
+		else
+			err(1, "SIOCGIFGROUP");
+	}
+
+	len = ifgr.ifgr_len;
+	ifgr.ifgr_groups =
+	    (struct ifg_req *)calloc(len / sizeof(struct ifg_req),
+	    sizeof(struct ifg_req));
+	if (ifgr.ifgr_groups == NULL)
+		err(1, "getifgroups");
+	if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
+		err(1, "SIOCGIFGROUP");
+
+	cnt = 0;
+	ifg = ifgr.ifgr_groups;
+	for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
+		len -= sizeof(struct ifg_req);
+		if (strcmp(ifg->ifgrq_group, "all")) {
+			if (cnt == 0)
+				printf("\tgroups: ");
+			cnt++;
+			printf("%s ", ifg->ifgrq_group);
+		}
+	}
+	if (cnt)
+		printf("\n");
+}
+
+static void
+printgroup(const char *groupname)
+{
+	struct ifgroupreq	 ifgr;
+	struct ifg_req		*ifg;
+	int			 len, cnt = 0;
+	int			 s;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s == -1)
+		err(1, "socket(AF_INET,SOCK_DGRAM)");
+	bzero(&ifgr, sizeof(ifgr));
+	strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
+	if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
+		if (errno == EINVAL || errno == ENOTTY ||
+		    errno == ENOENT)
+			exit(0);
+		else
+			err(1, "SIOCGIFGMEMB");
+	}
+
+	len = ifgr.ifgr_len;
+	if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
+		err(1, "printgroup");
+	if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
+		err(1, "SIOCGIFGMEMB");
+
+	for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
+	    ifg++) {
+		len -= sizeof(struct ifg_req);
+		printf("%s\n", ifg->ifgrq_member);
+		cnt++;
+	}
+	free(ifgr.ifgr_groups);
+
+	exit(0);
+}
+
+static struct cmd group_cmds[] = {
+	DEF_CMD_ARG("group",	setifgroup),
+	DEF_CMD_ARG("-group",	unsetifgroup),
+};
+static struct afswtch af_group = {
+	.af_name	= "af_group",
+	.af_af		= AF_UNSPEC,
+	.af_other_status = getifgroups,
+};
+static struct option group_gopt = { "g:", "[-g groupname]", printgroup };
+
+static __constructor void
+group_ctor(void)
+{
+#define	N(a)	(sizeof(a) / sizeof(a[0]))
+	int i;
+
+	for (i = 0; i < N(group_cmds);  i++)
+		cmd_register(&group_cmds[i]);
+	af_register(&af_group);
+	opt_register(&group_gopt);
+#undef N
+}
Index: af_inet6.c
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/af_inet6.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/ifconfig/af_inet6.c -L sbin/ifconfig/af_inet6.c -u -r1.1.1.1 -r1.2
--- sbin/ifconfig/af_inet6.c
+++ sbin/ifconfig/af_inet6.c
@@ -29,14 +29,13 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: src/sbin/ifconfig/af_inet6.c,v 1.3 2005/06/16 19:37:09 ume Exp $";
+  "$FreeBSD: src/sbin/ifconfig/af_inet6.c,v 1.6 2007/02/24 23:55:46 sam Exp $";
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <net/if.h>
-#include <net/route.h>		/* for RTX_IFA */
 
 #include <err.h>
 #include <stdio.h>
@@ -179,7 +178,7 @@
 }
 
 static void
-in6_status(int s __unused, const struct rt_addrinfo * info)
+in6_status(int s __unused, const struct ifaddrs *ifa)
 {
 	struct sockaddr_in6 *sin, null_sin;
 	struct in6_ifreq ifr6;
@@ -192,7 +191,7 @@
 
 	memset(&null_sin, 0, sizeof(null_sin));
 
-	sin = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA];
+	sin = (struct sockaddr_in6 *)ifa->ifa_addr;
 	if (sin == NULL)
 		return;
 
@@ -237,14 +236,13 @@
 			  sizeof(addr_buf));
 	printf("\tinet6 %s ", addr_buf);
 
-	if (flags & IFF_POINTOPOINT) {
-		/* note RTAX_BRD overlap with IFF_BROADCAST */
-		sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD];
+	if (ifa->ifa_flags & IFF_POINTOPOINT) {
+		sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
 		/*
 		 * some of the interfaces do not have valid destination
 		 * address.
 		 */
-		if (sin && sin->sin6_family == AF_INET6) {
+		if (sin != NULL && sin->sin6_family == AF_INET6) {
 			int error;
 
 			/* XXX: embedded link local addr check */
@@ -269,8 +267,8 @@
 		}
 	}
 
-	sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK];
-	if (!sin)
+	sin = (struct sockaddr_in6 *)ifa->ifa_netmask;
+	if (sin == NULL)
 		sin = &null_sin;
 	printf("prefixlen %d ", prefix(&sin->sin6_addr,
 		sizeof(struct in6_addr)));
Index: ifvlan.c
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/ifvlan.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sbin/ifconfig/ifvlan.c -L sbin/ifconfig/ifvlan.c -u -r1.2 -r1.3
--- sbin/ifconfig/ifvlan.c
+++ sbin/ifconfig/ifvlan.c
@@ -56,95 +56,119 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: src/sbin/ifconfig/ifvlan.c,v 1.7.2.5 2006/03/22 15:32:30 yar Exp $";
+  "$FreeBSD: src/sbin/ifconfig/ifvlan.c,v 1.12 2006/07/09 06:10:23 sam Exp $";
 #endif
-static struct vlanreq		__vreq;
-static int			__have_dev = 0;
-static int			__have_tag = 0;
 
-static void			vlan_set(int);
+#define	NOTAG	((u_short) -1)
+
+static 	struct vlanreq params = {
+	.vlr_tag	= NOTAG,
+};
+
+static int
+getvlan(int s, struct ifreq *ifr, struct vlanreq *vreq)
+{
+	bzero((char *)vreq, sizeof(*vreq));
+	ifr->ifr_data = (caddr_t)vreq;
+
+	return ioctl(s, SIOCGETVLAN, (caddr_t)ifr);
+}
 
 static void
 vlan_status(int s)
 {
 	struct vlanreq		vreq;
 
-	bzero((char *)&vreq, sizeof(vreq));
-	ifr.ifr_data = (caddr_t)&vreq;
+	if (getvlan(s, &ifr, &vreq) != -1)
+		printf("\tvlan: %d parent interface: %s\n",
+		    vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
+		    "<none>" : vreq.vlr_parent);
+}
 
-	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
-		return;
+static void
+vlan_create(int s, struct ifreq *ifr)
+{
+	if (params.vlr_tag != NOTAG || params.vlr_parent[0] != '\0') {
+		/*
+		 * One or both parameters were specified, make sure both.
+		 */
+		if (params.vlr_tag == NOTAG)
+			errx(1, "must specify a tag for vlan create");
+		if (params.vlr_parent[0] == '\0')
+			errx(1, "must specify a parent device for vlan create");
+		ifr->ifr_data = (caddr_t) ¶ms;
+	}
+	if (ioctl(s, SIOCIFCREATE2, ifr) < 0)
+		err(1, "SIOCIFCREATE2");
+}
 
-	printf("\tvlan: %d parent interface: %s\n",
-	    vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
-	    "<none>" : vreq.vlr_parent);
+static void
+vlan_cb(int s, void *arg)
+{
+	if ((params.vlr_tag != NOTAG) ^ (params.vlr_parent[0] != '\0'))
+		errx(1, "both vlan and vlandev must be specified");
 }
 
 static void
-setvlantag(const char *val, int d, int s, const struct afswtch	*afp)
+vlan_set(int s, struct ifreq *ifr)
 {
-	char			*endp;
-	u_long			ul;
+	if (params.vlr_tag != NOTAG && params.vlr_parent[0] != '\0') {
+		ifr->ifr_data = (caddr_t) ¶ms;
+		if (ioctl(s, SIOCSETVLAN, (caddr_t)ifr) == -1)
+			err(1, "SIOCSETVLAN");
+	}
+}
+
+static
+DECL_CMD_FUNC(setvlantag, val, d)
+{
+	struct vlanreq vreq;
+	u_long ul;
+	char *endp;
 
 	ul = strtoul(val, &endp, 0);
 	if (*endp != '\0')
 		errx(1, "invalid value for vlan");
-	__vreq.vlr_tag = ul;
+	params.vlr_tag = ul;
 	/* check if the value can be represented in vlr_tag */
-	if (__vreq.vlr_tag != ul)
+	if (params.vlr_tag != ul)
 		errx(1, "value for vlan out of range");
-	/* the kernel will do more specific checks on vlr_tag */
-	__have_tag = 1;
-	vlan_set(s);	/* try setting vlan params in kernel */
+
+	if (getvlan(s, &ifr, &vreq) != -1)
+		vlan_set(s, &ifr);
+	else
+		clone_setcallback(vlan_create);
 }
 
-static void
-setvlandev(const char *val, int d, int s, const struct afswtch	*afp)
+static
+DECL_CMD_FUNC(setvlandev, val, d)
 {
+	struct vlanreq vreq;
+
+	strlcpy(params.vlr_parent, val, sizeof(params.vlr_parent));
 
-	strncpy(__vreq.vlr_parent, val, sizeof(__vreq.vlr_parent));
-	__have_dev = 1;
-	vlan_set(s);	/* try setting vlan params in kernel */
+	if (getvlan(s, &ifr, &vreq) != -1)
+		vlan_set(s, &ifr);
+	else
+		clone_setcallback(vlan_create);
 }
 
-static void
-unsetvlandev(const char *val, int d, int s, const struct afswtch *afp)
+static
+DECL_CMD_FUNC(unsetvlandev, val, d)
 {
+	struct vlanreq		vreq;
 
-	if (val != NULL)
-		warnx("argument to -vlandev is useless and hence deprecated");
+	bzero((char *)&vreq, sizeof(struct vlanreq));
+	ifr.ifr_data = (caddr_t)&vreq;
 
-	bzero((char *)&__vreq, sizeof(__vreq));
-	ifr.ifr_data = (caddr_t)&__vreq;
-#if 0	/* this code will be of use when we can alter vlan or vlandev only */
 	if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
 		err(1, "SIOCGETVLAN");
 
-	bzero((char *)&__vreq.vlr_parent, sizeof(__vreq.vlr_parent));
-	__vreq.vlr_tag = 0; /* XXX clear parent only (no kernel support now) */
-#endif
+	bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent));
+	vreq.vlr_tag = 0;
+
 	if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
 		err(1, "SIOCSETVLAN");
-	__have_dev = __have_tag = 0;
-}
-
-static void
-vlan_cb(int s, void *arg)
-{
-
-	if (__have_tag ^ __have_dev)
-		errx(1, "both vlan and vlandev must be specified");
-}
-
-static void
-vlan_set(int s)
-{
-
-	if (__have_tag && __have_dev) {
-		ifr.ifr_data = (caddr_t)&__vreq;
-		if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
-			err(1, "SIOCSETVLAN");
-	}
 }
 
 static struct cmd vlan_cmds[] = {
Index: Makefile
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/Makefile,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/ifconfig/Makefile -L sbin/ifconfig/Makefile -u -r1.1.1.1 -r1.2
--- sbin/ifconfig/Makefile
+++ sbin/ifconfig/Makefile
@@ -1,5 +1,7 @@
 #	From: @(#)Makefile	8.1 (Berkeley) 6/5/93
-# $FreeBSD: src/sbin/ifconfig/Makefile,v 1.29 2005/06/05 03:32:51 thompsa Exp $
+# $FreeBSD: src/sbin/ifconfig/Makefile,v 1.33 2007/04/17 00:35:09 thompsa Exp $
+
+.include <bsd.own.mk>
 
 PROG=	ifconfig
 
@@ -24,11 +26,13 @@
 SRCS+=	ifieee80211.c		# SIOC[GS]IEEE80211 support
 
 SRCS+=	ifcarp.c		# SIOC[GS]VH support
+SRCS+=	ifgroup.c		# ...
 SRCS+=	ifpfsync.c		# pfsync(4) support
 
 SRCS+=	ifbridge.c		# bridge support
+SRCS+=	iflagg.c		# lagg support
 
-.if !defined(RELEASE_CRUNCH)
+.if ${MK_IPX_SUPPORT} != "no" && !defined(RELEASE_CRUNCH)
 SRCS+=	af_ipx.c		# IPX support
 DPADD=	${LIBIPX}
 LDADD=	-lipx
Index: ifbridge.c
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/ifbridge.c,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -L sbin/ifconfig/ifbridge.c -L sbin/ifconfig/ifbridge.c -u -r1.1.1.2 -r1.2
--- sbin/ifconfig/ifbridge.c
+++ sbin/ifconfig/ifbridge.c
@@ -35,7 +35,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: src/sbin/ifconfig/ifbridge.c,v 1.1.2.2 2005/12/28 04:12:58 thompsa Exp $";
+  "$FreeBSD: src/sbin/ifconfig/ifbridge.c,v 1.11 2007/08/01 00:33:52 thompsa Exp $";
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -61,6 +61,37 @@
 
 #include "ifconfig.h"
 
+#define PV2ID(pv, epri, eaddr)  do {		\
+		epri     = pv >> 48;		\
+		eaddr[0] = pv >> 40;		\
+		eaddr[1] = pv >> 32;		\
+		eaddr[2] = pv >> 24;		\
+		eaddr[3] = pv >> 16;		\
+		eaddr[4] = pv >> 8;		\
+		eaddr[5] = pv >> 0;		\
+} while (0)
+
+static const char *stpstates[] = {
+	"disabled",
+	"listening",
+	"learning",
+	"forwarding",
+	"blocking",
+	"discarding"
+};
+static const char *stpproto[] = {
+	"stp",
+	"-",
+	"rstp"
+};
+static const char *stproles[] = {
+	"disabled",
+	"root",
+	"designated",
+	"alternate",
+	"backup"
+};
+
 static int
 get_val(const char *cp, u_long *valp)
 {
@@ -113,13 +144,6 @@
 static void
 bridge_interfaces(int s, const char *prefix)
 {
-	static const char *stpstates[] = {
-		"disabled",
-		"listening",
-		"learning",
-		"forwarding",
-		"blocking",
-	};
 	struct ifbifconf bifc;
 	struct ifbreq *req;
 	char *inbuf = NULL, *ninbuf;
@@ -159,9 +183,23 @@
 			printf("port %u priority %u",
 			    req->ifbr_portno, req->ifbr_priority);
 			printf(" path cost %u", req->ifbr_path_cost);
+			if (req->ifbr_proto <
+			    sizeof(stpproto) / sizeof(stpproto[0]))
+				printf(" proto %s", stpproto[req->ifbr_proto]);
+			else
+				printf(" <unknown proto %d>",
+				    req->ifbr_proto);
+
+			printf("\n%s", pad);
+			if (req->ifbr_role <
+			    sizeof(stproles) / sizeof(stproles[0]))
+				printf("role %s", stproles[req->ifbr_role]);
+			else
+				printf("<unknown role %d>",
+				    req->ifbr_role);
 			if (req->ifbr_state <
 			    sizeof(stpstates) / sizeof(stpstates[0]))
-				printf(" %s", stpstates[req->ifbr_state]);
+				printf(" state %s", stpstates[req->ifbr_state]);
 			else
 				printf(" <unknown state %d>",
 				    req->ifbr_state);
@@ -198,8 +236,8 @@
 		ifba = ifbac.ifbac_req + i;
 		memcpy(ea.octet, ifba->ifba_dst,
 		    sizeof(ea.octet));
-		printf("%s%s %s %lu ", prefix, ether_ntoa(&ea),
-		    ifba->ifba_ifsname, ifba->ifba_expire);
+		printf("%s%s Vlan%d %s %lu ", prefix, ether_ntoa(&ea),
+		    ifba->ifba_vlan, ifba->ifba_ifsname, ifba->ifba_expire);
 		printb("flags", ifba->ifba_flags, IFBAFBITS);
 		printf("\n");
 	}
@@ -210,28 +248,39 @@
 static void
 bridge_status(int s)
 {
+	struct ifbropreq ifbp;
 	struct ifbrparam param;
 	u_int16_t pri;
-	u_int8_t ht, fd, ma;
+	u_int8_t ht, fd, ma, hc, pro;
+	u_int8_t lladdr[ETHER_ADDR_LEN];
+	u_int16_t bprio;
+	u_int32_t csize, ctime;
 
-	if (do_cmd(s, BRDGGPRI, &param, sizeof(param), 0) < 0)
+	if (do_cmd(s, BRDGGCACHE, &param, sizeof(param), 0) < 0)
 		return;
-	pri = param.ifbrp_prio;
-
-	if (do_cmd(s, BRDGGHT, &param, sizeof(param), 0) < 0)
+	csize = param.ifbrp_csize;
+	if (do_cmd(s, BRDGGTO, &param, sizeof(param), 0) < 0)
 		return;
-	ht = param.ifbrp_hellotime;
-
-	if (do_cmd(s, BRDGGFD, &param, sizeof(param), 0) < 0)
-		return;
-	fd = param.ifbrp_fwddelay;
-
-	if (do_cmd(s, BRDGGMA, &param, sizeof(param), 0) < 0)
+	ctime = param.ifbrp_ctime;
+	if (do_cmd(s, BRDGPARAM, &ifbp, sizeof(ifbp), 0) < 0)
 		return;
-	ma = param.ifbrp_maxage;
-
-	printf("\tpriority %u hellotime %u fwddelay %u maxage %u\n",
-	    pri, ht, fd, ma);
+	pri = ifbp.ifbop_priority;
+	pro = ifbp.ifbop_protocol;
+	ht = ifbp.ifbop_hellotime;
+	fd = ifbp.ifbop_fwddelay;
+	hc = ifbp.ifbop_holdcount;
+	ma = ifbp.ifbop_maxage;
+
+	PV2ID(ifbp.ifbop_bridgeid, bprio, lladdr);
+	printf("\tid %s priority %u hellotime %u fwddelay %u\n",
+	    ether_ntoa((struct ether_addr *)lladdr), pri, ht, fd);
+	printf("\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n",
+	    ma, hc, stpproto[pro], csize, ctime);
+
+	PV2ID(ifbp.ifbop_designated_root, bprio, lladdr);
+	printf("\troot id %s priority %d ifcost %u port %u\n",
+	    ether_ntoa((struct ether_addr *)lladdr), bprio,
+	    ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff);
 
 	bridge_interfaces(s, "\tmember: ");
 
@@ -290,6 +339,20 @@
 }
 
 static void
+setbridge_sticky(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_STICKY,  1);
+}
+
+static void
+unsetbridge_sticky(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_STICKY,  0);
+}
+
+static void
 setbridge_span(const char *val, int d, int s, const struct afswtch *afp)
 {
 	struct ifbreq req;
@@ -326,6 +389,54 @@
 }
 
 static void
+setbridge_edge(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 1);
+}
+
+static void
+unsetbridge_edge(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 0);
+}
+
+static void
+setbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 1);
+}
+
+static void
+unsetbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 0);
+}
+
+static void
+setbridge_ptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_PTP, 1);
+}
+
+static void
+unsetbridge_ptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_PTP, 0);
+}
+
+static void
+setbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 1);
+}
+
+static void
+unsetbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+	do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 0);
+}
+
+static void
 setbridge_flush(const char *val, int d, int s, const struct afswtch *afp)
 {
 	struct ifbreq req;
@@ -363,6 +474,7 @@
 
 	memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
 	req.ifba_flags = IFBAF_STATIC;
+	req.ifba_vlan = 1; /* XXX allow user to specify */
 
 	if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0)
 		err(1, "BRDGSADDR %s",  val);
@@ -469,6 +581,38 @@
 }
 
 static void
+setbridge_protocol(const char *arg, int d, int s, const struct afswtch *afp)
+{
+	struct ifbrparam param;
+
+	if (strcasecmp(arg, "stp") == 0) {
+		param.ifbrp_proto = 0;
+	} else if (strcasecmp(arg, "rstp") == 0) {
+		param.ifbrp_proto = 2;
+	} else {
+		errx(1, "unknown stp protocol");
+	}
+
+	if (do_cmd(s, BRDGSPROTO, &param, sizeof(param), 1) < 0)
+		err(1, "BRDGSPROTO %s",  arg);
+}
+
+static void
+setbridge_holdcount(const char *arg, int d, int s, const struct afswtch *afp)
+{
+	struct ifbrparam param;
+	u_long val;
+
+	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+		errx(1, "invalid value: %s",  arg);
+
+	param.ifbrp_txhc = val & 0xff;
+
+	if (do_cmd(s, BRDGSTXHC, &param, sizeof(param), 1) < 0)
+		err(1, "BRDGSTXHC %s",  arg);
+}
+
+static void
 setbridge_ifpriority(const char *ifn, const char *pri, int s,
     const struct afswtch *afp)
 {
@@ -496,11 +640,11 @@
 
 	memset(&req, 0, sizeof(req));
 
-	if (get_val(cost, &val) < 0 || (val & ~0xff) != 0)
+	if (get_val(cost, &val) < 0)
 		errx(1, "invalid value: %s",  cost);
 
 	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
-	req.ifbr_path_cost = val & 0xffff;
+	req.ifbr_path_cost = val;
 
 	if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0)
 		err(1, "BRDGSIFCOST %s",  cost);
@@ -521,6 +665,20 @@
 		err(1, "BRDGSTO %s",  arg);
 }
 
+static void
+setbridge_private(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_PRIVATE, 1);
+}
+
+static void
+unsetbridge_private(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	do_bridgeflag(s, val, IFBIF_PRIVATE, 0);
+}
+
 static struct cmd bridge_cmds[] = {
 	DEF_CMD_ARG("addm",		setbridge_add),
 	DEF_CMD_ARG("deletem",		setbridge_delete),
@@ -528,10 +686,20 @@
 	DEF_CMD_ARG("-discover",	unsetbridge_discover),
 	DEF_CMD_ARG("learn",		setbridge_learn),
 	DEF_CMD_ARG("-learn",		unsetbridge_learn),
+	DEF_CMD_ARG("sticky",		setbridge_sticky),
+	DEF_CMD_ARG("-sticky",		unsetbridge_sticky),
 	DEF_CMD_ARG("span",		setbridge_span),
 	DEF_CMD_ARG("-span",		unsetbridge_span),
 	DEF_CMD_ARG("stp",		setbridge_stp),
 	DEF_CMD_ARG("-stp",		unsetbridge_stp),
+	DEF_CMD_ARG("edge",		setbridge_edge),
+	DEF_CMD_ARG("-edge",		unsetbridge_edge),
+	DEF_CMD_ARG("autoedge",		setbridge_autoedge),
+	DEF_CMD_ARG("-autoedge",	unsetbridge_autoedge),
+	DEF_CMD_ARG("ptp",		setbridge_ptp),
+	DEF_CMD_ARG("-ptp",		unsetbridge_ptp),
+	DEF_CMD_ARG("autoptp",		setbridge_autoptp),
+	DEF_CMD_ARG("-autoptp",		unsetbridge_autoptp),
 	DEF_CMD("flush", 0,		setbridge_flush),
 	DEF_CMD("flushall", 0,		setbridge_flushall),
 	DEF_CMD_ARG2("static",		setbridge_static),
@@ -542,9 +710,13 @@
 	DEF_CMD_ARG("fwddelay",		setbridge_fwddelay),
 	DEF_CMD_ARG("maxage",		setbridge_maxage),
 	DEF_CMD_ARG("priority",		setbridge_priority),
+	DEF_CMD_ARG("proto",		setbridge_protocol),
+	DEF_CMD_ARG("holdcnt",		setbridge_holdcount),
 	DEF_CMD_ARG2("ifpriority",	setbridge_ifpriority),
 	DEF_CMD_ARG2("ifpathcost",	setbridge_ifpathcost),
 	DEF_CMD_ARG("timeout",		setbridge_timeout),
+	DEF_CMD_ARG("private",		setbridge_private),
+	DEF_CMD_ARG("-private",		unsetbridge_private),
 };
 static struct afswtch af_bridge = {
 	.af_name	= "af_bridge",
Index: ifpfsync.c
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/ifpfsync.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/ifconfig/ifpfsync.c -L sbin/ifconfig/ifpfsync.c -u -r1.1.1.1 -r1.2
--- sbin/ifconfig/ifpfsync.c
+++ sbin/ifconfig/ifpfsync.c
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sbin/ifconfig/ifpfsync.c,v 1.3 2005/05/03 16:59:14 mlaier Exp $
+ * $FreeBSD: src/sbin/ifconfig/ifpfsync.c,v 1.4 2006/06/06 11:21:08 glebius Exp $
  */
 
 #include <sys/types.h>
@@ -173,13 +173,18 @@
 	if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
 		return;
 
-	if (preq.pfsyncr_syncdev[0] != '\0') {
-		printf("\tpfsync: syncdev: %s ", preq.pfsyncr_syncdev);
-		if (preq.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP)
-			printf("syncpeer: %s ",
-			    inet_ntoa(preq.pfsyncr_syncpeer));
+	if (preq.pfsyncr_syncdev[0] != '\0' ||
+	    preq.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP)
+			printf("\t");
+
+	if (preq.pfsyncr_syncdev[0] != '\0')
+		printf("pfsync: syncdev: %s ", preq.pfsyncr_syncdev);
+	if (preq.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP)
+		printf("syncpeer: %s ", inet_ntoa(preq.pfsyncr_syncpeer));
+
+	if (preq.pfsyncr_syncdev[0] != '\0' ||
+	    preq.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP)
 		printf("maxupd: %d\n", preq.pfsyncr_maxupdates);
-	}
 }
 
 static struct cmd pfsync_cmds[] = {
Index: ifmedia.c
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/ifmedia.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sbin/ifconfig/ifmedia.c -L sbin/ifconfig/ifmedia.c -u -r1.2 -r1.3
--- sbin/ifconfig/ifmedia.c
+++ sbin/ifconfig/ifmedia.c
@@ -1,5 +1,5 @@
 /*	$NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $	*/
-/* $FreeBSD: src/sbin/ifconfig/ifmedia.c,v 1.19 2005/01/27 16:40:12 ambrisko Exp $ */
+/* $FreeBSD: src/sbin/ifconfig/ifmedia.c,v 1.25 2007/06/11 03:56:33 sam Exp $ */
 
 /*
  * Copyright (c) 1997 Jason R. Thorpe.
@@ -146,6 +146,7 @@
 		printf("\tstatus: ");
 		switch (IFM_TYPE(ifmr.ifm_active)) {
 		case IFM_ETHER:
+		case IFM_ATM:
 			if (ifmr.ifm_status & IFM_ACTIVE)
 				printf("active");
 			else
@@ -160,13 +161,6 @@
 				printf("no ring");
 			break;
 
-		case IFM_ATM:
-			if (ifmr.ifm_status & IFM_ACTIVE)
-				printf("active");
-			else
-				printf("no carrier");
-			break;
-
 		case IFM_IEEE80211:
 			/* XXX: Different value for adhoc? */
 			if (ifmr.ifm_status & IFM_ACTIVE)
@@ -190,8 +184,8 @@
 	free(media_list);
 }
 
-static struct ifmediareq *
-getifmediastate(int s)
+struct ifmediareq *
+ifmedia_getstate(int s)
 {
 	static struct ifmediareq *ifmr = NULL;
 	int *mwords;
@@ -254,9 +248,8 @@
 {
 	struct ifmediareq *ifmr;
 	int subtype;
-	
 
-	ifmr = getifmediastate(s);
+	ifmr = ifmedia_getstate(s);
 
 	/*
 	 * We are primarily concerned with the top-level type.
@@ -301,7 +294,7 @@
 	struct ifmediareq *ifmr;
 	int options;
 
-	ifmr = getifmediastate(s);
+	ifmr = ifmedia_getstate(s);
 
 	options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
 
@@ -309,13 +302,35 @@
 	ifr.ifr_media = ifmr->ifm_current;
 	if (clear)
 		ifr.ifr_media &= ~options;
-	else
+	else {
+		if (options & IFM_HDX) {
+			ifr.ifr_media &= ~IFM_FDX;
+			options &= ~IFM_HDX;
+		}
 		ifr.ifr_media |= options;
-
+	}
 	ifmr->ifm_current = ifr.ifr_media;
 	callback_register(setifmediacallback, (void *)ifmr);
 }
 
+static void
+setmediainst(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifmediareq *ifmr;
+	int inst;
+
+	ifmr = ifmedia_getstate(s);
+
+	inst = atoi(val);
+	if (inst < 0 || inst > IFM_INST_MAX)
+		errx(1, "invalid media instance: %s", val);
+
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
+
+	ifmr->ifm_current = ifr.ifr_media;
+	callback_register(setifmediacallback, (void *)ifmr);
+}
 
 static void
 setmediamode(const char *val, int d, int s, const struct afswtch *afp)
@@ -323,7 +338,7 @@
 	struct ifmediareq *ifmr;
 	int mode;
 
-	ifmr = getifmediastate(s);
+	ifmr = ifmedia_getstate(s);
 
 	mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
 
@@ -692,14 +707,11 @@
 
 	/* Find subtype. */
 	desc = get_subtype_desc(ifmw, ttos);
-	if (desc != NULL)
-		goto got_subtype;
-
-	/* Falling to here means unknown subtype. */
-	printf("<unknown subtype>");
-	return;
+	if (desc == NULL) {
+		printf("<unknown subtype>");
+		return;
+	}
 
- got_subtype:
 	if (print_toptype)
 		putchar(' ');
 
@@ -726,6 +738,9 @@
 		}
 	}
 	printf("%s", seen_option ? ">" : "");
+
+	if (print_toptype && IFM_INST(ifmw) != 0)
+		printf(" instance %d", IFM_INST(ifmw));
 }
 
 static void
@@ -750,14 +765,11 @@
 
 	/* Find subtype. */
 	desc = get_subtype_desc(ifmw, ttos);
-	if (desc != NULL)
-		goto got_subtype;
-
-	/* Falling to here means unknown subtype. */
-	printf("<unknown subtype>");
-	return;
+	if (desc == NULL) {
+		printf("<unknown subtype>");
+		return;
+	}
 
- got_subtype:
 	printf("media %s", desc->ifmt_string);
 
 	desc = get_mode_desc(ifmw, ttos);
@@ -775,6 +787,9 @@
 			}
 		}
 	}
+
+	if (IFM_INST(ifmw) != 0)
+		printf(" instance %d", IFM_INST(ifmw));
 }
 
 /**********************************************************************
@@ -786,6 +801,8 @@
 	DEF_CMD_ARG("mode",	setmediamode),
 	DEF_CMD_ARG("mediaopt",	setmediaopt),
 	DEF_CMD_ARG("-mediaopt",unsetmediaopt),
+	DEF_CMD_ARG("inst",	setmediainst),
+	DEF_CMD_ARG("instance",	setmediainst),
 };
 static struct afswtch af_media = {
 	.af_name	= "af_media",
Index: af_ipx.c
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/af_ipx.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/ifconfig/af_ipx.c -L sbin/ifconfig/af_ipx.c -u -r1.1.1.1 -r1.2
--- sbin/ifconfig/af_ipx.c
+++ sbin/ifconfig/af_ipx.c
@@ -29,22 +29,21 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: src/sbin/ifconfig/af_ipx.c,v 1.1 2004/12/08 19:18:07 sam Exp $";
+  "$FreeBSD: src/sbin/ifconfig/af_ipx.c,v 1.4 2007/06/13 18:07:59 rwatson Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <net/if.h>
-#include <net/route.h>
 
 #include <err.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ifaddrs.h>
 
 #include <net/if_var.h>
-#define	IPXIP
 #define IPTUNNEL
 #include <netipx/ipx.h>
 #include <netipx/ipx_if.h>
@@ -55,19 +54,19 @@
 static struct ifreq ipx_ridreq;
 
 static void
-ipx_status(int s __unused, const struct rt_addrinfo * info)
+ipx_status(int s __unused, const struct ifaddrs *ifa)
 {
 	struct sockaddr_ipx *sipx, null_sipx;
 
-	sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_IFA];
+	sipx = (struct sockaddr_ipx *)ifa->ifa_addr;
 	if (sipx == NULL)
 		return;
 
 	printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
 
-	if (flags & IFF_POINTOPOINT) {
-		sipx = (struct sockaddr_ipx *)info->rti_info[RTAX_BRD];
-		if (!sipx) {
+	if (ifa->ifa_flags & IFF_POINTOPOINT) {
+		sipx = (struct sockaddr_ipx *)ifa->ifa_dstaddr;
+		if (sipx == NULL) {
 			memset(&null_sipx, 0, sizeof(null_sipx));
 			sipx = &null_sipx;
 		}
@@ -97,16 +96,7 @@
 static void
 ipx_postproc(int s, const struct afswtch *afp)
 {
-	if (setipdst) {
-		struct ipxip_req rq;
-		int size = sizeof(rq);
 
-		rq.rq_ipx = ipx_addreq.ifra_addr;
-		rq.rq_ip = ipx_addreq.ifra_dstaddr;
-
-		if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
-			Perror("Encapsulation Routing");
-	}
 }
 
 static struct afswtch af_ipx = {
Index: ifconfig.h
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/ifconfig.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/ifconfig/ifconfig.h -L sbin/ifconfig/ifconfig.h -u -r1.1.1.1 -r1.2
--- sbin/ifconfig/ifconfig.h
+++ sbin/ifconfig/ifconfig.h
@@ -31,7 +31,7 @@
  *
  * so there!
  *
- * $FreeBSD: src/sbin/ifconfig/ifconfig.h,v 1.16.2.1 2005/07/21 12:25:40 rwatson Exp $
+ * $FreeBSD: src/sbin/ifconfig/ifconfig.h,v 1.21 2007/06/13 18:07:59 rwatson Exp $
  */
 
 #define	__constructor	__attribute__((constructor))
@@ -72,7 +72,7 @@
 #define	DEF_CMD_OPTARG(name, func)	{ name, OPTARG, { .c_func = func } }
 #define	DEF_CMD_ARG2(name, func)	{ name, NEXTARG2, { .c_func2 = func } }
 
-struct rt_addrinfo;
+struct ifaddrs;
 struct addrinfo;
 
 enum {
@@ -94,7 +94,7 @@
 	 * is defined then it is invoked after all address status
 	 * is presented.
 	 */
-	void		(*af_status)(int, const struct rt_addrinfo *);
+	void		(*af_status)(int, const struct ifaddrs *);
 	void		(*af_other_status)(int);
 					/* parse address method */
 	void		(*af_getaddr)(const char *, int);
@@ -127,17 +127,21 @@
 extern	int allmedia;
 extern	int supmedia;
 extern	int printkeys;
-extern	int printname;
-extern	int flags;
 extern	int newaddr;
 extern	int verbose;
-extern	int setipdst;
 
 void	setifcap(const char *, int value, int s, const struct afswtch *);
 
 void	Perror(const char *cmd);
 void	printb(const char *s, unsigned value, const char *bits);
 
-void	ifmaybeload(char *name);
+void	ifmaybeload(const char *name);
 
-void	clone_create(void);
+typedef void clone_callback_func(int, struct ifreq *);
+void	clone_setcallback(clone_callback_func *);
+
+/*
+ * XXX expose this so modules that neeed to know of any pending
+ * operations on ifmedia can avoid cmd line ordering confusion.
+ */
+struct ifmediareq *ifmedia_getstate(int s);
Index: af_atalk.c
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/af_atalk.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/ifconfig/af_atalk.c -L sbin/ifconfig/af_atalk.c -u -r1.1.1.1 -r1.2
--- sbin/ifconfig/af_atalk.c
+++ sbin/ifconfig/af_atalk.c
@@ -29,14 +29,13 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: src/sbin/ifconfig/af_atalk.c,v 1.1 2004/12/08 19:18:07 sam Exp $";
+  "$FreeBSD: src/sbin/ifconfig/af_atalk.c,v 1.2 2007/02/24 23:55:46 sam Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <net/if.h>
-#include <net/route.h>		/* for RTX_IFA */
 
 #include <netatalk/at.h>
 
@@ -45,6 +44,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <ifaddrs.h>
 
 #include <arpa/inet.h>
 
@@ -81,32 +81,30 @@
 }
 
 static void
-at_status(int s __unused, const struct rt_addrinfo * info)
+at_status(int s __unused, const struct ifaddrs *ifa)
 {
 	struct sockaddr_at *sat, null_sat;
 	struct netrange *nr;
 
 	memset(&null_sat, 0, sizeof(null_sat));
 
-	sat = (struct sockaddr_at *)info->rti_info[RTAX_IFA];
+	sat = (struct sockaddr_at *)ifa->ifa_addr;
 	if (sat == NULL)
 		return;
 	nr = &sat->sat_range.r_netrange;
 	printf("\tatalk %d.%d range %d-%d phase %d",
 		ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
 		ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
-	if (flags & IFF_POINTOPOINT) {
-		/* note RTAX_BRD overlap with IFF_BROADCAST */
-		sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
-		if (!sat)
+	if (ifa->ifa_flags & IFF_POINTOPOINT) {
+		sat = (struct sockaddr_at *)ifa->ifa_dstaddr;
+		if (sat == NULL)
 			sat = &null_sat;
 		printf("--> %d.%d",
 			ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
 	}
-	if (flags & IFF_BROADCAST) {
-		/* note RTAX_BRD overlap with IFF_POINTOPOINT */
-		sat = (struct sockaddr_at *)info->rti_info[RTAX_BRD];
-		if (sat)
+	if (ifa->ifa_flags & IFF_BROADCAST) {
+		sat = (struct sockaddr_at *)ifa->ifa_broadaddr;
+		if (sat != NULL)
 			printf(" broadcast %d.%d",
 				ntohs(sat->sat_addr.s_net),
 				sat->sat_addr.s_node);
Index: ifconfig.8
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/ifconfig.8,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sbin/ifconfig/ifconfig.8 -L sbin/ifconfig/ifconfig.8 -u -r1.2 -r1.3
--- sbin/ifconfig/ifconfig.8
+++ sbin/ifconfig/ifconfig.8
@@ -26,9 +26,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     From: @(#)ifconfig.8	8.3 (Berkeley) 1/5/94
-.\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.95.2.14 2006/03/10 22:05:53 sam Exp $
+.\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.142.2.1 2007/11/11 17:45:56 sam Exp $
 .\"
-.Dd February 27, 2006
+.Dd October 31, 2007
 .Dt IFCONFIG 8
 .Os
 .Sh NAME
@@ -39,6 +39,7 @@
 .Op Fl L
 .Op Fl k
 .Op Fl m
+.Op Fl n
 .Ar interface
 .Op Cm create
 .Op Ar address_family
@@ -71,6 +72,8 @@
 .Op Fl u
 .Op Fl v
 .Op Fl C
+.Nm
+.Op Fl g Ar groupname
 .Sh DESCRIPTION
 The
 .Nm
@@ -178,6 +181,8 @@
 .Dq name unit ,
 for example,
 .Dq Li ed0 .
+.It Ar groupname
+List the interfaces in the given group.
 .El
 .Pp
 The following parameters may be set with
@@ -262,6 +267,22 @@
 transmit messages through that interface.
 If possible, the interface will be reset to disable reception as well.
 This action does not automatically disable routes using the interface.
+.It Cm group Ar group-name
+Assign the interface to a
+.Dq group .
+Any interface can be in multiple groups.
+.Pp
+Cloned interfaces are members of their interface family group by default.
+For example, a PPP interface such as
+.Em ppp0
+is a member of the PPP interface family group,
+.Em ppp .
+.\" The interface(s) the default route(s) point to are members of the
+.\" .Em egress
+.\" interface group.
+.It Cm -group Ar group-name
+Remove the interface from the given
+.Dq group .
 .It Cm eui64
 (Inet6 only.)
 Fill interface index
@@ -322,6 +343,11 @@
 and 802.11g
 .Pq Cm 11g
 operating modes.
+.It Cm inst Ar minst , Cm instance Ar minst
+Set the media instance to
+.Ar minst .
+This is useful for devices which have multiple physical layer interfaces
+.Pq PHYs .
 .It Cm name Ar name
 Set the interface name to
 .Ar name .
@@ -336,6 +362,31 @@
 If the driver supports user-configurable checksum offloading,
 disable receive (or transmit) checksum offloading on the interface.
 These settings may not always be independent of each other.
+.It Cm tso
+If the driver supports
+.Xr tcp 4
+segmentation offloading, enable TSO on the interface.
+Some drivers may not be able to support TSO for
+.Xr ip 4
+and
+.Xr ip6 4
+packets, so they may enable only one of them.
+.It Fl tso
+If the driver supports
+.Xr tcp 4
+segmentation offloading, disable TSO on the interface.
+It will always disable TSO for
+.Xr ip 4
+and
+.Xr ip6 4 .
+.It Cm lro
+If the driver supports
+.Xr tcp 4
+large receive offloading, enable LRO on the interface.
+.It Fl lro
+If the driver supports
+.Xr tcp 4
+large receive offloading, disable LRO on the interface.
 .It Cm vlanmtu , vlanhwtag
 If the driver offers user-configurable VLAN support, enable
 reception of extended frames or tag processing in hardware,
@@ -390,7 +441,7 @@
 The routing metric is used by the routing protocol
 .Pq Xr routed 8 .
 Higher metrics have the effect of making a route
-less favorable; metrics are counted as addition hops
+less favorable; metrics are counted as additional hops
 to the destination network or host.
 .It Cm mtu Ar n
 Set the maximum transmission unit of the interface to
@@ -549,13 +600,67 @@
 (a supplicant for client operation or an authenticator when
 operating as an access point).
 Modes are case insensitive.
+.It Cm bgscan
+Enable background scanning when operating as a station.
+Background scanning is a technique whereby a station associated to
+an access point will temporarily leave the channel to scan for
+neighboring stations.
+This allows a station to maintain a cache of nearby access points
+so that roaming between access points can be done without
+a lengthy scan operation.
+Background scanning is done only when a station is not busy and
+any outbound traffic will cancel a scan operation.
+Background scanning should never cause packets to be lost though
+there may be some small latency if outbound traffic interrupts a
+scan operation.
+By default background scanning is enabled if the device is capable.
+To disable background scanning, use
+.Fl bgscan .
+Background scanning is controlled by the
+.Cm bgscanidle
+and
+.Cm bgscanintvl
+parameters.
+Background scanning must be enabled for roaming; this is an artifact
+of the current implementation and may not be required in the future.
+.It Cm bgscanidle Ar idletime
+Set the minimum time a station must be idle (not transmitting or
+receiving frames) before a background scan is initiated.
+The
+.Ar idletime
+parameter is specified in milliseconds.
+By default a station must be idle at least 250 milliseconds before
+a background scan is initiated.
+The idle time may not be set to less than 100 milliseconds.
+.It Cm bgscanintvl Ar interval
+Set the interval at which background scanning is attempted.
+The
+.Ar interval
+parameter is specified in seconds.
+By default a background scan is considered every 300 seconds (5 minutes).
+The 
+.Ar interval
+may not be set to less than 15 seconds.
 .It Cm bintval Ar interval
 Set the interval at which beacon frames are sent when operating in
 ad-hoc or ap mode.
 The
 .Ar interval
-parameter is specified in TU's (1/1024 msecs).
+parameter is specified in TU's (1024 usecs).
 By default beacon frames are transmitted every 100 TU's.
+.It Cm bmissthreshold Ar count
+Set the number of consecutive missed beacons at which the station
+will attempt to roam (i.e., search for a new access point).
+The
+.Ar count
+parameter must be in the range 1 to 255; though the
+upper bound may be reduced according to device capabilities.
+The default threshold is 7 consecutive missed beacons; but
+this may be overridden by the device driver.
+Another name for the
+.Cm bmissthreshold
+parameter is
+.Cm bmiss .
 .It Cm bssid Ar address
 Specify the MAC address of the access point to use when operating
 as a station in a BSS network.
@@ -565,7 +670,7 @@
 or
 .Cm -
 for the address.
-This option is useful when more than one access points have the same SSID.
+This option is useful when more than one access point uses the same SSID.
 Another name for the
 .Cm bssid
 parameter is
@@ -608,6 +713,54 @@
 adaptors ignore this setting unless you are in ad-hoc mode.
 Alternatively the frequency, in megahertz, may be specified
 instead of the channel number.
+.Pp
+When there are several ways to use a channel the channel
+number/frequency may be appended with attributes to clarify.
+For example, if a device is capable of operating on channel 6
+with 802.11n and 802.11g then one can specify that g-only use
+should be used by specifying ``6:g''.
+Similarly the channel width can be specified by appending it
+with ``/''; e.g. ``6/40'' specifies a 40MHz wide channel,
+These attributes can be combined as in: ``6:ht/40''.
+The full set of flags specified following a `:'' are:
+.Cm a
+(802.11a),
+.Cm b
+(802.11b),
+.Cm d
+(Atheros Dynamic Turbo mode),
+.Cm g
+(802.11g),
+.Cm h
+or
+.Cm n
+(802.11n aka HT),
+.Cm s
+(Atheros Static Turbo mode),
+and
+.Cm t
+(Atheros Dynamic Turbo mode, or appended to ``st'' and ``dt'').
+The full set of channel widths following a '/' are:
+.Cm 5 
+(5MHz aka quarter-rate channel),
+.Cm 10 
+(10MHz aka half-rate channel),
+.Cm 20 
+(20MHz mostly for use in specifying ht20),
+and
+.Cm 40 
+(40MHz mostly for use in specifying ht40),
+In addition,
+a 40MHz HT channel specification may include the location
+of the extension channel by appending ``+'' or ``-'' for above and below,
+respectively; e.g. ``2437:ht/40+'' specifies 40MHz wide HT operation 
+with the center channel at frequency 2437 and the extension channel above.
+.It Cm doth
+Enable inclusion of an 802.11h country information element in beacon
+frames transmitted when operating as an access point.
+By default 802.11h is enabled if the device is capable.
+To disable 802.11h use
+.Fl doth .
 .It Cm deftxkey Ar index
 Set the default key to use for transmission.
 Typically this is only set when using WEP encryption.
@@ -624,6 +777,23 @@
 specifies the number of beacon intervals between DTIM
 and must be in the range 1 to 15.
 By default DTIM is 1 (i.e., DTIM occurs at each beacon).
+.It Cm dturbo
+Enable the use of Atheros Dynamic Turbo mode when communicating with
+another Dynamic Turbo-capable station.
+Dynamic Turbo mode is an Atheros-specific mechanism by which
+stations switch between normal 802.11 operation and a ``boosted''
+mode in which a 40MHz wide channel is used for communication.
+Stations using Dynamic Turbo mode operate boosted only when the
+channel is free of non-dturbo stations; when a non-dturbo station
+is identified on the channel all stations will automatically drop
+back to normal operation.
+By default, Dynamic Turbo mode is not enabled, even if the device is capable.
+Note that turbo mode (dynamic or static) is only allowed on some
+channels depending on the regulatory constraints; use the
+.Cm list chan
+command to identify the channels where turbo mode may be used.
+To disable Dynamic Turbo mode use
+.Fl dturbo .
 .It Cm fragthreshold Ar length
 Set the threshold for which transmitted frames are broken into fragments.
 The
@@ -646,6 +816,19 @@
 undirected probe request frames are answered.
 To re-enable the broadcast of the SSID etc., use
 .Fl hidessid .
+.It Cm ff
+Enable the use of Atheros Fast Frames when communicating with
+another Fast Frames-capable station.
+Fast Frames are an encapsulation technique by which two 802.3
+frames are transmitted in a single 802.11 frame.
+This can noticeably improve throughput but requires that the
+receiving station understand how to decapsulate the frame.
+Fast frame use is negotiated using the Atheros 802.11 vendor-specific
+protocol extension so enabling use is safe when communicating with
+non-Atheros devices.
+By default, use of fast frames is enabled if the device is capable.
+To explicitly disable fast frames, use
+.Fl ff .
 .It Cm list active
 Display the list of channels available for use taking into account
 any restrictions set with the
@@ -669,7 +852,8 @@
 Channels identified as
 .Ql 11a Turbo
 may be used only for Atheros' Static Turbo mode
-.Pq specified with Cm mediaopt turbo .
+(specified with
+. Cm mediaopt turbo ) .
 Channels marked with a
 .Ql *
 have a regulatory constraint that they be passively scanned.
@@ -679,6 +863,9 @@
 on the channel.
 .Cm list freq
 is another way of requesting this information.
+By default a compacted list of channels is displayed; if the
+.Fl v
+option is specified then all channels are shown.
 .It Cm list mac
 Display the current MAC Access Control List state.
 Each address is prefixed with a character that indicates the
@@ -693,10 +880,15 @@
 .It Cm list scan
 Display the access points and/or ad-hoc neighbors
 located in the vicinity.
+The
+.Fl v
+flag may be used to display long SSIDs.
+.Fl v
+also causes received information elements to be displayed symbolicaly.
 This information may be updated automatically by the adaptor
 and/or with a
 .Cm scan
-request.
+request or through background scanning.
 .Cm list ap
 is another way of requesting this information.
 .It Cm list sta
@@ -704,6 +896,38 @@
 currently associated.
 When operating in ad-hoc mode display stations identified as
 neighbors in the IBSS.
+When operating in station mode display the access point.
+Capabilities advertised by the stations are described under
+the
+.Cm scan
+request.
+Depending on the capabilities of the stations the following
+flags can be included in the output:
+.Bl -tag -width 3n
+.It Li A
+Authorized.
+Indicates that the station is permitted to send/receive data frames.
+.It Li E
+Extended Rate Phy (ERP).
+Indicates that the station is operating in an 802.11g network
+using extended transmit rates.
+.It Li H
+High Throughput (HT).
+Indicates that the station is using MCS to send/receive frames.
+.It Li P
+Power Save.
+Indicates that the station is operating in power save mode.
+.It Li Q
+Quality of Service (QoS).
+Indicates that the station is using QoS encapsulation for
+data frame.
+QoS encapsulation is enabled only when WME mode is enabled.
+.El
+.Pp
+By default information elements received from associated stations
+are displayed in a short form; the
+.Fl v
+flag causes this information to be displayed symbolicaly.
 .It Cm list wme
 Display the current parameters to use when operating in WME mode.
 When WME mode is enabled for an adaptor this information will be
@@ -714,7 +938,7 @@
 directive for information on the various parameters.
 .It Cm mcastrate Ar rate
 Set the rate for transmitting multicast/broadcast frames.
-Rates are specified as megabits/second in decimal; e.g. 5.5 for 5.5 Mb/s.
+Rates are specified as megabits/second in decimal; e.g.\& 5.5 for 5.5 Mb/s.
 This rate should be valid for the current operating conditions;
 if an invalid rate is specified drivers are free to chose an
 appropriate rate.
@@ -724,15 +948,15 @@
 periodically turning off the radio and listening for
 messages from the access point telling it there are packets waiting.
 The station must then retrieve the packets.
-When operating as an access point, the station must honor power
-save operation of associated clients.
-Not all devices support power save operation, either as a client
-or as an access point.
+Not all devices support power save operation as a client.
+The 802.11 specification requires that all access points support
+power save but some drivers do not.
 Use
 .Fl powersave
-to disable powersave operation.
+to disable powersave operation when operating as a client.
 .It Cm powersavesleep Ar sleep
-Set the desired max powersave sleep time in milliseconds.
+Set the desired max powersave sleep time in TU's (1024 usecs).
+By default the max powersave sleep time is 100 TU's.
 .It Cm protmode Ar technique
 For interfaces operating in 802.11g, use the specified
 .Ar technique
@@ -744,6 +968,9 @@
 .Cm rtscts
 (RTS/CTS).
 Technique names are case insensitive.
+Not all devices support
+.Cm cts
+as a protection technique.
 .It Cm pureg
 When operating as an access point in 802.11g mode allow only
 11g-capable stations to associate (11b-only stations are not
@@ -766,8 +993,81 @@
 By default, the device is left to handle this if it is
 capable; otherwise, the operating system will automatically
 attempt to reestablish communication.
-Manual mode is mostly useful when an application wants to
-control the selection of an access point.
+Manual mode is used by applications such as
+.Xr wpa_supplicant 8
+that want to control the selection of an access point.
+.It Cm roam:rssi11a Ar rssi
+Set the threshold for controlling roaming when operating in an
+802.11a BSS.
+The
+.Ar rssi
+parameter specifies the receive signal strength in dBm units
+at which roaming should be considered.
+If the current rssi drops below this setting and background scanning
+is enabled, then the system will check if a more desirable access point is
+available and switch over to it.
+The current scan cache contents are used if they are considered
+valid according to the
+.Cm scanvalid
+parameter; otherwise a background scan operation is triggered before
+any selection occurs.
+By default
+.Ar rssi
+is set to 7 dBm.
+.It Cm roam:rssi11b Ar rssi
+Set the threshold for controlling roaming when operating in an
+802.11b-only BSS.
+See 
+.Cm roam:rssi11a
+for a description of this parameter.
+By default
+.Ar rssi
+is set to 7 dBm.
+.It Cm roam:rssi11g Ar rssi
+Set the threshold for controlling roaming when operating in a
+(mixed) 802.11g BSS.
+See 
+.Cm roam:rssi11a
+for a description of this parameter.
+By default
+.Ar rssi
+is set to 7 dBm.
+.It Cm roam:rate11a Ar rate
+Set the threshold for controlling roaming when operating in an
+802.11a BSS.
+The
+.Ar rate
+parameter specifies the transmit rate in megabits
+at which roaming should be considered.
+If the current transmit rate drops below this setting and background scanning
+is enabled, then the system will check if a more desirable access point is
+available and switch over to it.
+The current scan cache contents are used if they are considered
+valid according to the
+.Cm scanvalid
+parameter; otherwise a background scan operation is triggered before
+any selection occurs.
+By default
+.Ar rate
+is set to 12 Mb/s.
+.It Cm roam:rate11b Ar rate
+Set the threshold for controlling roaming when operating in an
+802.11b-only BSS.
+See 
+.Cm roam:rate11a
+for a description of this parameter.
+By default
+.Ar rate
+is set to 1 Mb/s.
+.It Cm roam:rate11g Ar rate
+Set the threshold for controlling roaming when operating in a
+(mixed) 802.11g BSS.
+See 
+.Cm roam:rate11a
+for a description of this parameter.
+By default
+.Ar rate
+is set to 5 Mb/s.
 .It Cm rtsthreshold Ar length
 Set the threshold for which
 transmitted frames are preceded by transmission of an
@@ -801,6 +1101,20 @@
 Depending on the capabilities of the APs, the following
 flags can be included in the output:
 .Bl -tag -width 3n
+.It Li A
+Channel Agility.
+Indicates that the station support channel hopping as described by the
+IEEE 802.11b specification.
+.It Li B
+Packet Binary Convolution Code (PBCC).
+A modulation alternative to the standard OFDM method.
+.It Dv C
+Pollreq
+.It Dv c
+Pollable
+.It Dv D
+Direct Sequence Spread Spectrum (DSSSOFDM).
+Indicates the the station supports DSSS modulation.
 .It Li E
 Extended Service Set (ESS).
 Indicates that the station is part of an infrastructure network
@@ -816,6 +1130,10 @@
 This means that this BSS requires the station to
 use cryptographic means such as WEP, TKIP or AES-CCMP to
 encrypt/decrypt data frames being exchanged with others.
+.It Dv R
+Robust Security Network (RSN).
+Indicates that the station supports the IEEE 802.11i authentication
+and key management protocol.
 .It Li S
 Short Preamble.
 Indicates that the network is using short preambles (defined
@@ -827,14 +1145,50 @@
 Indicates that the network is using a short slot time.
 .El
 .Pp
+Interesting information elements captured from the neighboring
+stations are displayed at the end of each row.
+Possible elements are:
+.Cm WME
+(station supports WME),
+.Cm WPA
+(station supports WPA),
+.Cm RSN
+(station supports 802.11i/RSN),
+.Cm HT
+(station supports 802.11n/HT communication),
+.Cm ATH
+(station supoprts Atheros protocol extensions),
+.Cm VEN
+(station supports unknown vendor-specific extensions).
+If the
+.Fl v
+flag is used the information element contents will be shown.
+.Pp
 The
 .Cm list scan
 request can be used to show recent scan results without
 initiating a new scan.
+.Pp
+The
+.Fl v
+flag may be used to prevent the shortening of long SSIDs.
+.It Cm scanvalid Ar threshold
+Set the maximum time the scan cache contents are considered valid;
+i.e. will be used without first triggering a scan operation to
+refresh the data.
+The
+.Ar threshold
+parameter is specified in seconds and defaults to 60 seconds.
+The minimum setting for
+.Ar threshold
+is 10 seconds.
+One should take care setting this threshold; if it is set too low
+then attempts to roam to another access point may trigger unnecessary
+background scan operations.
 .It Cm stationname Ar name
 Set the name of this station.
-It appears that the station name is not really part of the IEEE 802.11
-protocol though all interfaces seem to support it.
+The station name is not part of the IEEE 802.11
+protocol though some interfaces support it.
 As such it only
 seems to be meaningful to identical or virtually identical equipment.
 Setting the station name is identical in syntax to setting the SSID.
@@ -842,9 +1196,7 @@
 Set the power used to transmit frames.
 The
 .Ar power
-argument
-is a unitless value in the range 0 to 100 that is interpreted
-by drivers to derive a device-specific value.
+argument is specified in .5 dBm units.
 Out of range values are truncated.
 Typically only a few discreet power settings are available and
 the driver will use the setting closest to the specified value.
@@ -1146,6 +1498,28 @@
 Clear the
 .Dq learning
 attribute on a member interface.
+.It Cm sticky Ar interface
+Mark an interface as a
+.Dq sticky
+interface.
+Dynamically learned address entries are treated at static once entered into
+the cache.
+Sticky entries are never aged out of the cache or replaced, even if the
+address is seen on a different interface.
+.It Cm -sticky Ar interface
+Clear the
+.Dq sticky
+attribute on a member interface.
+.It Cm private Ar interface
+Mark an interface as a
+.Dq private
+interface.
+A private interface does not forward any traffic to any other port that is also
+a private interface.
+.It Cm -private Ar interface
+Clear the
+.Dq private
+attribute on a member interface.
 .It Cm span Ar interface
 Add the interface named by
 .Ar interface
@@ -1168,38 +1542,104 @@
 Disable Spanning Tree protocol on
 .Ar interface .
 This is the default for all interfaces added to a bridge.
+.It Cm edge Ar interface
+Set
+.Ar interface
+as an edge port.
+An edge port connects directly to end stations cannot create bridging
+loops in the network, this allows it to transition straight to forwarding.
+.It Cm -edge Ar interface
+Disable edge status on
+.Ar interface .
+.It Cm autoedge Ar interface
+Allow
+.Ar interface
+to automatically detect edge status.
+This is the default for all interfaces added to a bridge.
+.It Cm -autoedge Ar interface
+Disable automatic edge status on
+.Ar interface .
+.It Cm ptp Ar interface
+Set the
+.Ar interface
+as a point to point link.
+This is required for straight transitions to forwarding and
+should be enabled on a direct link to another RSTP capable switch.
+.It Cm -ptp Ar interface
+Disable point to point link status on
+.Ar interface .
+This should be disabled for a half duplex link and for an interface
+connected to a shared network segment,
+like a hub or a wireless network.
+.It Cm autoptp Ar interface
+Automatically detect the point to point status on
+.Ar interface
+by checking the full duplex link status.
+This is the default for interfaces added to the bridge.
+.It Cm -autoptp Ar interface
+Disable automatic point to point link detection on
+.Ar interface .
 .It Cm maxage Ar seconds
 Set the time that a Spanning Tree protocol configuration is valid.
 The default is 20 seconds.
-The minimum is 1 second and the maximum is 255 seconds.
+The minimum is 6 seconds and the maximum is 40 seconds.
 .It Cm fwddelay Ar seconds
 Set the time that must pass before an interface begins forwarding
 packets when Spanning Tree is enabled.
 The default is 15 seconds.
-The minimum is 1 second and the maximum is 255 seconds.
+The minimum is 4 seconds and the maximum is 30 seconds.
 .It Cm hellotime Ar seconds
 Set the time between broadcasting of Spanning Tree protocol
 configuration messages.
+The hello time may only be changed when operating in legacy stp mode.
 The default is 2 seconds.
-The minimum is 1 second and the maximum is 255 seconds.
+The minimum is 1 second and the maximum is 2 seconds.
 .It Cm priority Ar value
 Set the bridge priority for Spanning Tree.
 The default is 32768.
-The minimum is 0 and the maximum is 65536.
+The minimum is 0 and the maximum is 61440.
+.It Cm proto Ar value
+Set the Spanning Tree protocol.
+The default is rstp.
+The available options are stp and rstp.
+.It Cm holdcnt Ar value
+Set the transmit hold count for Spanning Tree.
+This is the number of packets transmitted before being rate limited.
+The default is 6.
+The minimum is 1 and the maximum is 10.
 .It Cm ifpriority Ar interface Ar value
 Set the Spanning Tree priority of
 .Ar interface
 to
 .Ar value .
 The default is 128.
-The minimum is 0 and the maximum is 255.
+The minimum is 0 and the maximum is 240.
 .It Cm ifpathcost Ar interface Ar value
 Set the Spanning Tree path cost of
 .Ar interface
 to
 .Ar value .
-The default is 55.
-The minimum is 0 and the maximum is 65535.
+The default is calculated from the link speed.
+To change a previously selected path cost back to automatic, set the
+cost to 0.
+The minimum is 1 and the maximum is 200000000.
+.El
+.Pp
+The following parameters are specific to lagg interfaces:
+.Bl -tag -width indent
+.It Cm laggport Ar interface
+Add the interface named by
+.Ar interface
+as a port of the aggregation interface.
+.It Cm -laggport Ar interface
+Remove the interface named by
+.Ar interface
+from the aggregation interface.
+.It Cm laggproto Ar proto
+Set the aggregation protocol.
+The default is failover.
+The available options are failover, fec, lacp, loadbalance, roundrobin and
+none.
 .El
 .Pp
 The following parameters are specific to IP tunnel interfaces,
@@ -1231,7 +1671,7 @@
 .It Cm maxupd Ar n
 Set the maximum number of updates for a single state which
 can be collapsed into one.
-This is an 8-bit number; the default value is 128. 
+This is an 8-bit number; the default value is 128.
 .El
 .Pp
 The following parameters are specific to
@@ -1397,11 +1837,74 @@
 the current user.
 This information is not printed by default, as it may be considered
 sensitive.
+.Pp 
+If the network interface driver is not present in the kernel then
+.Nm
+will attempt to load it.
+The
+.Fl n
+flag disables this behavior.
 .Pp
 Only the super-user may modify the configuration of a network interface.
 .Sh NOTES
 The media selection system is relatively new and only some drivers support
 it (or have need for it).
+.Sh EXAMPLES
+Assign the IPv4 address
+.Li 192.0.2.10 ,
+with a network mask of
+.Li 255.255.255.0 ,
+to the interface
+.Li fxp0 :
+.Dl # ifconfig fxp0 inet 192.0.2.10 netmask 255.255.255.0
+.Pp
+Add the IPv4 address
+.Li 192.0.2.45 ,
+with the CIDR network prefix
+.Li /28 ,
+to the interface
+.Li ed0 ,
+using
+.Cm add
+as a synonym for the canonical form of the option
+.Cm alias :
+.Dl # ifconfig ed0 inet 192.0.2.45/28 add
+.Pp
+Remove the IPv4 address
+.Li 192.0.2.45
+from the interface
+.Li ed0 :
+.Dl # ifconfig ed0 inet 192.0.2.45 -alias
+.Pp
+Add the IPv6 address
+.Li 2001:DB8:DBDB::123/48
+to the interface
+.Li em0 :
+.Dl # ifconfig em0 inet6 2001:db8:bdbd::123 prefixlen 48 alias
+Note that lower case hexadecimal IPv6 addresses are acceptable.
+.Pp
+Remove the IPv6 address added in the above example,
+using the
+.Li /
+character as shorthand for the network prefix,
+and using
+.Cm delete
+as a synonym for the canonical form of the option
+.Fl alias :
+.Dl # ifconfig em0 inet6 2001:db8:bdbd::123/48 delete
+.Pp
+Configure the interface
+.Li xl0 ,
+to use 100baseTX, full duplex Ethernet media options:
+.Dl # ifconfig xl0 media 100baseTX mediaopt full-duplex
+.Pp
+Create the software network interface
+.Li gif1 :
+.Dl # ifconfig gif1 create
+.Pp
+Destroy the software network interface
+.Li gif1 :
+.Dl # ifconfig gif1 destroy
 .Sh DIAGNOSTICS
 Messages indicating the specified interface does not exist, the
 requested address is unknown, or the user is not privileged and
@@ -1433,5 +1936,5 @@
 .Pp
 If you delete such an address using
 .Nm ,
-the kernel may act very oddly.
+the kernel may act very odd.
 Do this at your own risk.
Index: ifclone.c
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/ifclone.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/ifconfig/ifclone.c -L sbin/ifconfig/ifclone.c -u -r1.1.1.1 -r1.2
--- sbin/ifconfig/ifclone.c
+++ sbin/ifconfig/ifclone.c
@@ -29,7 +29,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: src/sbin/ifconfig/ifclone.c,v 1.1 2004/12/08 19:18:07 sam Exp $";
+  "$FreeBSD: src/sbin/ifconfig/ifclone.c,v 1.3 2006/08/12 18:07:17 yar Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -88,49 +88,64 @@
 	free(buf);
 }
 
+static clone_callback_func *clone_cb = NULL;
+
 void
-clone_create(void)
+clone_setcallback(clone_callback_func *p)
 {
-	int s;
+	if (clone_cb != NULL && clone_cb != p)
+		errx(1, "conflicting device create parameters");
+	clone_cb = p;
+}
 
-	s = socket(AF_INET, SOCK_DGRAM, 0);
-	if (s == -1)
-		err(1, "socket(AF_INET,SOCK_DGRAM)");
+/*
+ * Do the actual clone operation.  Any parameters must have been
+ * setup by now.  If a callback has been setup to do the work
+ * then defer to it; otherwise do a simple create operation with
+ * no parameters.
+ */
+static void
+ifclonecreate(int s, void *arg)
+{
+	struct ifreq ifr;
 
 	memset(&ifr, 0, sizeof(ifr));
 	(void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-	if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
-		err(1, "SIOCIFCREATE");
+	if (clone_cb == NULL) {
+		/* NB: no parameters */
+		if (ioctl(s, SIOCIFCREATE2, &ifr) < 0)
+			err(1, "SIOCIFCREATE2");
+	} else {
+		clone_cb(s, &ifr);
+	}
 
 	/*
-	 * If we get a different name back then we put in, we probably
-	 * want to print it out, but we might change our mind later so
-	 * we just signal our intrest and leave the printout for later.
+	 * If we get a different name back than we put in, print it.
 	 */
-	if (strcmp(name, ifr.ifr_name) != 0) {
-		printname = 1;
+	if (strncmp(name, ifr.ifr_name, sizeof(name)) != 0) {
 		strlcpy(name, ifr.ifr_name, sizeof(name));
+		printf("%s\n", name);
 	}
-
-	close(s);
 }
 
-static void
-clone_destroy(const char *val, int d, int s, const struct afswtch *rafp)
+static
+DECL_CMD_FUNC(clone_create, arg, d)
 {
+	callback_register(ifclonecreate, NULL);
+}
 
+static
+DECL_CMD_FUNC(clone_destroy, arg, d)
+{
 	(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
 	if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
 		err(1, "SIOCIFDESTROY");
-	/*
-	 * If we create and destroy an interface in the same command,
-	 * there isn't any reason to print it's name.
-	 */
-	printname = 0;
 }
 
 static struct cmd clone_cmds[] = {
+	DEF_CMD("create",	0,	clone_create),
 	DEF_CMD("destroy",	0,	clone_destroy),
+	DEF_CMD("plumb",	0,	clone_create),
 	DEF_CMD("unplumb",	0,	clone_destroy),
 };
 
Index: ifconfig.c
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sbin/ifconfig/ifconfig.c -L sbin/ifconfig/ifconfig.c -u -r1.2 -r1.3
--- sbin/ifconfig/ifconfig.c
+++ sbin/ifconfig/ifconfig.c
@@ -38,7 +38,7 @@
 static char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
 #endif
 static const char rcsid[] =
-  "$FreeBSD: src/sbin/ifconfig/ifconfig.c,v 1.113.2.5 2006/03/18 21:59:22 glebius Exp $";
+  "$FreeBSD: src/sbin/ifconfig/ifconfig.c,v 1.134 2007/10/04 09:45:41 thompsa Exp $";
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -62,6 +62,7 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 
+#include <ifaddrs.h>
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
@@ -81,23 +82,20 @@
 struct	ifreq ifr;
 
 char	name[IFNAMSIZ];
-int	flags;
 int	setaddr;
-int	setipdst;
 int	setmask;
 int	doalias;
 int	clearaddr;
 int	newaddr = 1;
 int	verbose;
+int	noload;
 
 int	supmedia = 0;
 int	printkeys = 0;		/* Print keying material for interfaces. */
-int	printname = 0;		/* Print the name of the created interface. */
 
 static	int ifconfig(int argc, char *const *argv, const struct afswtch *afp);
-static	void status(const struct afswtch *afp, int addrcount,
-		    struct sockaddr_dl *sdl, struct if_msghdr *ifm,
-		    struct ifa_msghdr *ifam);
+static	void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
+		struct ifaddrs *ifa);
 static	void tunnel_status(int s);
 static	void usage(void);
 
@@ -142,22 +140,20 @@
 main(int argc, char *argv[])
 {
 	int c, all, namesonly, downonly, uponly;
-	int need_nl = 0, count = 0;
 	const struct afswtch *afp = NULL;
-	int addrcount, ifindex;
-	struct if_msghdr *ifm, *nextifm;
-	struct ifa_msghdr *ifam;
-	struct sockaddr_dl *sdl;
-	char *buf, *lim, *next;
-	size_t needed;
-	int mib[6];
-	char options[1024];
+	int ifindex;
+	struct ifaddrs *ifap, *ifa;
+	struct ifreq paifr;
+	const struct sockaddr_dl *sdl;
+	char options[1024], *cp;
+	const char *ifname;
 	struct option *p;
+	size_t iflen;
 
-	all = downonly = uponly = namesonly = verbose = 0;
+	all = downonly = uponly = namesonly = noload = verbose = 0;
 
 	/* Parse leading line options */
-	strlcpy(options, "adklmuv", sizeof(options));
+	strlcpy(options, "adklmnuv", sizeof(options));
 	for (p = opts; p != NULL; p = p->next)
 		strlcat(options, p->opt, sizeof(options));
 	while ((c = getopt(argc, argv, options)) != -1) {
@@ -177,6 +173,9 @@
 		case 'm':	/* show media choices in status */
 			supmedia = 1;
 			break;
+		case 'n':	/* suppress module loading */
+			noload++;
+			break;
 		case 'u':	/* restrict scan to "up" interfaces */
 			uponly++;
 			break;
@@ -214,6 +213,7 @@
 		if (argc > 1)
 			usage();
 
+		ifname = NULL;
 		ifindex = 0;
 		if (argc == 1) {
 			afp = af_getbyname(*argv);
@@ -228,27 +228,30 @@
 		if (argc < 1)
 			usage();
 
-		strncpy(name, *argv, sizeof(name));
+		ifname = *argv;
 		argc--, argv++;
 
 		/* check and maybe load support for this interface */
-		ifmaybeload(name);
+		ifmaybeload(ifname);
 
-		/*
-		 * NOTE:  We must special-case the `create' command right
-		 * here as we would otherwise fail when trying to find
-		 * the interface.
-		 */
-		if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
-		    strcmp(argv[0], "plumb") == 0)) {
-			clone_create();
-			argc--, argv++;
-			if (argc == 0)
-				goto end;
+		ifindex = if_nametoindex(ifname);
+		if (ifindex == 0) {
+			/*
+			 * NOTE:  We must special-case the `create' command
+			 * right here as we would otherwise fail when trying
+			 * to find the interface.
+			 */
+			if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
+			    strcmp(argv[0], "plumb") == 0)) {
+				iflen = strlcpy(name, ifname, sizeof(name));
+				if (iflen >= sizeof(name))
+					errx(1, "%s: cloning name too long",
+					    ifname);
+				ifconfig(argc, argv, NULL);
+				exit(0);
+			}
+			errx(1, "interface %s does not exist", ifname);
 		}
-		ifindex = if_nametoindex(name);
-		if (ifindex == 0)
-			errx(1, "interface %s does not exist", name);
 	}
 
 	/* Check for address family */
@@ -258,109 +261,59 @@
 			argc--, argv++;
 	}
 
-retry:
-	mib[0] = CTL_NET;
-	mib[1] = PF_ROUTE;
-	mib[2] = 0;
-	mib[3] = 0;			/* address family */
-	mib[4] = NET_RT_IFLIST;
-	mib[5] = ifindex;		/* interface index */
-
-	/* if particular family specified, only ask about it */
-	if (afp != NULL)
-		mib[3] = afp->af_af;
-
-	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
-		errx(1, "iflist-sysctl-estimate");
-	if ((buf = malloc(needed)) == NULL)
-		errx(1, "malloc");
-	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
-		if (errno == ENOMEM && count++ < 10) {
-			warnx("Routing table grew, retrying");
-			free(buf);
-			sleep(1);
-			goto retry;
+	if (getifaddrs(&ifap) != 0)
+		err(EXIT_FAILURE, "getifaddrs");
+	cp = NULL;
+	ifindex = 0;
+	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+		memset(&paifr, 0, sizeof(paifr));
+		strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
+		if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
+			memcpy(&paifr.ifr_addr, ifa->ifa_addr,
+			    ifa->ifa_addr->sa_len);
 		}
-		errx(1, "actual retrieval of interface table");
-	}
-	lim = buf + needed;
-
-	next = buf;
-	while (next < lim) {
 
-		ifm = (struct if_msghdr *)next;
-		
-		if (ifm->ifm_type == RTM_IFINFO) {
-			if (ifm->ifm_data.ifi_datalen == 0)
-				ifm->ifm_data.ifi_datalen = sizeof(struct if_data);
-			sdl = (struct sockaddr_dl *)((char *)ifm + sizeof(struct if_msghdr) -
-			     sizeof(struct if_data) + ifm->ifm_data.ifi_datalen);
-			flags = ifm->ifm_flags;
-		} else {
-			fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n");
-			fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO,
-				ifm->ifm_type);
-			fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen);
-			fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next,
-				lim);
-			exit (1);
+		if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
+			continue;
+		if (ifa->ifa_addr->sa_family == AF_LINK)
+			sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
+		else
+			sdl = NULL;
+		if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0)
+			continue;
+		iflen = strlcpy(name, ifa->ifa_name, sizeof(name));
+		if (iflen >= sizeof(name)) {
+			warnx("%s: interface name too long, skipping",
+			    ifa->ifa_name);
+			continue;
 		}
+		cp = ifa->ifa_name;
 
-		next += ifm->ifm_msglen;
-		ifam = NULL;
-		addrcount = 0;
-		while (next < lim) {
-
-			nextifm = (struct if_msghdr *)next;
-
-			if (nextifm->ifm_type != RTM_NEWADDR)
-				break;
-
-			if (ifam == NULL)
-				ifam = (struct ifa_msghdr *)nextifm;
-
-			addrcount++;
-			next += nextifm->ifm_msglen;
-		}
-		memcpy(name, sdl->sdl_data,
-		    sizeof(name) < sdl->sdl_nlen ?
-		    sizeof(name)-1 : sdl->sdl_nlen);
-		name[sizeof(name) < sdl->sdl_nlen ?
-		    sizeof(name)-1 : sdl->sdl_nlen] = '\0';
-
-		if (all || namesonly) {
-			if (uponly)
-				if ((flags & IFF_UP) == 0)
-					continue; /* not up */
-			if (downonly)
-				if (flags & IFF_UP)
-					continue; /* not down */
-			if (namesonly) {
-				if (afp == NULL || afp->af_af != AF_LINK ||
-				    sdl->sdl_type == IFT_ETHER) {
-					if (need_nl)
-						putchar(' ');
-					fputs(name, stdout);
-					need_nl++;
-				}
-				continue;
-			}
+		if (downonly && (ifa->ifa_flags & IFF_UP) != 0)
+			continue;
+		if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
+			continue;
+		ifindex++;
+		/*
+		 * Are we just listing the interfaces?
+		 */
+		if (namesonly) {
+			if (ifindex > 1)
+				printf(" ");
+			fputs(name, stdout);
+			continue;
 		}
 
 		if (argc > 0)
 			ifconfig(argc, argv, afp);
 		else
-			status(afp, addrcount, sdl, ifm, ifam);
+			status(afp, sdl, ifa);
 	}
-	free(buf);
+	if (namesonly)
+		printf("\n");
+	freeifaddrs(ifap);
 
-	if (namesonly && need_nl > 0)
-		putchar('\n');
-end:
-	if (printname)
-		printf("%s\n", name);
-
-	exit (0);
+	exit(0);
 }
 
 static struct afswtch *afs = NULL;
@@ -662,7 +615,6 @@
 	if (inet == NULL)
 		return;
 	inet->af_getaddr(addr, DSTADDR);
-	setipdst++;
 	clearaddr = 0;
 	newaddr = 0;
 }
@@ -703,6 +655,7 @@
 setifflags(const char *vname, int value, int s, const struct afswtch *afp)
 {
 	struct ifreq		my_ifr;
+	int flags;
 
 	bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
 
@@ -727,6 +680,7 @@
 void
 setifcap(const char *vname, int value, int s, const struct afswtch *afp)
 {
+	int flags;
 
  	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
  		Perror("ioctl (SIOCGIFCAP)");
@@ -738,6 +692,7 @@
 		flags &= ~value;
 	} else
 		flags |= value;
+	flags &= ifr.ifr_reqcap;
 	ifr.ifr_reqcap = flags;
 	if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0)
 		Perror(vname);
@@ -782,31 +737,6 @@
 	}
 	strlcpy(name, newname, sizeof(name));
 	free(newname);
-
-	/*
-	 * Even if we just created the interface, we don't need to print
-	 * its name because we just nailed it down separately.
-	 */
-	printname = 0;
-}
-
-/*
- * Expand the compacted form of addresses as returned via the
- * configuration read via sysctl().
- */
-static void
-rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
-{
-	struct sockaddr *sa;
-	int i;
-
-	memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
-	for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
-		if ((rtinfo->rti_addrs & (1 << i)) == 0)
-			continue;
-		rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
-		cp += SA_SIZE(sa);
-	}
 }
 
 #define	IFFBITS \
@@ -815,17 +745,18 @@
 "\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP\25NEEDSGIANT"
 
 #define	IFCAPBITS \
-"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING"
+"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
+"\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO"
 
 /*
  * Print the status of the interface.  If an address family was
  * specified, show only it; otherwise, show them all.
  */
 static void
-status(const struct afswtch *afp, int addrcount, struct	sockaddr_dl *sdl,
-    struct if_msghdr *ifm, struct ifa_msghdr *ifam)
+status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
+	struct ifaddrs *ifa)
 {
-	struct	rt_addrinfo info;
+	struct ifaddrs *ift;
 	int allfamilies, s;
 	struct ifstat ifs;
 
@@ -843,11 +774,11 @@
 		err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
 
 	printf("%s: ", name);
-	printb("flags", flags, IFFBITS);
-	if (ifm->ifm_data.ifi_metric)
-		printf(" metric %ld", ifm->ifm_data.ifi_metric);
-	if (ifm->ifm_data.ifi_mtu)
-		printf(" mtu %ld", ifm->ifm_data.ifi_mtu);
+	printb("flags", ifa->ifa_flags, IFFBITS);
+	if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
+		printf(" metric %d", ifr.ifr_metric);
+	if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
+		printf(" mtu %d", ifr.ifr_mtu);
 	putchar('\n');
 
 	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
@@ -863,22 +794,20 @@
 
 	tunnel_status(s);
 
-	while (addrcount > 0) {
-		info.rti_addrs = ifam->ifam_addrs;
-		/* Expand the compacted addresses */
-		rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
-			  &info);
-
+	for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
+		if (ift->ifa_addr == NULL)
+			continue;
+		if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
+			continue;
 		if (allfamilies) {
 			const struct afswtch *p;
-			p = af_getbyfamily(info.rti_info[RTAX_IFA]->sa_family);
+			p = af_getbyfamily(ift->ifa_addr->sa_family);
 			if (p != NULL && p->af_status != NULL)
-				p->af_status(s, &info);
-		} else if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family)
-			afp->af_status(s, &info);
-		addrcount--;
-		ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
+				p->af_status(s, ift);
+		} else if (afp->af_af == ift->ifa_addr->sa_family)
+			afp->af_status(s, ift);
 	}
+#if 0
 	if (allfamilies || afp->af_af == AF_LINK) {
 		const struct afswtch *lafp;
 
@@ -894,6 +823,7 @@
 			lafp->af_status(s, &info);
 		}
 	}
+#endif
 	if (allfamilies)
 		af_other_status(s);
 	else if (afp->af_other_status != NULL)
@@ -963,18 +893,30 @@
 }
 
 void
-ifmaybeload(char *name)
+ifmaybeload(const char *name)
 {
+#define MOD_PREFIX_LEN		3	/* "if_" */
 	struct module_stat mstat;
 	int fileid, modid;
-	char ifkind[35], *cp, *dp;
+	char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
+	const char *cp;
+
+	/* loading suppressed by the user */
+	if (noload)
+		return;
+
+	/* trim the interface number off the end */
+	strlcpy(ifname, name, sizeof(ifname));
+	for (dp = ifname; *dp != 0; dp++)
+		if (isdigit(*dp)) {
+			*dp = 0;
+			break;
+		}
 
 	/* turn interface and unit into module name */
 	strcpy(ifkind, "if_");
-	for (cp = name, dp = ifkind + 3;
-	    (*cp != 0) && !isdigit(*cp); cp++, dp++)
-		*dp = *cp;
-	*dp = 0;
+	strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
+	    sizeof(ifkind) - MOD_PREFIX_LEN);
 
 	/* scan files in kernel */
 	mstat.version = sizeof(struct module_stat);
@@ -991,8 +933,8 @@
 				cp = mstat.name;
 			}
 			/* already loaded? */
-			if (strncmp(name, cp, strlen(cp)) == 0 ||
-			    strncmp(ifkind, cp, strlen(cp)) == 0)
+			if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
+			    strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
 				return;
 		}
 	}
@@ -1045,6 +987,10 @@
 	DEF_CMD("-netcons",	-IFCAP_NETCONS,	setifcap),
 	DEF_CMD("polling",	IFCAP_POLLING,	setifcap),
 	DEF_CMD("-polling",	-IFCAP_POLLING,	setifcap),
+	DEF_CMD("tso",		IFCAP_TSO,	setifcap),
+	DEF_CMD("-tso",		-IFCAP_TSO,	setifcap),
+	DEF_CMD("lro",		IFCAP_LRO,	setifcap),
+	DEF_CMD("-lro",		-IFCAP_LRO,	setifcap),
 	DEF_CMD("normal",	-IFF_LINK0,	setifflags),
 	DEF_CMD("compress",	IFF_LINK0,	setifflags),
 	DEF_CMD("noicmp",	IFF_LINK1,	setifflags),
Index: af_link.c
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/af_link.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sbin/ifconfig/af_link.c -L sbin/ifconfig/af_link.c -u -r1.1.1.1 -r1.2
--- sbin/ifconfig/af_link.c
+++ sbin/ifconfig/af_link.c
@@ -29,19 +29,19 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: src/sbin/ifconfig/af_link.c,v 1.2 2004/12/31 19:46:27 sam Exp $";
+  "$FreeBSD: src/sbin/ifconfig/af_link.c,v 1.4 2007/02/24 23:55:46 sam Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <net/if.h>
-#include <net/route.h>		/* for RTX_IFA */
 
 #include <err.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ifaddrs.h>
 
 #include <net/if_dl.h>
 #include <net/if_types.h>
@@ -52,16 +52,16 @@
 static struct ifreq link_ridreq;
 
 static void
-link_status(int s __unused, const struct rt_addrinfo *info)
+link_status(int s __unused, const struct ifaddrs *ifa)
 {
-	const struct sockaddr_dl *sdl =
-		(const struct sockaddr_dl *) info->rti_info[RTAX_IFA];
+	/* XXX no const 'cuz LLADDR is defined wrong */
+	struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr;
 
 	if (sdl != NULL && sdl->sdl_alen > 0) {
 		if (sdl->sdl_type == IFT_ETHER &&
 		    sdl->sdl_alen == ETHER_ADDR_LEN)
 			printf("\tether %s\n",
-			    ether_ntoa((const struct ether_addr *)LLADDR(sdl)));
+			    ether_ntoa((struct ether_addr *)LLADDR(sdl)));
 		else {
 			int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
 
@@ -79,7 +79,7 @@
 
 	if (which != ADDR)
 		errx(1, "can't set link-level netmask or broadcast");
-	if ((temp = malloc(strlen(addr) + 1)) == NULL)
+	if ((temp = malloc(strlen(addr) + 2)) == NULL)
 		errx(1, "malloc failed");
 	temp[0] = ':';
 	strcpy(temp + 1, addr);
Index: ifieee80211.c
===================================================================
RCS file: /home/cvs/src/sbin/ifconfig/ifieee80211.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sbin/ifconfig/ifieee80211.c -L sbin/ifconfig/ifieee80211.c -u -r1.2 -r1.3
--- sbin/ifconfig/ifieee80211.c
+++ sbin/ifconfig/ifieee80211.c
@@ -24,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.18.2.9 2006/03/07 17:50:23 sam Exp $
+ * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.47.2.1.2.2 2008/02/05 18:17:29 sam Exp $
  */
 
 /*-
@@ -91,19 +91,236 @@
 #include <string.h>
 #include <unistd.h>
 #include <stdarg.h>
+#include <stddef.h>		/* NB: for offsetof */
 
 #include "ifconfig.h"
 
-static void set80211(int s, int type, int val, int len, u_int8_t *data);
+#define	MAXCOL	78
+static	int col;
+static	char spacer;
+
+static void LINE_INIT(char c);
+static void LINE_BREAK(void);
+static void LINE_CHECK(const char *fmt, ...);
+
+/* XXX need max array size */
+static const int htrates[16] = {
+	13,		/* IFM_IEEE80211_MCS0 */
+	26,		/* IFM_IEEE80211_MCS1 */
+	39,		/* IFM_IEEE80211_MCS2 */
+	52,		/* IFM_IEEE80211_MCS3 */
+	78,		/* IFM_IEEE80211_MCS4 */
+	104,		/* IFM_IEEE80211_MCS5 */
+	117,		/* IFM_IEEE80211_MCS6 */
+	130,		/* IFM_IEEE80211_MCS7 */
+	26,		/* IFM_IEEE80211_MCS8 */
+	52,		/* IFM_IEEE80211_MCS9 */
+	78,		/* IFM_IEEE80211_MCS10 */
+	104,		/* IFM_IEEE80211_MCS11 */
+	156,		/* IFM_IEEE80211_MCS12 */
+	208,		/* IFM_IEEE80211_MCS13 */
+	234,		/* IFM_IEEE80211_MCS14 */
+	260,		/* IFM_IEEE80211_MCS15 */
+};
+
+static int get80211(int s, int type, void *data, int len);
+static int get80211len(int s, int type, void *data, int len, int *plen);
+static int get80211val(int s, int type, int *val);
+static void set80211(int s, int type, int val, int len, void *data);
 static const char *get_string(const char *val, const char *sep,
     u_int8_t *buf, int *lenp);
 static void print_string(const u_int8_t *buf, int len);
 
+static struct ieee80211req_chaninfo chaninfo;
+static struct ifmediareq *ifmr;
+static struct ieee80211_channel curchan;
+static int gotcurchan = 0;
+static int htconf = 0;
+static	int gothtconf = 0;
+
+static void
+gethtconf(int s)
+{
+	if (gothtconf)
+		return;
+	if (get80211val(s, IEEE80211_IOC_HTCONF, &htconf) < 0)
+		warn("unable to get HT configuration information");
+	gothtconf = 1;
+}
+
+/*
+ * Collect channel info from the kernel.  We use this (mostly)
+ * to handle mapping between frequency and IEEE channel number.
+ */
+static void
+getchaninfo(int s)
+{
+	if (chaninfo.ic_nchans != 0)
+		return;
+	if (get80211(s, IEEE80211_IOC_CHANINFO, &chaninfo, sizeof(chaninfo)) < 0)
+		errx(1, "unable to get channel information");
+
+	ifmr = ifmedia_getstate(s);
+	gethtconf(s);
+}
+
+/*
+ * Given the channel at index i with attributes from,
+ * check if there is a channel with attributes to in
+ * the channel table.  With suitable attributes this
+ * allows the caller to look for promotion; e.g. from
+ * 11b > 11g.
+ */
+static int
+canpromote(int i, int from, int to)
+{
+	const struct ieee80211_channel *fc = &chaninfo.ic_chans[i];
+	int j;
+
+	if ((fc->ic_flags & from) != from)
+		return i;
+	/* NB: quick check exploiting ordering of chans w/ same frequency */
+	if (i+1 < chaninfo.ic_nchans &&
+	    chaninfo.ic_chans[i+1].ic_freq == fc->ic_freq &&
+	    (chaninfo.ic_chans[i+1].ic_flags & to) == to)
+		return i+1;
+	/* brute force search in case channel list is not ordered */
+	for (j = 0; j < chaninfo.ic_nchans; j++) {
+		const struct ieee80211_channel *tc = &chaninfo.ic_chans[j];
+		if (j != i &&
+		    tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to)
+		return j;
+	}
+	return i;
+}
+
+/*
+ * Handle channel promotion.  When a channel is specified with
+ * only a frequency we want to promote it to the ``best'' channel
+ * available.  The channel list has separate entries for 11b, 11g,
+ * 11a, and 11n[ga] channels so specifying a frequency w/o any
+ * attributes requires we upgrade, e.g. from 11b -> 11g.  This
+ * gets complicated when the channel is specified on the same
+ * command line with a media request that constrains the available
+ * channe list (e.g. mode 11a); we want to honor that to avoid
+ * confusing behaviour.
+ */
+static int
+promote(int i)
+{
+	/*
+	 * Query the current mode of the interface in case it's
+	 * constrained (e.g. to 11a).  We must do this carefully
+	 * as there may be a pending ifmedia request in which case
+	 * asking the kernel will give us the wrong answer.  This
+	 * is an unfortunate side-effect of the way ifconfig is
+	 * structure for modularity (yech).
+	 *
+	 * NB: ifmr is actually setup in getchaninfo (above); we
+	 *     assume it's called coincident with to this call so
+	 *     we have a ``current setting''; otherwise we must pass
+	 *     the socket descriptor down to here so we can make
+	 *     the ifmedia_getstate call ourselves.
+	 */
+	int chanmode = ifmr != NULL ? IFM_MODE(ifmr->ifm_current) : IFM_AUTO;
+
+	/* when ambiguous promote to ``best'' */
+	/* NB: we abitrarily pick HT40+ over HT40- */
+	if (chanmode != IFM_IEEE80211_11B)
+		i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G);
+	if (chanmode != IFM_IEEE80211_11G && (htconf & 1)) {
+		i = canpromote(i, IEEE80211_CHAN_G,
+			IEEE80211_CHAN_G | IEEE80211_CHAN_HT20);
+		if (htconf & 2) {
+			i = canpromote(i, IEEE80211_CHAN_G,
+				IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D);
+			i = canpromote(i, IEEE80211_CHAN_G,
+				IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U);
+		}
+	}
+	if (chanmode != IFM_IEEE80211_11A && (htconf & 1)) {
+		i = canpromote(i, IEEE80211_CHAN_A,
+			IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
+		if (htconf & 2) {
+			i = canpromote(i, IEEE80211_CHAN_A,
+				IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
+			i = canpromote(i, IEEE80211_CHAN_A,
+				IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
+		}
+	}
+	return i;
+}
+
+static void
+mapfreq(struct ieee80211_channel *chan, int freq, int flags)
+{
+	int i;
+
+	for (i = 0; i < chaninfo.ic_nchans; i++) {
+		const struct ieee80211_channel *c = &chaninfo.ic_chans[i];
+
+		if (c->ic_freq == freq && (c->ic_flags & flags) == flags) {
+			if (flags == 0) {
+				/* when ambiguous promote to ``best'' */
+				c = &chaninfo.ic_chans[promote(i)];
+			}
+			*chan = *c;
+			return;
+		}
+	}
+	errx(1, "unknown/undefined frequency %u/0x%x", freq, flags);
+}
+
+static void
+mapchan(struct ieee80211_channel *chan, int ieee, int flags)
+{
+	int i;
+
+	for (i = 0; i < chaninfo.ic_nchans; i++) {
+		const struct ieee80211_channel *c = &chaninfo.ic_chans[i];
+
+		if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) {
+			if (flags == 0) {
+				/* when ambiguous promote to ``best'' */
+				c = &chaninfo.ic_chans[promote(i)];
+			}
+			*chan = *c;
+			return;
+		}
+	}
+	errx(1, "unknown/undefined channel number %d flags 0x%x", ieee, flags);
+}
+
+static const struct ieee80211_channel *
+getcurchan(int s)
+{
+	if (gotcurchan)
+		return &curchan;
+	if (get80211(s, IEEE80211_IOC_CURCHAN, &curchan, sizeof(curchan)) < 0) {
+		int val;
+		/* fall back to legacy ioctl */
+		if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0)
+			errx(-1, "cannot figure out current channel");
+		getchaninfo(s);
+		mapchan(&curchan, val, 0);
+	}
+	gotcurchan = 1;
+	return &curchan;
+}
+
+static int
+ieee80211_mhz2ieee(int freq, int flags)
+{
+	struct ieee80211_channel chan;
+	mapfreq(&chan, freq, flags);
+	return chan.ic_ieee;
+}
+
 static int
 isanyarg(const char *arg)
 {
-	return (strcmp(arg, "-") == 0 ||
-	    strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
+	return (strncmp(arg, "-", 1) == 0 ||
+	    strncasecmp(arg, "any", 3) == 0 || strncasecmp(arg, "off", 3) == 0);
 }
 
 static void
@@ -142,45 +359,147 @@
 }
 
 /*
- * Convert IEEE channel number to MHz frequency.
- */
-static u_int
-ieee80211_ieee2mhz(u_int chan)
-{
-	if (chan == 14)
-		return 2484;
-	if (chan < 14)			/* 0-13 */
-		return 2407 + chan*5;
-	if (chan < 27)			/* 15-26 */
-		return 2512 + ((chan-15)*20);
-	return 5000 + (chan*5);
-}
-
-/*
- * Convert MHz frequency to IEEE channel number.
- */
-static u_int
-ieee80211_mhz2ieee(u_int freq)
+ * Parse a channel specification for attributes/flags.
+ * The syntax is:
+ *	freq/xx		channel width (5,10,20,40,40+,40-)
+ *	freq:mode	channel mode (a,b,g,h,n,t,s,d)
+ *
+ * These can be combined in either order; e.g. 2437:ng/40.
+ * Modes are case insensitive.
+ *
+ * The result is not validated here; it's assumed to be
+ * checked against the channel table fetched from the kernel.
+ */ 
+static int
+getchannelflags(const char *val, int freq)
 {
-	if (freq == 2484)
-		return 14;
-	if (freq < 2484)
-		return (freq - 2407) / 5;
-	if (freq < 5000)
-		return 15 + ((freq - 2512) / 20);
-	return (freq - 5000) / 5;
+#define	_CHAN_HT	0x80000000
+	const char *cp;
+	int flags;
+
+	flags = 0;
+
+	cp = strchr(val, ':');
+	if (cp != NULL) {
+		for (cp++; isalpha((int) *cp); cp++) {
+			/* accept mixed case */
+			int c = *cp;
+			if (isupper(c))
+				c = tolower(c);
+			switch (c) {
+			case 'a':		/* 802.11a */
+				flags |= IEEE80211_CHAN_A;
+				break;
+			case 'b':		/* 802.11b */
+				flags |= IEEE80211_CHAN_B;
+				break;
+			case 'g':		/* 802.11g */
+				flags |= IEEE80211_CHAN_G;
+				break;
+			case 'h':		/* ht = 802.11n */
+			case 'n':		/* 802.11n */
+				flags |= _CHAN_HT;	/* NB: private */
+				break;
+			case 'd':		/* dt = Atheros Dynamic Turbo */
+				flags |= IEEE80211_CHAN_TURBO;
+				break;
+			case 't':		/* ht, dt, st, t */
+				/* dt and unadorned t specify Dynamic Turbo */
+				if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0)
+					flags |= IEEE80211_CHAN_TURBO;
+				break;
+			case 's':		/* st = Atheros Static Turbo */
+				flags |= IEEE80211_CHAN_STURBO;
+				break;
+			default:
+				errx(-1, "%s: Invalid channel attribute %c\n",
+				    val, *cp);
+			}
+		}
+	}
+	cp = strchr(val, '/');
+	if (cp != NULL) {
+		char *ep;
+		u_long cw = strtoul(cp+1, &ep, 10);
+
+		switch (cw) {
+		case 5:
+			flags |= IEEE80211_CHAN_QUARTER;
+			break;
+		case 10:
+			flags |= IEEE80211_CHAN_HALF;
+			break;
+		case 20:
+			/* NB: this may be removed below */
+			flags |= IEEE80211_CHAN_HT20;
+			break;
+		case 40:
+			if (ep != NULL && *ep == '+')
+				flags |= IEEE80211_CHAN_HT40U;
+			else if (ep != NULL && *ep == '-')
+				flags |= IEEE80211_CHAN_HT40D;
+			break;
+		default:
+			errx(-1, "%s: Invalid channel width\n", val);
+		}
+	}
+	/*
+	 * Cleanup specifications.
+	 */ 
+	if ((flags & _CHAN_HT) == 0) {
+		/*
+		 * If user specified freq/20 or freq/40 quietly remove
+		 * HT cw attributes depending on channel use.  To give
+		 * an explicit 20/40 width for an HT channel you must
+		 * indicate it is an HT channel since all HT channels
+		 * are also usable for legacy operation; e.g. freq:n/40.
+		 */
+		flags &= ~IEEE80211_CHAN_HT;
+	} else {
+		/*
+		 * Remove private indicator that this is an HT channel
+		 * and if no explicit channel width has been given
+		 * provide the default settings.
+		 */
+		flags &= ~_CHAN_HT;
+		if ((flags & IEEE80211_CHAN_HT) == 0) {
+			struct ieee80211_channel chan;
+			/*
+			 * Consult the channel list to see if we can use
+			 * HT40+ or HT40- (if both the map routines choose).
+			 */
+			if (freq > 255)
+				mapfreq(&chan, freq, 0);
+			else
+				mapchan(&chan, freq, 0);
+			flags |= (chan.ic_flags & IEEE80211_CHAN_HT);
+		}
+	}
+	return flags;
+#undef _CHAN_HT
 }
 
 static void
 set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
 {
+	struct ieee80211_channel chan;
+
+	memset(&chan, 0, sizeof(chan));
 	if (!isanyarg(val)) {
-		int v = atoi(val);
-		if (v > 255)		/* treat as frequency */
-			v = ieee80211_mhz2ieee(v);
-		set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
-	} else
-		set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
+		int v, flags;
+
+		getchaninfo(s);
+		v = atoi(val);
+		flags = getchannelflags(val, v);
+		if (v > 255) {		/* treat as frequency */
+			mapfreq(&chan, v, flags);
+		} else {
+			mapchan(&chan, v, flags);
+		}
+	} else {
+		chan.ic_freq = IEEE80211_CHAN_ANY;
+	}
+	set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan);
 }
 
 static void
@@ -361,7 +680,7 @@
 		mode = IEEE80211_PROTMODE_OFF;
 	} else if (strcasecmp(val, "cts") == 0) {
 		mode = IEEE80211_PROTMODE_CTS;
-	} else if (strcasecmp(val, "rtscts") == 0) {
+	} else if (strncasecmp(val, "rtscts", 3) == 0) {
 		mode = IEEE80211_PROTMODE_RTSCTS;
 	} else {
 		errx(1, "unknown protection mode");
@@ -371,9 +690,31 @@
 }
 
 static void
+set80211htprotmode(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int	mode;
+
+	if (strcasecmp(val, "off") == 0) {
+		mode = IEEE80211_PROTMODE_OFF;
+	} else if (strncasecmp(val, "rts", 3) == 0) {
+		mode = IEEE80211_PROTMODE_RTSCTS;
+	} else {
+		errx(1, "unknown protection mode");
+	}
+
+	set80211(s, IEEE80211_IOC_HTPROTMODE, mode, 0, NULL);
+}
+
+static void
 set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
 {
-	set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
+	double v = atof(val);
+	int txpow;
+
+	txpow = (int) (2*v);
+	if (txpow != 2*v)
+		errx(-1, "invalid tx power (must be .5 dBm units)");
+	set80211(s, IEEE80211_IOC_TXPOWER, txpow, 0, NULL);
 }
 
 #define	IEEE80211_ROAMING_DEVICE	0
@@ -416,6 +757,18 @@
 }
 
 static void
+set80211fastframes(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_FF, d, 0, NULL);
+}
+
+static void
+set80211dturbo(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL);
+}
+
+static void
 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
 {
 	struct ieee80211req_chanlist chanlist;
@@ -429,7 +782,7 @@
 	memset(&chanlist, 0, sizeof(chanlist));
 	cp = temp;
 	for (;;) {
-		int first, last, f;
+		int first, last, f, c;
 
 		tp = strchr(cp, ',');
 		if (tp != NULL)
@@ -457,14 +810,14 @@
 		}
 		if (tp == NULL)
 			break;
-		while (isspace(*tp))
+		c = *tp;
+		while (isspace(c))
 			tp++;
-		if (!isdigit(*tp))
+		if (!isdigit(c))
 			break;
 		cp = tp;
 	}
-	set80211(s, IEEE80211_IOC_CHANLIST, 0,
-		sizeof(chanlist), (uint8_t *) &chanlist);
+	set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist);
 #undef MAXCHAN
 }
 
@@ -648,7 +1001,7 @@
 	mlme.im_op = IEEE80211_MLME_DEAUTH;
 	mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
 	memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
-	set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme);
+	set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme);
 }
 
 static
@@ -664,155 +1017,852 @@
 }
 
 static void
-set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
+set80211bgscan(const char *val, int d, int s, const struct afswtch *rafp)
 {
-	set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
+	set80211(s, IEEE80211_IOC_BGSCAN, d, 0, NULL);
 }
 
 static
-DECL_CMD_FUNC(set80211mcastrate, val, d)
+DECL_CMD_FUNC(set80211bgscanidle, val, d)
 {
-	set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
+	set80211(s, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL);
 }
 
 static
-DECL_CMD_FUNC(set80211fragthreshold, val, d)
+DECL_CMD_FUNC(set80211bgscanintvl, val, d)
 {
-	set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
-		isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
+	set80211(s, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL);
 }
 
-static int
-getmaxrate(uint8_t rates[15], uint8_t nrates)
+static
+DECL_CMD_FUNC(set80211scanvalid, val, d)
 {
-	int i, maxrate = -1;
-
-	for (i = 0; i < nrates; i++) {
-		int rate = rates[i] & IEEE80211_RATE_VAL;
-		if (rate > maxrate)
-			maxrate = rate;
-	}
-	return maxrate / 2;
+	set80211(s, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL);
 }
 
-static const char *
-getcaps(int capinfo)
+static
+DECL_CMD_FUNC(set80211roamrssi11a, val, d)
 {
-	static char capstring[32];
-	char *cp = capstring;
-
-	if (capinfo & IEEE80211_CAPINFO_ESS)
-		*cp++ = 'E';
-	if (capinfo & IEEE80211_CAPINFO_IBSS)
-		*cp++ = 'I';
-	if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
-		*cp++ = 'c';
-	if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
-		*cp++ = 'C';
-	if (capinfo & IEEE80211_CAPINFO_PRIVACY)
-		*cp++ = 'P';
-	if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
-		*cp++ = 'S';
-	if (capinfo & IEEE80211_CAPINFO_PBCC)
-		*cp++ = 'B';
-	if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
-		*cp++ = 'A';
-	if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
-		*cp++ = 's';
-	if (capinfo & IEEE80211_CAPINFO_RSN)
-		*cp++ = 'R';
-	if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
-		*cp++ = 'D';
-	*cp = '\0';
-	return capstring;
+	set80211(s, IEEE80211_IOC_ROAM_RSSI_11A, atoi(val), 0, NULL);
 }
 
-static void
-printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
+static
+DECL_CMD_FUNC(set80211roamrssi11b, val, d)
 {
-	printf("%s", tag);
-	if (verbose) {
-		maxlen -= strlen(tag)+2;
-		if (2*ielen > maxlen)
-			maxlen--;
-		printf("<");
-		for (; ielen > 0; ie++, ielen--) {
-			if (maxlen-- <= 0)
-				break;
-			printf("%02x", *ie);
-		}
-		if (ielen != 0)
-			printf("-");
-		printf(">");
-	}
+	set80211(s, IEEE80211_IOC_ROAM_RSSI_11B, atoi(val), 0, NULL);
 }
 
-/*
- * Copy the ssid string contents into buf, truncating to fit.  If the
- * ssid is entirely printable then just copy intact.  Otherwise convert
- * to hexadecimal.  If the result is truncated then replace the last
- * three characters with "...".
- */
-static int
-copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
+static
+DECL_CMD_FUNC(set80211roamrssi11g, val, d)
 {
-	const u_int8_t *p; 
-	size_t maxlen;
-	int i;
-
-	if (essid_len > bufsize)
-		maxlen = bufsize;
-	else
-		maxlen = essid_len;
-	/* determine printable or not */
-	for (i = 0, p = essid; i < maxlen; i++, p++) {
-		if (*p < ' ' || *p > 0x7e)
-			break;
-	}
-	if (i != maxlen) {		/* not printable, print as hex */
-		if (bufsize < 3)
-			return 0;
-		strlcpy(buf, "0x", bufsize);
-		bufsize -= 2;
-		p = essid;
-		for (i = 0; i < maxlen && bufsize >= 2; i++) {
-			sprintf(&buf[2+2*i], "%02x", p[i]);
-			bufsize -= 2;
-		}
-		if (i != essid_len)
-			memcpy(&buf[2+2*i-3], "...", 3);
-	} else {			/* printable, truncate as needed */
-		memcpy(buf, essid, maxlen);
-		if (maxlen != essid_len)
-			memcpy(&buf[maxlen-3], "...", 3);
-	}
-	return maxlen;
+	set80211(s, IEEE80211_IOC_ROAM_RSSI_11G, atoi(val), 0, NULL);
 }
 
-/* unaligned little endian access */     
-#define LE_READ_4(p)					\
-	((u_int32_t)					\
-	 ((((const u_int8_t *)(p))[0]      ) |		\
-	  (((const u_int8_t *)(p))[1] <<  8) |		\
-	  (((const u_int8_t *)(p))[2] << 16) |		\
-	  (((const u_int8_t *)(p))[3] << 24)))
+static
+DECL_CMD_FUNC(set80211roamrate11a, val, d)
+{
+	set80211(s, IEEE80211_IOC_ROAM_RATE_11A, 2*atoi(val), 0, NULL);
+}
 
-static int __inline
-iswpaoui(const u_int8_t *frm)
+static
+DECL_CMD_FUNC(set80211roamrate11b, val, d)
 {
-	return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
+	set80211(s, IEEE80211_IOC_ROAM_RATE_11B, 2*atoi(val), 0, NULL);
 }
 
-static int __inline
-iswmeoui(const u_int8_t *frm)
+static
+DECL_CMD_FUNC(set80211roamrate11g, val, d)
 {
-	return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
+	set80211(s, IEEE80211_IOC_ROAM_RATE_11G, 2*atoi(val), 0, NULL);
 }
 
-static int __inline
-isatherosoui(const u_int8_t *frm)
+static
+DECL_CMD_FUNC(set80211mcastrate, val, d)
 {
-	return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
+	set80211(s, IEEE80211_IOC_MCAST_RATE, 2*atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211fragthreshold, val, d)
+{
+	set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
+		isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bmissthreshold, val, d)
+{
+	set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
+		isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
+}
+
+static void
+set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
+}
+
+static void
+set80211doth(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL);
+}
+
+static void
+set80211shortgi(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_SHORTGI,
+		d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0,
+		0, NULL);
+}
+
+static void
+set80211ampdu(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int ampdu;
+
+	if (get80211val(s, IEEE80211_IOC_AMPDU, &ampdu) < 0)
+		errx(-1, "cannot get AMPDU setting");
+	if (d < 0) {
+		d = -d;
+		ampdu &= ~d;
+	} else
+		ampdu |= d;
+	set80211(s, IEEE80211_IOC_AMPDU, ampdu, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211ampdulimit, val, d)
+{
+	int v;
+
+	switch (atoi(val)) {
+	case 8:
+	case 8*1024:
+		v = IEEE80211_HTCAP_MAXRXAMPDU_8K;
+		break;
+	case 16:
+	case 16*1024:
+		v = IEEE80211_HTCAP_MAXRXAMPDU_16K;
+		break;
+	case 32:
+	case 32*1024:
+		v = IEEE80211_HTCAP_MAXRXAMPDU_32K;
+		break;
+	case 64:
+	case 64*1024:
+		v = IEEE80211_HTCAP_MAXRXAMPDU_64K;
+		break;
+	default:
+		errx(-1, "invalid A-MPDU limit %s", val);
+	}
+	set80211(s, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211ampdudensity, val, d)
+{
+	int v;
+
+	if (isanyarg(val))
+		v = IEEE80211_HTCAP_MPDUDENSITY_NA;
+	else switch ((int)(atof(val)*4)) {
+	case 0:
+		v = IEEE80211_HTCAP_MPDUDENSITY_NA;
+		break;
+	case 1:
+		v = IEEE80211_HTCAP_MPDUDENSITY_025;
+		break;
+	case 2:
+		v = IEEE80211_HTCAP_MPDUDENSITY_05;
+		break;
+	case 4:
+		v = IEEE80211_HTCAP_MPDUDENSITY_1;
+		break;
+	case 8:
+		v = IEEE80211_HTCAP_MPDUDENSITY_2;
+		break;
+	case 16:
+		v = IEEE80211_HTCAP_MPDUDENSITY_4;
+		break;
+	case 32:
+		v = IEEE80211_HTCAP_MPDUDENSITY_8;
+		break;
+	case 64:
+		v = IEEE80211_HTCAP_MPDUDENSITY_16;
+		break;
+	default:
+		errx(-1, "invalid A-MPDU density %s", val);
+	}
+	set80211(s, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL);
+}
+
+static void
+set80211amsdu(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	int amsdu;
+
+	if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0)
+		errx(-1, "cannot get AMSDU setting");
+	if (d < 0) {
+		d = -d;
+		amsdu &= ~d;
+	} else
+		amsdu |= d;
+	set80211(s, IEEE80211_IOC_AMSDU, amsdu, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211amsdulimit, val, d)
+{
+	set80211(s, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL);
+}
+
+static void
+set80211puren(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_PUREN, d, 0, NULL);
+}
+
+static void
+set80211htcompat(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_HTCOMPAT, d, 0, NULL);
+}
+
+static void
+set80211htconf(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_HTCONF, d, 0, NULL);
+	htconf = d;
+}
+
+static void
+set80211inact(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	set80211(s, IEEE80211_IOC_INACTIVITY, d, 0, NULL);
+}
+
+static void
+LINE_INIT(char c)
+{
+	spacer = c;
+	if (c == '\t')
+		col = 8;
+	else
+		col = 1;
+}
+
+static void
+LINE_BREAK(void)
+{
+	if (spacer != '\t') {
+		printf("\n");
+		spacer = '\t';
+	}
+	col = 8;		/* 8-col tab */
+}
+
+static void
+LINE_CHECK(const char *fmt, ...)
+{
+	char buf[80];
+	va_list ap;
+	int n;
+
+	va_start(ap, fmt);
+	n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
+	va_end(ap);
+	col += 1+n;
+	if (col > MAXCOL) {
+		LINE_BREAK();
+		col += n;
+	}
+	buf[0] = spacer;
+	printf("%s", buf);
+	spacer = ' ';
+}
+
+static int
+getmaxrate(const uint8_t rates[15], uint8_t nrates)
+{
+	int i, maxrate = -1;
+
+	for (i = 0; i < nrates; i++) {
+		int rate = rates[i] & IEEE80211_RATE_VAL;
+		if (rate > maxrate)
+			maxrate = rate;
+	}
+	return maxrate / 2;
+}
+
+static const char *
+getcaps(int capinfo)
+{
+	static char capstring[32];
+	char *cp = capstring;
+
+	if (capinfo & IEEE80211_CAPINFO_ESS)
+		*cp++ = 'E';
+	if (capinfo & IEEE80211_CAPINFO_IBSS)
+		*cp++ = 'I';
+	if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
+		*cp++ = 'c';
+	if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
+		*cp++ = 'C';
+	if (capinfo & IEEE80211_CAPINFO_PRIVACY)
+		*cp++ = 'P';
+	if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
+		*cp++ = 'S';
+	if (capinfo & IEEE80211_CAPINFO_PBCC)
+		*cp++ = 'B';
+	if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
+		*cp++ = 'A';
+	if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
+		*cp++ = 's';
+	if (capinfo & IEEE80211_CAPINFO_RSN)
+		*cp++ = 'R';
+	if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
+		*cp++ = 'D';
+	*cp = '\0';
+	return capstring;
+}
+
+static const char *
+getflags(int flags)
+{
+/* XXX need these publicly defined or similar */
+#define	IEEE80211_NODE_AUTH	0x0001		/* authorized for data */
+#define	IEEE80211_NODE_QOS	0x0002		/* QoS enabled */
+#define	IEEE80211_NODE_ERP	0x0004		/* ERP enabled */
+#define	IEEE80211_NODE_PWR_MGT	0x0010		/* power save mode enabled */
+#define	IEEE80211_NODE_HT	0x0040		/* HT enabled */
+#define	IEEE80211_NODE_HTCOMPAT	0x0080		/* HT setup w/ vendor OUI's */
+#define	IEEE80211_NODE_WPS	0x0100		/* WPS association */
+#define	IEEE80211_NODE_TSN	0x0200		/* TSN association */
+
+	static char flagstring[32];
+	char *cp = flagstring;
+
+	if (flags & IEEE80211_NODE_AUTH)
+		*cp++ = 'A';
+	if (flags & IEEE80211_NODE_QOS)
+		*cp++ = 'Q';
+	if (flags & IEEE80211_NODE_ERP)
+		*cp++ = 'E';
+	if (flags & IEEE80211_NODE_PWR_MGT)
+		*cp++ = 'P';
+	if (flags & IEEE80211_NODE_HT) {
+		*cp++ = 'H';
+		if (flags & IEEE80211_NODE_HTCOMPAT)
+			*cp++ = '+';
+	}
+	if (flags & IEEE80211_NODE_WPS)
+		*cp++ = 'W';
+	if (flags & IEEE80211_NODE_TSN)
+		*cp++ = 'T';
+	*cp = '\0';
+	return flagstring;
+#undef IEEE80211_NODE_TSN
+#undef IEEE80211_NODE_WPS
+#undef IEEE80211_NODE_HTCOMPAT
+#undef IEEE80211_NODE_HT
+#undef IEEE80211_NODE_AUTH
+#undef IEEE80211_NODE_QOS
+#undef IEEE80211_NODE_ERP
+#undef IEEE80211_NODE_PWR_MGT
+}
+
+static void
+printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
+{
+	printf("%s", tag);
+	if (verbose) {
+		maxlen -= strlen(tag)+2;
+		if (2*ielen > maxlen)
+			maxlen--;
+		printf("<");
+		for (; ielen > 0; ie++, ielen--) {
+			if (maxlen-- <= 0)
+				break;
+			printf("%02x", *ie);
+		}
+		if (ielen != 0)
+			printf("-");
+		printf(">");
+	}
+}
+
+#define LE_READ_2(p)					\
+	((u_int16_t)					\
+	 ((((const u_int8_t *)(p))[0]      ) |		\
+	  (((const u_int8_t *)(p))[1] <<  8)))
+#define LE_READ_4(p)					\
+	((u_int32_t)					\
+	 ((((const u_int8_t *)(p))[0]      ) |		\
+	  (((const u_int8_t *)(p))[1] <<  8) |		\
+	  (((const u_int8_t *)(p))[2] << 16) |		\
+	  (((const u_int8_t *)(p))[3] << 24)))
+
+/*
+ * NB: The decoding routines assume a properly formatted ie
+ *     which should be safe as the kernel only retains them
+ *     if they parse ok.
+ */
+
+static void
+printwmeparam(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
+	static const char *acnames[] = { "BE", "BK", "VO", "VI" };
+	const struct ieee80211_wme_param *wme =
+	    (const struct ieee80211_wme_param *) ie;
+	int i;
+
+	printf("%s", tag);
+	if (!verbose)
+		return;
+	printf("<qosinfo 0x%x", wme->param_qosInfo);
+	ie += offsetof(struct ieee80211_wme_param, params_acParams);
+	for (i = 0; i < WME_NUM_AC; i++) {
+		const struct ieee80211_wme_acparams *ac =
+		    &wme->params_acParams[i];
+
+		printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]"
+			, acnames[i]
+			, MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : ""
+			, MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN)
+			, MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN)
+			, MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX)
+			, LE_READ_2(&ac->acp_txop)
+		);
+	}
+	printf(">");
+#undef MS
+}
+
+static void
+printwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	printf("%s", tag);
+	if (verbose) {
+		const struct ieee80211_wme_info *wme =
+		    (const struct ieee80211_wme_info *) ie;
+		printf("<version 0x%x info 0x%x>",
+		    wme->wme_version, wme->wme_info);
+	}
+}
+
+static void
+printhtcap(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	printf("%s", tag);
+	if (verbose) {
+		const struct ieee80211_ie_htcap *htcap =
+		    (const struct ieee80211_ie_htcap *) ie;
+		const char *sep;
+		int i, j;
+
+		printf("<cap 0x%x param 0x%x",
+		    LE_READ_2(&htcap->hc_cap), htcap->hc_param);
+		printf(" mcsset[");
+		sep = "";
+		for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
+			if (isset(htcap->hc_mcsset, i)) {
+				for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
+					if (isclr(htcap->hc_mcsset, j))
+						break;
+				j--;
+				if (i == j)
+					printf("%s%u", sep, i);
+				else
+					printf("%s%u-%u", sep, i, j);
+				i += j-i;
+				sep = ",";
+			}
+		printf("] extcap 0x%x txbf 0x%x antenna 0x%x>",
+		    LE_READ_2(&htcap->hc_extcap),
+		    LE_READ_4(&htcap->hc_txbf),
+		    htcap->hc_antenna);
+	}
+}
+
+static void
+printhtinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	printf("%s", tag);
+	if (verbose) {
+		const struct ieee80211_ie_htinfo *htinfo =
+		    (const struct ieee80211_ie_htinfo *) ie;
+		const char *sep;
+		int i, j;
+
+		printf("<ctl %u, %x,%x,%x,%x", htinfo->hi_ctrlchannel,
+		    htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3,
+		    LE_READ_2(&htinfo->hi_byte45));
+		printf(" basicmcs[");
+		sep = "";
+		for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
+			if (isset(htinfo->hi_basicmcsset, i)) {
+				for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
+					if (isclr(htinfo->hi_basicmcsset, j))
+						break;
+				j--;
+				if (i == j)
+					printf("%s%u", sep, i);
+				else
+					printf("%s%u-%u", sep, i, j);
+				i += j-i;
+				sep = ",";
+			}
+		printf("]>");
+	}
+}
+
+static void
+printathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+
+	printf("%s", tag);
+	if (verbose) {
+		const struct ieee80211_ath_ie *ath =
+			(const struct ieee80211_ath_ie *)ie;
+
+		printf("<");
+		if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME)
+			printf("DTURBO,");
+		if (ath->ath_capability & ATHEROS_CAP_COMPRESSION)
+			printf("COMP,");
+		if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME)
+			printf("FF,");
+		if (ath->ath_capability & ATHEROS_CAP_XR)
+			printf("XR,");
+		if (ath->ath_capability & ATHEROS_CAP_AR)
+			printf("AR,");
+		if (ath->ath_capability & ATHEROS_CAP_BURST)
+			printf("BURST,");
+		if (ath->ath_capability & ATHEROS_CAP_WME)
+			printf("WME,");
+		if (ath->ath_capability & ATHEROS_CAP_BOOST)
+			printf("BOOST,");
+		printf("0x%x>", LE_READ_2(ath->ath_defkeyix));
+	}
+}
+
+static const char *
+wpa_cipher(const u_int8_t *sel)
+{
+#define	WPA_SEL(x)	(((x)<<24)|WPA_OUI)
+	u_int32_t w = LE_READ_4(sel);
+
+	switch (w) {
+	case WPA_SEL(WPA_CSE_NULL):
+		return "NONE";
+	case WPA_SEL(WPA_CSE_WEP40):
+		return "WEP40";
+	case WPA_SEL(WPA_CSE_WEP104):
+		return "WEP104";
+	case WPA_SEL(WPA_CSE_TKIP):
+		return "TKIP";
+	case WPA_SEL(WPA_CSE_CCMP):
+		return "AES-CCMP";
+	}
+	return "?";		/* NB: so 1<< is discarded */
+#undef WPA_SEL
+}
+
+static const char *
+wpa_keymgmt(const u_int8_t *sel)
+{
+#define	WPA_SEL(x)	(((x)<<24)|WPA_OUI)
+	u_int32_t w = LE_READ_4(sel);
+
+	switch (w) {
+	case WPA_SEL(WPA_ASE_8021X_UNSPEC):
+		return "8021X-UNSPEC";
+	case WPA_SEL(WPA_ASE_8021X_PSK):
+		return "8021X-PSK";
+	case WPA_SEL(WPA_ASE_NONE):
+		return "NONE";
+	}
+	return "?";
+#undef WPA_SEL
+}
+
+static void
+printwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	u_int8_t len = ie[1];
+
+	printf("%s", tag);
+	if (verbose) {
+		const char *sep;
+		int n;
+
+		ie += 6, len -= 4;		/* NB: len is payload only */
+
+		printf("<v%u", LE_READ_2(ie));
+		ie += 2, len -= 2;
+
+		printf(" mc:%s", wpa_cipher(ie));
+		ie += 4, len -= 4;
+
+		/* unicast ciphers */
+		n = LE_READ_2(ie);
+		ie += 2, len -= 2;
+		sep = " uc:";
+		for (; n > 0; n--) {
+			printf("%s%s", sep, wpa_cipher(ie));
+			ie += 4, len -= 4;
+			sep = "+";
+		}
+
+		/* key management algorithms */
+		n = LE_READ_2(ie);
+		ie += 2, len -= 2;
+		sep = " km:";
+		for (; n > 0; n--) {
+			printf("%s%s", sep, wpa_keymgmt(ie));
+			ie += 4, len -= 4;
+			sep = "+";
+		}
+
+		if (len > 2)		/* optional capabilities */
+			printf(", caps 0x%x", LE_READ_2(ie));
+		printf(">");
+	}
+}
+
+static const char *
+rsn_cipher(const u_int8_t *sel)
+{
+#define	RSN_SEL(x)	(((x)<<24)|RSN_OUI)
+	u_int32_t w = LE_READ_4(sel);
+
+	switch (w) {
+	case RSN_SEL(RSN_CSE_NULL):
+		return "NONE";
+	case RSN_SEL(RSN_CSE_WEP40):
+		return "WEP40";
+	case RSN_SEL(RSN_CSE_WEP104):
+		return "WEP104";
+	case RSN_SEL(RSN_CSE_TKIP):
+		return "TKIP";
+	case RSN_SEL(RSN_CSE_CCMP):
+		return "AES-CCMP";
+	case RSN_SEL(RSN_CSE_WRAP):
+		return "AES-OCB";
+	}
+	return "?";
+#undef WPA_SEL
+}
+
+static const char *
+rsn_keymgmt(const u_int8_t *sel)
+{
+#define	RSN_SEL(x)	(((x)<<24)|RSN_OUI)
+	u_int32_t w = LE_READ_4(sel);
+
+	switch (w) {
+	case RSN_SEL(RSN_ASE_8021X_UNSPEC):
+		return "8021X-UNSPEC";
+	case RSN_SEL(RSN_ASE_8021X_PSK):
+		return "8021X-PSK";
+	case RSN_SEL(RSN_ASE_NONE):
+		return "NONE";
+	}
+	return "?";
+#undef RSN_SEL
+}
+
+static void
+printrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	printf("%s", tag);
+	if (verbose) {
+		const char *sep;
+		int n;
+
+		ie += 2, ielen -= 2;
+
+		printf("<v%u", LE_READ_2(ie));
+		ie += 2, ielen -= 2;
+
+		printf(" mc:%s", rsn_cipher(ie));
+		ie += 4, ielen -= 4;
+
+		/* unicast ciphers */
+		n = LE_READ_2(ie);
+		ie += 2, ielen -= 2;
+		sep = " uc:";
+		for (; n > 0; n--) {
+			printf("%s%s", sep, rsn_cipher(ie));
+			ie += 4, ielen -= 4;
+			sep = "+";
+		}
+
+		/* key management algorithms */
+		n = LE_READ_2(ie);
+		ie += 2, ielen -= 2;
+		sep = " km:";
+		for (; n > 0; n--) {
+			printf("%s%s", sep, rsn_keymgmt(ie));
+			ie += 4, ielen -= 4;
+			sep = "+";
+		}
+
+		if (ielen > 2)		/* optional capabilities */
+			printf(", caps 0x%x", LE_READ_2(ie));
+		/* XXXPMKID */
+		printf(">");
+	}
+}
+
+/*
+ * Copy the ssid string contents into buf, truncating to fit.  If the
+ * ssid is entirely printable then just copy intact.  Otherwise convert
+ * to hexadecimal.  If the result is truncated then replace the last
+ * three characters with "...".
+ */
+static int
+copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
+{
+	const u_int8_t *p; 
+	size_t maxlen;
+	int i;
+
+	if (essid_len > bufsize)
+		maxlen = bufsize;
+	else
+		maxlen = essid_len;
+	/* determine printable or not */
+	for (i = 0, p = essid; i < maxlen; i++, p++) {
+		if (*p < ' ' || *p > 0x7e)
+			break;
+	}
+	if (i != maxlen) {		/* not printable, print as hex */
+		if (bufsize < 3)
+			return 0;
+		strlcpy(buf, "0x", bufsize);
+		bufsize -= 2;
+		p = essid;
+		for (i = 0; i < maxlen && bufsize >= 2; i++) {
+			sprintf(&buf[2+2*i], "%02x", p[i]);
+			bufsize -= 2;
+		}
+		if (i != essid_len)
+			memcpy(&buf[2+2*i-3], "...", 3);
+	} else {			/* printable, truncate as needed */
+		memcpy(buf, essid, maxlen);
+		if (maxlen != essid_len)
+			memcpy(&buf[maxlen-3], "...", 3);
+	}
+	return maxlen;
+}
+
+static void
+printssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	char ssid[2*IEEE80211_NWID_LEN+1];
+
+	printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid);
+}
+
+static void
+printrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	const char *sep;
+	int i;
+
+	printf("%s", tag);
+	sep = "<";
+	for (i = 2; i < ielen; i++) {
+		printf("%s%s%d", sep,
+		    ie[i] & IEEE80211_RATE_BASIC ? "B" : "",
+		    ie[i] & IEEE80211_RATE_VAL);
+		sep = ",";
+	}
+	printf(">");
+}
+
+static void
+printcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+	const struct ieee80211_country_ie *cie =
+	   (const struct ieee80211_country_ie *) ie;
+	int i, nbands, schan, nchan;
+
+	printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]);
+	nbands = (cie->len - 3) / sizeof(cie->band[0]);
+	for (i = 0; i < nbands; i++) {
+		schan = cie->band[i].schan;
+		nchan = cie->band[i].nchan;
+		if (nchan != 1)
+			printf(" %u-%u,%u", schan, schan + nchan-1,
+			    cie->band[i].maxtxpwr);
+		else
+			printf(" %u,%u", schan, cie->band[i].maxtxpwr);
+	}
+	printf(">");
+}
+
+/* unaligned little endian access */     
+#define LE_READ_4(p)					\
+	((u_int32_t)					\
+	 ((((const u_int8_t *)(p))[0]      ) |		\
+	  (((const u_int8_t *)(p))[1] <<  8) |		\
+	  (((const u_int8_t *)(p))[2] << 16) |		\
+	  (((const u_int8_t *)(p))[3] << 24)))
+
+static int __inline
+iswpaoui(const u_int8_t *frm)
+{
+	return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
+}
+
+static int __inline
+iswmeinfo(const u_int8_t *frm)
+{
+	return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
+		frm[6] == WME_INFO_OUI_SUBTYPE;
+}
+
+static int __inline
+iswmeparam(const u_int8_t *frm)
+{
+	return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
+		frm[6] == WME_PARAM_OUI_SUBTYPE;
+}
+
+static int __inline
+isatherosoui(const u_int8_t *frm)
+{
+	return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
+}
+
+static const char *
+iename(int elemid)
+{
+	switch (elemid) {
+	case IEEE80211_ELEMID_FHPARMS:	return " FHPARMS";
+	case IEEE80211_ELEMID_CFPARMS:	return " CFPARMS";
+	case IEEE80211_ELEMID_TIM:	return " TIM";
+	case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS";
+	case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE";
+	case IEEE80211_ELEMID_PWRCNSTR:	return " PWRCNSTR";
+	case IEEE80211_ELEMID_PWRCAP:	return " PWRCAP";
+	case IEEE80211_ELEMID_TPCREQ:	return " TPCREQ";
+	case IEEE80211_ELEMID_TPCREP:	return " TPCREP";
+	case IEEE80211_ELEMID_SUPPCHAN:	return " SUPPCHAN";
+	case IEEE80211_ELEMID_CHANSWITCHANN:return " CSA";
+	case IEEE80211_ELEMID_MEASREQ:	return " MEASREQ";
+	case IEEE80211_ELEMID_MEASREP:	return " MEASREP";
+	case IEEE80211_ELEMID_QUIET:	return " QUIET";
+	case IEEE80211_ELEMID_IBSSDFS:	return " IBSSDFS";
+	case IEEE80211_ELEMID_TPC:	return " TPC";
+	case IEEE80211_ELEMID_CCKM:	return " CCKM";
+	}
+	return " ???";
 }
 
 static void
@@ -820,21 +1870,53 @@
 {
 	while (ielen > 0) {
 		switch (vp[0]) {
+		case IEEE80211_ELEMID_SSID:
+			if (verbose)
+				printssid(" SSID", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_RATES:
+		case IEEE80211_ELEMID_XRATES:
+			if (verbose)
+				printrates(vp[0] == IEEE80211_ELEMID_RATES ?
+				    " RATES" : " XRATES", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_DSPARMS:
+			if (verbose)
+				printf(" DSPARMS<%u>", vp[2]);
+			break;
+		case IEEE80211_ELEMID_COUNTRY:
+			if (verbose)
+				printcountry(" COUNTRY", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_ERP:
+			if (verbose)
+				printf(" ERP<0x%x>", vp[2]);
+			break;
 		case IEEE80211_ELEMID_VENDOR:
 			if (iswpaoui(vp))
-				printie(" WPA", vp, 2+vp[1], maxcols);
-			else if (iswmeoui(vp))
-				printie(" WME", vp, 2+vp[1], maxcols);
+				printwpaie(" WPA", vp, 2+vp[1], maxcols);
+			else if (iswmeinfo(vp))
+				printwmeinfo(" WME", vp, 2+vp[1], maxcols);
+			else if (iswmeparam(vp))
+				printwmeparam(" WME", vp, 2+vp[1], maxcols);
 			else if (isatherosoui(vp))
-				printie(" ATH", vp, 2+vp[1], maxcols);
-			else
+				printathie(" ATH", vp, 2+vp[1], maxcols);
+			else if (verbose)
 				printie(" VEN", vp, 2+vp[1], maxcols);
 			break;
 		case IEEE80211_ELEMID_RSN:
-			printie(" RSN", vp, 2+vp[1], maxcols);
+			printrsnie(" RSN", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_HTCAP:
+			printhtcap(" HTCAP", vp, 2+vp[1], maxcols);
+			break;
+		case IEEE80211_ELEMID_HTINFO:
+			if (verbose)
+				printhtinfo(" HTINFO", vp, 2+vp[1], maxcols);
 			break;
 		default:
-			printie(" ???", vp, 2+vp[1], maxcols);
+			if (verbose)
+				printie(iename(vp[0]), vp, 2+vp[1], maxcols);
 			break;
 		}
 		ielen -= 2+vp[1];
@@ -846,51 +1928,46 @@
 list_scan(int s)
 {
 	uint8_t buf[24*1024];
-	struct ieee80211req ireq;
 	char ssid[IEEE80211_NWID_LEN+1];
-	uint8_t *cp;
+	const uint8_t *cp;
 	int len, ssidmax;
 
-	(void) memset(&ireq, 0, sizeof(ireq));
-	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
-	ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
-	ireq.i_data = buf;
-	ireq.i_len = sizeof(buf);
-	if (ioctl(s, SIOCG80211, &ireq) < 0)
+	if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0)
 		errx(1, "unable to get scan results");
-	len = ireq.i_len;
 	if (len < sizeof(struct ieee80211req_scan_result))
 		return;
 
+	getchaninfo(s);
+
 	ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
-	printf("%-*.*s  %-17.17s  %4s %4s  %-5s %3s %4s\n"
+	printf("%-*.*s  %-17.17s  %4s %4s  %-7s  %3s %4s\n"
 		, ssidmax, ssidmax, "SSID"
 		, "BSSID"
 		, "CHAN"
 		, "RATE"
-		, "S:N"
+		, " S:N"
 		, "INT"
 		, "CAPS"
 	);
 	cp = buf;
 	do {
-		struct ieee80211req_scan_result *sr;
-		uint8_t *vp;
+		const struct ieee80211req_scan_result *sr;
+		const uint8_t *vp;
 
-		sr = (struct ieee80211req_scan_result *) cp;
-		vp = (u_int8_t *)(sr+1);
-		printf("%-*.*s  %s  %3d  %3dM %2d:%-2d  %3d %-4.4s"
+		sr = (const struct ieee80211req_scan_result *) cp;
+		vp = cp + sr->isr_ie_off;
+		printf("%-*.*s  %s  %3d  %3dM %3d:%-3d  %3d %-4.4s"
 			, ssidmax
 			  , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
 			  , ssid
 			, ether_ntoa((const struct ether_addr *) sr->isr_bssid)
-			, ieee80211_mhz2ieee(sr->isr_freq)
+			, ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
 			, getmaxrate(sr->isr_rates, sr->isr_nrates)
-			, sr->isr_rssi, sr->isr_noise
+			, (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise
 			, sr->isr_intval
 			, getcaps(sr->isr_capinfo)
 		);
-		printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);;
+		printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
 		printf("\n");
 		cp += sr->isr_len, len -= sr->isr_len;
 	} while (len >= sizeof(struct ieee80211req_scan_result));
@@ -940,26 +2017,86 @@
 	list_scan(s);
 }
 
+static enum ieee80211_opmode get80211opmode(int s);
+
+static int
+gettxseq(const struct ieee80211req_sta_info *si)
+{
+#define	IEEE80211_NODE_QOS	0x0002		/* QoS enabled */
+
+	int i, txseq;
+
+	if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
+		return si->isi_txseqs[0];
+	/* XXX not right but usually what folks want */
+	txseq = 0;
+	for (i = 0; i < IEEE80211_TID_SIZE; i++)
+		if (si->isi_txseqs[i] > txseq)
+			txseq = si->isi_txseqs[i];
+	return txseq;
+#undef IEEE80211_NODE_QOS
+}
+
+static int
+getrxseq(const struct ieee80211req_sta_info *si)
+{
+#define	IEEE80211_NODE_QOS	0x0002		/* QoS enabled */
+
+	int i, rxseq;
+
+	if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
+		return si->isi_rxseqs[0];
+	/* XXX not right but usually what folks want */
+	rxseq = 0;
+	for (i = 0; i < IEEE80211_TID_SIZE; i++)
+		if (si->isi_rxseqs[i] > rxseq)
+			rxseq = si->isi_rxseqs[i];
+	return rxseq;
+#undef IEEE80211_NODE_QOS
+}
+
+static int
+gettxrate(const struct ieee80211req_sta_info *si)
+{
+	int txrate = si->isi_txrate;
+
+	if (txrate & 0x80) {
+		txrate = htrates[txrate & 0xf];
+		/* NB: could bump this more based on short gi */
+		return si->isi_flags & IEEE80211_CHAN_HT40 ?
+		    txrate : txrate / 2;
+	} else
+		return (si->isi_rates[txrate] & IEEE80211_RATE_VAL) / 2;
+}
+
 static void
 list_stations(int s)
 {
-	uint8_t buf[24*1024];
-	struct ieee80211req ireq;
-	uint8_t *cp;
+	union {
+		struct ieee80211req_sta_req req;
+		uint8_t buf[24*1024];
+	} u;
+	enum ieee80211_opmode opmode = get80211opmode(s);
+	const uint8_t *cp;
 	int len;
 
-	(void) memset(&ireq, 0, sizeof(ireq));
-	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
-	ireq.i_type = IEEE80211_IOC_STA_INFO;
-	ireq.i_data = buf;
-	ireq.i_len = sizeof(buf);
-	if (ioctl(s, SIOCG80211, &ireq) < 0)
+	/* broadcast address =>'s get all stations */
+	(void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
+	if (opmode == IEEE80211_M_STA) {
+		/*
+		 * Get information about the associated AP.
+		 */
+		(void) get80211(s, IEEE80211_IOC_BSSID,
+		    u.req.is_u.macaddr, IEEE80211_ADDR_LEN);
+	}
+	if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0)
 		errx(1, "unable to get station information");
-	len = ireq.i_len;
 	if (len < sizeof(struct ieee80211req_sta_info))
 		return;
 
-	printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n"
+	getchaninfo(s);
+
+	printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n"
 		, "ADDR"
 		, "AID"
 		, "CHAN"
@@ -969,114 +2106,229 @@
 		, "TXSEQ"
 		, "RXSEQ"
 		, "CAPS"
-		, "ERP"
+		, "FLAG"
 	);
-	cp = buf;
+	cp = (const uint8_t *) u.req.info;
 	do {
-		struct ieee80211req_sta_info *si;
-		uint8_t *vp;
+		const struct ieee80211req_sta_info *si;
 
-		si = (struct ieee80211req_sta_info *) cp;
-		vp = (u_int8_t *)(si+1);
-		printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x"
+		si = (const struct ieee80211req_sta_info *) cp;
+		if (si->isi_len < sizeof(*si))
+			break;
+		printf("%s %4u %4d %3dM %3.1f %4d %6d %6d %-4.4s %-4.4s"
 			, ether_ntoa((const struct ether_addr*) si->isi_macaddr)
 			, IEEE80211_AID(si->isi_associd)
-			, ieee80211_mhz2ieee(si->isi_freq)
-			, (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
-			, si->isi_rssi
+			, ieee80211_mhz2ieee(si->isi_freq, si->isi_flags)
+			, gettxrate(si)
+			, si->isi_rssi/2.
 			, si->isi_inact
-			, si->isi_txseqs[0]
-			, si->isi_rxseqs[0]
+			, gettxseq(si)
+			, getrxseq(si)
 			, getcaps(si->isi_capinfo)
-			, si->isi_erp
+			, getflags(si->isi_state)
 		);
-		printies(vp, si->isi_ie_len, 24);
+		printies(cp + si->isi_ie_off, si->isi_ie_len, 24);
 		printf("\n");
 		cp += si->isi_len, len -= si->isi_len;
 	} while (len >= sizeof(struct ieee80211req_sta_info));
 }
 
+static const char *
+get_chaninfo(const struct ieee80211_channel *c, int precise,
+	char buf[], size_t bsize)
+{
+	buf[0] = '\0';
+	if (IEEE80211_IS_CHAN_FHSS(c))
+		strlcat(buf, " FHSS", bsize);
+	if (IEEE80211_IS_CHAN_A(c)) {
+		if (IEEE80211_IS_CHAN_HALF(c))
+			strlcat(buf, " 11a/10Mhz", bsize);
+		else if (IEEE80211_IS_CHAN_QUARTER(c))
+			strlcat(buf, " 11a/5Mhz", bsize);
+		else
+			strlcat(buf, " 11a", bsize);
+	}
+	if (IEEE80211_IS_CHAN_ANYG(c)) {
+		if (IEEE80211_IS_CHAN_HALF(c))
+			strlcat(buf, " 11g/10Mhz", bsize);
+		else if (IEEE80211_IS_CHAN_QUARTER(c))
+			strlcat(buf, " 11g/5Mhz", bsize);
+		else
+			strlcat(buf, " 11g", bsize);
+	} else if (IEEE80211_IS_CHAN_B(c))
+		strlcat(buf, " 11b", bsize);
+	if (IEEE80211_IS_CHAN_TURBO(c))
+		strlcat(buf, " Turbo", bsize);
+	if (precise) {
+		if (IEEE80211_IS_CHAN_HT20(c))
+			strlcat(buf, " ht/20", bsize);
+		else if (IEEE80211_IS_CHAN_HT40D(c))
+			strlcat(buf, " ht/40-", bsize);
+		else if (IEEE80211_IS_CHAN_HT40U(c))
+			strlcat(buf, " ht/40+", bsize);
+	} else {
+		if (IEEE80211_IS_CHAN_HT(c))
+			strlcat(buf, " ht", bsize);
+	}
+	return buf;
+}
+
 static void
-print_chaninfo(const struct ieee80211_channel *c)
+print_chaninfo(const struct ieee80211_channel *c, int verb)
 {
-#define	IEEE80211_IS_CHAN_PASSIVE(_c) \
-	(((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
 	char buf[14];
 
-	buf[0] = '\0';
-	if (IEEE80211_IS_CHAN_FHSS(c))
-		strlcat(buf, " FHSS", sizeof(buf));
-	if (IEEE80211_IS_CHAN_A(c))
-		strlcat(buf, " 11a", sizeof(buf));
-	/* XXX 11g schizophrenia */
-	if (IEEE80211_IS_CHAN_G(c) ||
-	    IEEE80211_IS_CHAN_PUREG(c))
-		strlcat(buf, " 11g", sizeof(buf));
-	else if (IEEE80211_IS_CHAN_B(c))
-		strlcat(buf, " 11b", sizeof(buf));
-	if (IEEE80211_IS_CHAN_T(c))
-		strlcat(buf, " Turbo", sizeof(buf));
 	printf("Channel %3u : %u%c Mhz%-14.14s",
-		ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
-		IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
-#undef IEEE80211_IS_CHAN_PASSIVE
+		ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
+		IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ',
+		get_chaninfo(c, verb, buf, sizeof(buf)));
 }
 
 static void
-list_channels(int s, int allchans)
+print_channels(int s, const struct ieee80211req_chaninfo *chans,
+	int allchans, int verb)
 {
-	struct ieee80211req ireq;
-	struct ieee80211req_chaninfo chans;
 	struct ieee80211req_chaninfo achans;
+	uint8_t reported[IEEE80211_CHAN_BYTES];
 	const struct ieee80211_channel *c;
 	int i, half;
 
-	(void) memset(&ireq, 0, sizeof(ireq));
-	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
-	ireq.i_type = IEEE80211_IOC_CHANINFO;
-	ireq.i_data = &chans;
-	ireq.i_len = sizeof(chans);
-	if (ioctl(s, SIOCG80211, &ireq) < 0)
-		errx(1, "unable to get channel information");
+	memset(&achans, 0, sizeof(achans));
+	memset(reported, 0, sizeof(reported));
 	if (!allchans) {
 		struct ieee80211req_chanlist active;
 
-		ireq.i_type = IEEE80211_IOC_CHANLIST;
-		ireq.i_data = &active;
-		ireq.i_len = sizeof(active);
-		if (ioctl(s, SIOCG80211, &ireq) < 0)
+		if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0)
 			errx(1, "unable to get active channel list");
 		memset(&achans, 0, sizeof(achans));
-		for (i = 0; i < chans.ic_nchans; i++) {
-			c = &chans.ic_chans[i];
-			if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
+		for (i = 0; i < chans->ic_nchans; i++) {
+			c = &chans->ic_chans[i];
+			if (!isset(active.ic_channels, c->ic_ieee))
+				continue;
+			/*
+			 * Suppress compatible duplicates unless
+			 * verbose.  The kernel gives us it's
+			 * complete channel list which has separate
+			 * entries for 11g/11b and 11a/turbo.
+			 */
+			if (isset(reported, c->ic_ieee) && !verb) {
+				/* XXX we assume duplicates are adjacent */
+				achans.ic_chans[achans.ic_nchans-1] = *c;
+			} else {
 				achans.ic_chans[achans.ic_nchans++] = *c;
+				setbit(reported, c->ic_ieee);
+			}
 		}
-	} else
-		achans = chans;
+	} else {
+		for (i = 0; i < chans->ic_nchans; i++) {
+			c = &chans->ic_chans[i];
+			/* suppress duplicates as above */
+			if (isset(reported, c->ic_ieee) && !verb) {
+				/* XXX we assume duplicates are adjacent */
+				achans.ic_chans[achans.ic_nchans-1] = *c;
+			} else {
+				achans.ic_chans[achans.ic_nchans++] = *c;
+				setbit(reported, c->ic_ieee);
+			}
+		}
+	}
 	half = achans.ic_nchans / 2;
 	if (achans.ic_nchans % 2)
 		half++;
+
 	for (i = 0; i < achans.ic_nchans / 2; i++) {
-		print_chaninfo(&achans.ic_chans[i]);
-		print_chaninfo(&achans.ic_chans[half+i]);
+		print_chaninfo(&achans.ic_chans[i], verb);
+		print_chaninfo(&achans.ic_chans[half+i], verb);
 		printf("\n");
 	}
 	if (achans.ic_nchans % 2) {
-		print_chaninfo(&achans.ic_chans[i]);
+		print_chaninfo(&achans.ic_chans[i], verb);
 		printf("\n");
 	}
 }
 
 static void
+list_channels(int s, int allchans)
+{
+	getchaninfo(s);
+	print_channels(s, &chaninfo, allchans, verbose);
+}
+
+static void
+print_txpow(const struct ieee80211_channel *c)
+{
+	printf("Channel %3u : %u Mhz %3.1f reg %2d  ",
+	    c->ic_ieee, c->ic_freq,
+	    c->ic_maxpower/2., c->ic_maxregpower);
+}
+
+static void
+print_txpow_verbose(const struct ieee80211_channel *c)
+{
+	print_chaninfo(c, 1);
+	printf("min %4.1f dBm  max %3.1f dBm  reg %2d dBm",
+	    c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower);
+	/* indicate where regulatory cap limits power use */
+	if (c->ic_maxpower > 2*c->ic_maxregpower)
+		printf(" <");
+}
+
+static void
+list_txpow(int s)
+{
+	struct ieee80211req_chaninfo achans;
+	uint8_t reported[IEEE80211_CHAN_BYTES];
+	struct ieee80211_channel *c, *prev;
+	int i, half;
+
+	getchaninfo(s);
+	memset(&achans, 0, sizeof(achans));
+	memset(reported, 0, sizeof(reported));
+	for (i = 0; i < chaninfo.ic_nchans; i++) {
+		c = &chaninfo.ic_chans[i];
+		/* suppress duplicates as above */
+		if (isset(reported, c->ic_ieee) && !verbose) {
+			/* XXX we assume duplicates are adjacent */
+			prev = &achans.ic_chans[achans.ic_nchans-1];
+			/* display highest power on channel */
+			if (c->ic_maxpower > prev->ic_maxpower)
+				*prev = *c;
+		} else {
+			achans.ic_chans[achans.ic_nchans++] = *c;
+			setbit(reported, c->ic_ieee);
+		}
+	}
+	if (!verbose) {
+		half = achans.ic_nchans / 2;
+		if (achans.ic_nchans % 2)
+			half++;
+
+		for (i = 0; i < achans.ic_nchans / 2; i++) {
+			print_txpow(&achans.ic_chans[i]);
+			print_txpow(&achans.ic_chans[half+i]);
+			printf("\n");
+		}
+		if (achans.ic_nchans % 2) {
+			print_txpow(&achans.ic_chans[i]);
+			printf("\n");
+		}
+	} else {
+		for (i = 0; i < achans.ic_nchans; i++) {
+			print_txpow_verbose(&achans.ic_chans[i]);
+			printf("\n");
+		}
+	}
+}
+
+static void
 list_keys(int s)
 {
 }
 
 #define	IEEE80211_C_BITS \
-"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
+"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\7FF\10TURBOP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
 "\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
-"\31WPA2\32BURST\33WME"
+"\31WPA2\32BURST\33WME\34WDS\36BGSCAN\37TXFRAG"
 
 static void
 list_capabilities(int s)
@@ -1094,61 +2346,87 @@
 	putchar('\n');
 }
 
-static void
-list_wme(int s)
+static int
+get80211wme(int s, int param, int ac, int *val)
 {
-	static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
 	struct ieee80211req ireq;
-	int ac;
 
 	(void) memset(&ireq, 0, sizeof(ireq));
 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
-	ireq.i_len = 0;
+	ireq.i_type = param;
+	ireq.i_len = ac;
+	if (ioctl(s, SIOCG80211, &ireq) < 0) {
+		warn("cannot get WME parameter %d, ac %d%s",
+		    param, ac & IEEE80211_WMEPARAM_VAL,
+		    ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : "");
+		return -1;
+	}
+	*val = ireq.i_val;
+	return 0;
+}
+
+static void
+list_wme(int s)
+{
+	static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" };
+	int ac, val;
+
 	for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
 again:
-		if (ireq.i_len & IEEE80211_WMEPARAM_BSS)
+		if (ac & IEEE80211_WMEPARAM_BSS)
 			printf("\t%s", "     ");
 		else
 			printf("\t%s", acnames[ac]);
 
-		ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac;
-
 		/* show WME BSS parameters */
-		ireq.i_type = IEEE80211_IOC_WME_CWMIN;
-		if (ioctl(s, SIOCG80211, &ireq) != -1)
-			printf(" cwmin %2u", ireq.i_val);
-		ireq.i_type = IEEE80211_IOC_WME_CWMAX;
-		if (ioctl(s, SIOCG80211, &ireq) != -1)
-			printf(" cwmax %2u", ireq.i_val);
-		ireq.i_type = IEEE80211_IOC_WME_AIFS;
-		if (ioctl(s, SIOCG80211, &ireq) != -1)
-			printf(" aifs %2u", ireq.i_val);
-		ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT;
-		if (ioctl(s, SIOCG80211, &ireq) != -1)
-			printf(" txopLimit %3u", ireq.i_val);
-		ireq.i_type = IEEE80211_IOC_WME_ACM;
-		if (ioctl(s, SIOCG80211, &ireq) != -1) {
-			if (ireq.i_val)
+		if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1)
+			printf(" cwmin %2u", val);
+		if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1)
+			printf(" cwmax %2u", val);
+		if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1)
+			printf(" aifs %2u", val);
+		if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1)
+			printf(" txopLimit %3u", val);
+		if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) {
+			if (val)
 				printf(" acm");
 			else if (verbose)
 				printf(" -acm");
 		}
 		/* !BSS only */
-		if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
-			ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY;
-			if (ioctl(s, SIOCG80211, &ireq) != -1) {
-				if (!ireq.i_val)
+		if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
+			if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) {
+				if (!val)
 					printf(" -ack");
 				else if (verbose)
 					printf(" ack");
 			}
 		}
 		printf("\n");
-		if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
-			ireq.i_len |= IEEE80211_WMEPARAM_BSS;
+		if ((ac & IEEE80211_WMEPARAM_BSS) == 0) {
+			ac |= IEEE80211_WMEPARAM_BSS;
 			goto again;
 		} else
-			ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
+			ac &= ~IEEE80211_WMEPARAM_BSS;
+	}
+}
+
+static void
+printpolicy(int policy)
+{
+	switch (policy) {
+	case IEEE80211_MACCMD_POLICY_OPEN:
+		printf("policy: open\n");
+		break;
+	case IEEE80211_MACCMD_POLICY_ALLOW:
+		printf("policy: allow\n");
+		break;
+	case IEEE80211_MACCMD_POLICY_DENY:
+		printf("policy: deny\n");
+		break;
+	default:
+		printf("policy: unknown (%u)\n", policy);
+		break;
 	}
 }
 
@@ -1157,7 +2435,8 @@
 {
 	struct ieee80211req ireq;
 	struct ieee80211req_maclist *acllist;
-	int i, nacls, policy;
+	int i, nacls, policy, len;
+	uint8_t *data;
 	char c;
 
 	(void) memset(&ireq, 0, sizeof(ireq));
@@ -1172,41 +2451,43 @@
 		err(1, "unable to get mac policy");
 	}
 	policy = ireq.i_val;
+	if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
+		c = '*';
+	} else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
+		c = '+';
+	} else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
+		c = '-';
+	} else {
+		printf("policy: unknown (%u)\n", policy);
+		c = '?';
+	}
+	if (verbose || c == '?')
+		printpolicy(policy);
 
 	ireq.i_val = IEEE80211_MACCMD_LIST;
 	ireq.i_len = 0;
 	if (ioctl(s, SIOCG80211, &ireq) < 0)
 		err(1, "unable to get mac acl list size");
-	if (ireq.i_len == 0)		/* NB: no acls */
+	if (ireq.i_len == 0) {		/* NB: no acls */
+		if (!(verbose || c == '?'))
+			printpolicy(policy);
 		return;
+	}
+	len = ireq.i_len;
 
-	ireq.i_data = malloc(ireq.i_len);
-	if (ireq.i_data == NULL)
+	data = malloc(len);
+	if (data == NULL)
 		err(1, "out of memory for acl list");
 
+	ireq.i_data = data;
 	if (ioctl(s, SIOCG80211, &ireq) < 0)
 		err(1, "unable to get mac acl list");
-	if (policy == IEEE80211_MACCMD_POLICY_OPEN) {
-		if (verbose)
-			printf("policy: open\n");
-		c = '*';
-	} else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) {
-		if (verbose)
-			printf("policy: allow\n");
-		c = '+';
-	} else if (policy == IEEE80211_MACCMD_POLICY_DENY) {
-		if (verbose)
-			printf("policy: deny\n");
-		c = '-';
-	} else {
-		printf("policy: unknown (%u)\n", policy);
-		c = '?';
-	}
-	nacls = ireq.i_len / sizeof(*acllist);
-	acllist = (struct ieee80211req_maclist *) ireq.i_data;
+	nacls = len / sizeof(*acllist);
+	acllist = (struct ieee80211req_maclist *) data;
 	for (i = 0; i < nacls; i++)
 		printf("%c%s\n", c, ether_ntoa(
 			(const struct ether_addr *) acllist[i].ml_macaddr));
+	free(data);
 }
 
 static
@@ -1214,6 +2495,8 @@
 {
 #define	iseq(a,b)	(strncasecmp(a,b,sizeof(b)-1) == 0)
 
+	LINE_INIT('\t');
+
 	if (iseq(arg, "sta"))
 		list_stations(s);
 	else if (iseq(arg, "scan") || iseq(arg, "ap"))
@@ -1230,6 +2513,8 @@
 		list_wme(s);
 	else if (iseq(arg, "mac"))
 		list_mac(s);
+	else if (iseq(arg, "txpow"))
+		list_txpow(s);
 	else
 		errx(1, "Don't know how to list %s for %s", arg, name);
 #undef iseq
@@ -1254,31 +2539,6 @@
 	return IEEE80211_M_STA;
 }
 
-static const struct ieee80211_channel *
-getchaninfo(int s, int chan)
-{
-	struct ieee80211req ireq;
-	static struct ieee80211req_chaninfo chans;
-	static struct ieee80211_channel undef;
-	const struct ieee80211_channel *c;
-	int i, freq;
-
-	(void) memset(&ireq, 0, sizeof(ireq));
-	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
-	ireq.i_type = IEEE80211_IOC_CHANINFO;
-	ireq.i_data = &chans;
-	ireq.i_len = sizeof(chans);
-	if (ioctl(s, SIOCG80211, &ireq) < 0)
-		errx(1, "unable to get channel information");
-	freq = ieee80211_ieee2mhz(chan);
-	for (i = 0; i < chans.ic_nchans; i++) {
-		c = &chans.ic_chans[i];
-		if (c->ic_freq == freq)
-			return c;
-	}
-	return &undef;
-}
-
 #if 0
 static void
 printcipher(int s, struct ieee80211req *ireq, int keylenop)
@@ -1315,40 +2575,6 @@
 }
 #endif
 
-#define	MAXCOL	78
-static	int col;
-static	char spacer;
-
-static void
-LINE_BREAK(void)
-{
-	if (spacer != '\t') {
-		printf("\n");
-		spacer = '\t';
-	}
-	col = 8;	/* 8-col tab */
-}
-
-static void
-LINE_CHECK(const char *fmt, ...)
-{
-	char buf[80];
-	va_list ap;
-	int n;
-
-	va_start(ap, fmt);
-	n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
-	va_end(ap);
-	col += 1+n;
-	if (col > MAXCOL) {
-		LINE_BREAK();
-		col += n;
-	}
-	buf[0] = spacer;
-	printf("%s", buf);
-	spacer = ' ';
-}
-
 static void
 printkey(const struct ieee80211req_key *ik)
 {
@@ -1417,131 +2643,164 @@
 }
 
 static void
-ieee80211_status(int s)
+printrate(const char *tag, int v, int defrate, int defmcs)
+{
+	if (v == 11)
+		LINE_CHECK("%s 5.5", tag);
+	else if (v & 0x80) {
+		if (v != defmcs)
+			LINE_CHECK("%s %d", tag, v &~ 0x80);
+	} else {
+		if (v != defrate)
+			LINE_CHECK("%s %d", tag, v/2);
+	}
+}
+
+static int
+getssid(int s, int ix, void *data, size_t len, int *plen)
 {
-	static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
-	enum ieee80211_opmode opmode = get80211opmode(s);
-	int i, num, wpa, wme;
 	struct ieee80211req ireq;
-	u_int8_t data[32];
-	const struct ieee80211_channel *c;
 
 	(void) memset(&ireq, 0, sizeof(ireq));
 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
-	ireq.i_data = &data;
+	ireq.i_type = IEEE80211_IOC_SSID;
+	ireq.i_val = ix;
+	ireq.i_data = data;
+	ireq.i_len = len;
+	if (ioctl(s, SIOCG80211, &ireq) < 0)
+		return -1;
+	*plen = ireq.i_len;
+	return 0;
+}
 
-	wpa = 0;		/* unknown/not set */
+static void
+printrssi(const char *tag, int rssi)
+{
+	if (rssi & 1)
+		LINE_CHECK("%s %u.5", tag, rssi/2);
+	else
+		LINE_CHECK("%s %u", tag, rssi/2);
+}
 
-	ireq.i_type = IEEE80211_IOC_SSID;
-	ireq.i_val = -1;
-	if (ioctl(s, SIOCG80211, &ireq) < 0) {
+static void
+ieee80211_status(int s)
+{
+	static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
+	enum ieee80211_opmode opmode = get80211opmode(s);
+	int i, num, wpa, wme, bgscan, bgscaninterval, val, len, wepmode;
+	uint8_t data[32];
+	const struct ieee80211_channel *c;
+
+	if (getssid(s, -1, data, sizeof(data), &len) < 0) {
 		/* If we can't get the SSID, this isn't an 802.11 device. */
 		return;
 	}
-	num = 0;
-	ireq.i_type = IEEE80211_IOC_NUMSSIDS;
-	if (ioctl(s, SIOCG80211, &ireq) >= 0)
-		num = ireq.i_val;
+
+	/*
+	 * Invalidate cached state so printing status for multiple
+	 * if's doesn't reuse the first interfaces' cached state.
+	 */
+	gotcurchan = 0;
+	gothtconf = 0;
+
+	if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0)
+		num = 0;
 	printf("\tssid ");
 	if (num > 1) {
-		ireq.i_type = IEEE80211_IOC_SSID;
-		for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) {
-			if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) {
-				printf(" %d:", ireq.i_val + 1);
-				print_string(data, ireq.i_len);
+		for (i = 0; i < num; i++) {
+			if (getssid(s, i, data, sizeof(data), &len) >= 0 && len > 0) {
+				printf(" %d:", i + 1);
+				print_string(data, len);
 			}
 		}
 	} else
-		print_string(data, ireq.i_len);
+		print_string(data, len);
 
-	ireq.i_type = IEEE80211_IOC_CHANNEL;
-	if (ioctl(s, SIOCG80211, &ireq) < 0)
-		goto end;
-	c = getchaninfo(s, ireq.i_val);
-	if (ireq.i_val != -1) {
-		printf(" channel %d", ireq.i_val);
-		if (verbose)
-			printf(" (%u)", c->ic_freq);
+	c = getcurchan(s);
+	if (c->ic_freq != IEEE80211_CHAN_ANY) {
+		char buf[14];
+		printf(" channel %d (%u Mhz%s)", c->ic_ieee, c->ic_freq,
+			get_chaninfo(c, 1, buf, sizeof(buf)));
 	} else if (verbose)
 		printf(" channel UNDEF");
 
-	ireq.i_type = IEEE80211_IOC_BSSID;
-	ireq.i_len = IEEE80211_ADDR_LEN;
-	if (ioctl(s, SIOCG80211, &ireq) >= 0 &&
-	    (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
-		printf(" bssid %s", ether_ntoa(ireq.i_data));
+	if (get80211(s, IEEE80211_IOC_BSSID, data, IEEE80211_ADDR_LEN) >= 0 &&
+	    (memcmp(data, zerobssid, sizeof(zerobssid)) != 0 || verbose))
+		printf(" bssid %s", ether_ntoa((struct ether_addr *)data));
 
-	ireq.i_type = IEEE80211_IOC_STATIONNAME;
-	if (ioctl(s, SIOCG80211, &ireq) != -1) {
+	if (get80211len(s, IEEE80211_IOC_STATIONNAME, data, sizeof(data), &len) != -1) {
 		printf("\n\tstationname ");
-		print_string(data, ireq.i_len);
+		print_string(data, len);
 	}
 
 	spacer = ' ';		/* force first break */
 	LINE_BREAK();
 
-	ireq.i_type = IEEE80211_IOC_AUTHMODE;
-	if (ioctl(s, SIOCG80211, &ireq) != -1) {
-		switch (ireq.i_val) {
-			case IEEE80211_AUTH_NONE:
-				LINE_CHECK("authmode NONE");
-				break;
-			case IEEE80211_AUTH_OPEN:
-				LINE_CHECK("authmode OPEN");
-				break;
-			case IEEE80211_AUTH_SHARED:
-				LINE_CHECK("authmode SHARED");
-				break;
-			case IEEE80211_AUTH_8021X:
-				LINE_CHECK("authmode 802.1x");
-				break;
-			case IEEE80211_AUTH_WPA:
-				ireq.i_type = IEEE80211_IOC_WPA;
-				if (ioctl(s, SIOCG80211, &ireq) != -1)
-					wpa = ireq.i_val;
-				if (!wpa)
-					wpa = 1;	/* default to WPA1 */
-				switch (wpa) {
-				case 2:
-					LINE_CHECK("authmode WPA2/802.11i");
-					break;
-				case 3:
-					LINE_CHECK("authmode WPA1+WPA2/802.11i");
-					break;
-				default:
-					LINE_CHECK("authmode WPA");
-					break;
-				}
+	wpa = 0;
+	if (get80211val(s, IEEE80211_IOC_AUTHMODE, &val) != -1) {
+		switch (val) {
+		case IEEE80211_AUTH_NONE:
+			LINE_CHECK("authmode NONE");
+			break;
+		case IEEE80211_AUTH_OPEN:
+			LINE_CHECK("authmode OPEN");
+			break;
+		case IEEE80211_AUTH_SHARED:
+			LINE_CHECK("authmode SHARED");
+			break;
+		case IEEE80211_AUTH_8021X:
+			LINE_CHECK("authmode 802.1x");
+			break;
+		case IEEE80211_AUTH_WPA:
+			if (get80211val(s, IEEE80211_IOC_WPA, &wpa) < 0)
+				wpa = 1;	/* default to WPA1 */
+			switch (wpa) {
+			case 2:
+				LINE_CHECK("authmode WPA2/802.11i");
 				break;
-			case IEEE80211_AUTH_AUTO:
-				LINE_CHECK("authmode AUTO");
+			case 3:
+				LINE_CHECK("authmode WPA1+WPA2/802.11i");
 				break;
 			default:
-				LINE_CHECK("authmode UNKNOWN (0x%x)",
-					ireq.i_val);
+				LINE_CHECK("authmode WPA");
 				break;
+			}
+			break;
+		case IEEE80211_AUTH_AUTO:
+			LINE_CHECK("authmode AUTO");
+			break;
+		default:
+			LINE_CHECK("authmode UNKNOWN (0x%x)", val);
+			break;
+		}
+	}
+
+	if (wpa || verbose) {
+		if (ioctl(s, IEEE80211_IOC_COUNTERMEASURES, &val) != -1) {
+			if (val)
+				LINE_CHECK("countermeasures");
+			else if (verbose)
+				LINE_CHECK("-countermeasures");
 		}
 	}
 
-	ireq.i_type = IEEE80211_IOC_WEP;
-	if (ioctl(s, SIOCG80211, &ireq) != -1 &&
-	    ireq.i_val != IEEE80211_WEP_NOSUP) {
-		int firstkey, wepmode;
+	if (get80211val(s, IEEE80211_IOC_WEP, &wepmode) != -1 &&
+	    wepmode != IEEE80211_WEP_NOSUP) {
+		int firstkey;
 
-		wepmode = ireq.i_val;
 		switch (wepmode) {
-			case IEEE80211_WEP_OFF:
-				LINE_CHECK("privacy OFF");
-				break;
-			case IEEE80211_WEP_ON:
-				LINE_CHECK("privacy ON");
-				break;
-			case IEEE80211_WEP_MIXED:
-				LINE_CHECK("privacy MIXED");
-				break;
-			default:
-				LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
-				break;
+		case IEEE80211_WEP_OFF:
+			LINE_CHECK("privacy OFF");
+			break;
+		case IEEE80211_WEP_ON:
+			LINE_CHECK("privacy ON");
+			break;
+		case IEEE80211_WEP_MIXED:
+			LINE_CHECK("privacy MIXED");
+			break;
+		default:
+			LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode);
+			break;
 		}
 
 		/*
@@ -1549,22 +2808,19 @@
 		 * to print WEP status.
 		 */
 
-		ireq.i_type = IEEE80211_IOC_WEPTXKEY;
-		if (ioctl(s, SIOCG80211, &ireq) < 0) {
+		if (get80211val(s, IEEE80211_IOC_WEPTXKEY, &val) < 0) {
 			warn("WEP support, but no tx key!");
 			goto end;
 		}
-		if (ireq.i_val != -1)
-			LINE_CHECK("deftxkey %d", ireq.i_val+1);
+		if (val != -1)
+			LINE_CHECK("deftxkey %d", val+1);
 		else if (wepmode != IEEE80211_WEP_OFF || verbose)
 			LINE_CHECK("deftxkey UNDEF");
 
-		ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
-		if (ioctl(s, SIOCG80211, &ireq) < 0) {
+		if (get80211val(s, IEEE80211_IOC_NUMWEPKEYS, &num) < 0) {
 			warn("WEP support, but no NUMWEPKEYS support!");
 			goto end;
 		}
-		num = ireq.i_val;
 
 		firstkey = 1;
 		for (i = 0; i < num; i++) {
@@ -1572,10 +2828,7 @@
 
 			memset(&ik, 0, sizeof(ik));
 			ik.ik_keyix = i;
-			ireq.i_type = IEEE80211_IOC_WPAKEY;
-			ireq.i_data = &ik;
-			ireq.i_len = sizeof(ik);
-			if (ioctl(s, SIOCG80211, &ireq) < 0) {
+			if (get80211(s, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik)) < 0) {
 				warn("WEP support, but can get keys!");
 				goto end;
 			}
@@ -1586,95 +2839,252 @@
 				firstkey = 0;
 			}
 		}
+end:
+		;
 	}
 
-	ireq.i_type = IEEE80211_IOC_POWERSAVE;
-	if (ioctl(s, SIOCG80211, &ireq) != -1 &&
-	    ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
-		if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) {
-			switch (ireq.i_val) {
-				case IEEE80211_POWERSAVE_OFF:
-					LINE_CHECK("powersavemode OFF");
-					break;
-				case IEEE80211_POWERSAVE_CAM:
-					LINE_CHECK("powersavemode CAM");
-					break;
-				case IEEE80211_POWERSAVE_PSP:
-					LINE_CHECK("powersavemode PSP");
-					break;
-				case IEEE80211_POWERSAVE_PSP_CAM:
-					LINE_CHECK("powersavemode PSP-CAM");
-					break;
+	if (get80211val(s, IEEE80211_IOC_POWERSAVE, &val) != -1 &&
+	    val != IEEE80211_POWERSAVE_NOSUP ) {
+		if (val != IEEE80211_POWERSAVE_OFF || verbose) {
+			switch (val) {
+			case IEEE80211_POWERSAVE_OFF:
+				LINE_CHECK("powersavemode OFF");
+				break;
+			case IEEE80211_POWERSAVE_CAM:
+				LINE_CHECK("powersavemode CAM");
+				break;
+			case IEEE80211_POWERSAVE_PSP:
+				LINE_CHECK("powersavemode PSP");
+				break;
+			case IEEE80211_POWERSAVE_PSP_CAM:
+				LINE_CHECK("powersavemode PSP-CAM");
+				break;
 			}
-			ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
-			if (ioctl(s, SIOCG80211, &ireq) != -1)
-				LINE_CHECK("powersavesleep %d", ireq.i_val);
+			if (get80211val(s, IEEE80211_IOC_POWERSAVESLEEP, &val) != -1)
+				LINE_CHECK("powersavesleep %d", val);
 		}
 	}
 
-	ireq.i_type = IEEE80211_IOC_TXPOWMAX;
-	if (ioctl(s, SIOCG80211, &ireq) != -1)
-		LINE_CHECK("txpowmax %d", ireq.i_val);
-
+	if (get80211val(s, IEEE80211_IOC_TXPOWER, &val) != -1) {
+		if (val & 1)
+			LINE_CHECK("txpower %d.5", val/2);
+		else
+			LINE_CHECK("txpower %d", val/2);
+	}
 	if (verbose) {
-		ireq.i_type = IEEE80211_IOC_TXPOWER;
-		if (ioctl(s, SIOCG80211, &ireq) != -1)
-			LINE_CHECK("txpower %d", ireq.i_val);
-	}
-
-	ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
-	if (ioctl(s, SIOCG80211, &ireq) != -1) {
-		if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
-			LINE_CHECK("rtsthreshold %d", ireq.i_val);
-	}
-
-	ireq.i_type = IEEE80211_IOC_MCAST_RATE;
-	if (ioctl(s, SIOCG80211, &ireq) != -1) {
-		if (ireq.i_val != 2*1 || verbose) {
-			if (ireq.i_val == 11)
-				LINE_CHECK("mcastrate 5.5");
-			else
-				LINE_CHECK("mcastrate %d", ireq.i_val/2);
+		if (get80211val(s, IEEE80211_IOC_TXPOWMAX, &val) != -1)
+			LINE_CHECK("txpowmax %.1f", val/2.);
+	}
+
+	if (get80211val(s, IEEE80211_IOC_RTSTHRESHOLD, &val) != -1) {
+		if (val != IEEE80211_RTS_MAX || verbose)
+			LINE_CHECK("rtsthreshold %d", val);
+	}
+
+	if (get80211val(s, IEEE80211_IOC_FRAGTHRESHOLD, &val) != -1) {
+		if (val != IEEE80211_FRAG_MAX || verbose)
+			LINE_CHECK("fragthreshold %d", val);
+	}
+	if (opmode == IEEE80211_M_STA || verbose) {
+		if (get80211val(s, IEEE80211_IOC_BMISSTHRESHOLD, &val) != -1) {
+			if (val != IEEE80211_HWBMISS_MAX || verbose)
+				LINE_CHECK("bmiss %d", val);
 		}
 	}
 
-	ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
-	if (ioctl(s, SIOCG80211, &ireq) != -1) {
-		if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
-			LINE_CHECK("fragthreshold %d", ireq.i_val);
+	if (get80211val(s, IEEE80211_IOC_MCAST_RATE, &val) != -1)
+		printrate("mcastrate", val, 2*1, 0/*XXX*/);
+
+	bgscaninterval = -1;
+	(void) get80211val(s, IEEE80211_IOC_BGSCAN_INTERVAL, &bgscaninterval);
+
+	if (get80211val(s, IEEE80211_IOC_SCANVALID, &val) != -1) {
+		if (val != bgscaninterval || verbose)
+			LINE_CHECK("scanvalid %u", val);
+	}
+
+	bgscan = 0;
+	if (get80211val(s, IEEE80211_IOC_BGSCAN, &bgscan) != -1) {
+		if (bgscan)
+			LINE_CHECK("bgscan");
+		else if (verbose)
+			LINE_CHECK("-bgscan");
+	}
+	if (bgscan || verbose) {
+		if (bgscaninterval != -1)
+			LINE_CHECK("bgscanintvl %u", bgscaninterval);
+		if (get80211val(s, IEEE80211_IOC_BGSCAN_IDLE, &val) != -1)
+			LINE_CHECK("bgscanidle %u", val);
+		if (IEEE80211_IS_CHAN_A(c) || verbose) {
+			if (get80211val(s, IEEE80211_IOC_ROAM_RSSI_11A, &val) != -1)
+				printrssi("roam:rssi11a", val);
+			if (get80211val(s, IEEE80211_IOC_ROAM_RATE_11A, &val) != -1)
+				printrate("roam:rate11a", val, -1, -1);
+		}
+		if (IEEE80211_IS_CHAN_B(c) || verbose) {
+			if (get80211val(s, IEEE80211_IOC_ROAM_RSSI_11B, &val) != -1)
+				printrssi("roam:rssi11b", val);
+			if (get80211val(s, IEEE80211_IOC_ROAM_RATE_11B, &val) != -1)
+				printrate("roam:rate11b", val, -1, -1);
+		}
+		if (IEEE80211_IS_CHAN_ANYG(c) || verbose) {
+			if (get80211val(s, IEEE80211_IOC_ROAM_RSSI_11G, &val) != -1)
+				printrssi("roam:rssi11g", val);
+			if (get80211val(s, IEEE80211_IOC_ROAM_RATE_11G, &val) != -1)
+				printrate("roam:rate11g", val, -1, -1);
+		}
 	}
 
-	if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
-		ireq.i_type = IEEE80211_IOC_PUREG;
-		if (ioctl(s, SIOCG80211, &ireq) != -1) {
-			if (ireq.i_val)
+	if (IEEE80211_IS_CHAN_ANYG(c) || verbose) {
+		if (get80211val(s, IEEE80211_IOC_PUREG, &val) != -1) {
+			if (val)
 				LINE_CHECK("pureg");
 			else if (verbose)
 				LINE_CHECK("-pureg");
 		}
-		ireq.i_type = IEEE80211_IOC_PROTMODE;
-		if (ioctl(s, SIOCG80211, &ireq) != -1) {
-			switch (ireq.i_val) {
-				case IEEE80211_PROTMODE_OFF:
-					LINE_CHECK("protmode OFF");
-					break;
-				case IEEE80211_PROTMODE_CTS:
-					LINE_CHECK("protmode CTS");
-					break;
-				case IEEE80211_PROTMODE_RTSCTS:
-					LINE_CHECK("protmode RTSCTS");
-					break;
-				default:
-					LINE_CHECK("protmode UNKNOWN (0x%x)",
-						ireq.i_val);
-					break;
+		if (get80211val(s, IEEE80211_IOC_PROTMODE, &val) != -1) {
+			switch (val) {
+			case IEEE80211_PROTMODE_OFF:
+				LINE_CHECK("protmode OFF");
+				break;
+			case IEEE80211_PROTMODE_CTS:
+				LINE_CHECK("protmode CTS");
+				break;
+			case IEEE80211_PROTMODE_RTSCTS:
+				LINE_CHECK("protmode RTSCTS");
+				break;
+			default:
+				LINE_CHECK("protmode UNKNOWN (0x%x)", val);
+				break;
+			}
+		}
+	}
+
+	if (IEEE80211_IS_CHAN_HT(c) || verbose) {
+		gethtconf(s);
+		switch (htconf & 3) {
+		case 0:
+		case 2:
+			LINE_CHECK("-ht");
+			break;
+		case 1:
+			LINE_CHECK("ht20");
+			break;
+		case 3:
+			if (verbose)
+				LINE_CHECK("ht");
+			break;
+		}
+		if (get80211val(s, IEEE80211_IOC_HTCOMPAT, &val) != -1) {
+			if (!val)
+				LINE_CHECK("-htcompat");
+			else if (verbose)
+				LINE_CHECK("htcompat");
+		}
+		if (get80211val(s, IEEE80211_IOC_AMPDU, &val) != -1) {
+			switch (val) {
+			case 0:
+				LINE_CHECK("-ampdu");
+				break;
+			case 1:
+				LINE_CHECK("ampdutx -ampdurx");
+				break;
+			case 2:
+				LINE_CHECK("-ampdutx ampdurx");
+				break;
+			case 3:
+				if (verbose)
+					LINE_CHECK("ampdu");
+				break;
+			}
+		}
+		if (get80211val(s, IEEE80211_IOC_AMPDU_LIMIT, &val) != -1) {
+			switch (val) {
+			case IEEE80211_HTCAP_MAXRXAMPDU_8K:
+				LINE_CHECK("ampdulimit 8k");
+				break;
+			case IEEE80211_HTCAP_MAXRXAMPDU_16K:
+				LINE_CHECK("ampdulimit 16k");
+				break;
+			case IEEE80211_HTCAP_MAXRXAMPDU_32K:
+				LINE_CHECK("ampdulimit 32k");
+				break;
+			case IEEE80211_HTCAP_MAXRXAMPDU_64K:
+				LINE_CHECK("ampdulimit 64k");
+				break;
+			}
+		}
+		if (get80211val(s, IEEE80211_IOC_AMPDU_DENSITY, &val) != -1) {
+			switch (val) {
+			case IEEE80211_HTCAP_MPDUDENSITY_NA:
+				if (verbose)
+					LINE_CHECK("ampdudensity -");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_025:
+				LINE_CHECK("ampdudensity .25");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_05:
+				LINE_CHECK("ampdudensity .5");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_1:
+				LINE_CHECK("ampdudensity 1");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_2:
+				LINE_CHECK("ampdudensity 2");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_4:
+				LINE_CHECK("ampdudensity 4");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_8:
+				LINE_CHECK("ampdudensity 8");
+				break;
+			case IEEE80211_HTCAP_MPDUDENSITY_16:
+				LINE_CHECK("ampdudensity 16");
+				break;
+			}
+		}
+		if (get80211val(s, IEEE80211_IOC_AMSDU, &val) != -1) {
+			switch (val) {
+			case 0:
+				LINE_CHECK("-amsdu");
+				break;
+			case 1:
+				LINE_CHECK("amsdutx -amsdurx");
+				break;
+			case 2:
+				LINE_CHECK("-amsdutx amsdurx");
+				break;
+			case 3:
+				if (verbose)
+					LINE_CHECK("amsdu");
+				break;
 			}
 		}
+		/* XXX amsdu limit */
+		/* XXX 20/40 */
+		if (get80211val(s, IEEE80211_IOC_SHORTGI, &val) != -1) {
+			if (val)
+				LINE_CHECK("shortgi");
+			else if (verbose)
+				LINE_CHECK("-shortgi");
+		}
+		if (get80211val(s, IEEE80211_IOC_HTPROTMODE, &val) != -1) {
+			if (val == IEEE80211_PROTMODE_OFF)
+				LINE_CHECK("htprotmode OFF");
+			else if (val != IEEE80211_PROTMODE_RTSCTS)
+				LINE_CHECK("htprotmode UNKNOWN (0x%x)", val);
+			else if (verbose)
+				LINE_CHECK("htprotmode RTSCTS");
+		}
+		if (get80211val(s, IEEE80211_IOC_PUREN, &val) != -1) {
+			if (val)
+				LINE_CHECK("puren");
+			else if (verbose)
+				LINE_CHECK("-puren");
+		}
 	}
 
-	ireq.i_type = IEEE80211_IOC_WME;
-	if (ioctl(s, SIOCG80211, &ireq) != -1) {
-		wme = ireq.i_val;
+	if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) {
 		if (wme)
 			LINE_CHECK("wme");
 		else if (verbose)
@@ -1682,39 +3092,58 @@
 	} else
 		wme = 0;
 
-	ireq.i_type = IEEE80211_IOC_BURST;
-	if (ioctl(s, SIOCG80211, &ireq) != -1) {
-		if (ireq.i_val)
+	if (get80211val(s, IEEE80211_IOC_BURST, &val) != -1) {
+		if (val)
 			LINE_CHECK("burst");
 		else if (verbose)
 			LINE_CHECK("-burst");
 	}
 
+	if (get80211val(s, IEEE80211_IOC_FF, &val) != -1) {
+		if (val)
+			LINE_CHECK("ff");
+		else if (verbose)
+			LINE_CHECK("-ff");
+	}
+	if (get80211val(s, IEEE80211_IOC_TURBOP, &val) != -1) {
+		if (val)
+			LINE_CHECK("dturbo");
+		else if (verbose)
+			LINE_CHECK("-dturbo");
+	}
+
 	if (opmode == IEEE80211_M_HOSTAP) {
-		ireq.i_type = IEEE80211_IOC_HIDESSID;
-		if (ioctl(s, SIOCG80211, &ireq) != -1) {
-			if (ireq.i_val)
-				LINE_CHECK("ssid HIDE");
+		if (get80211val(s, IEEE80211_IOC_HIDESSID, &val) != -1) {
+			if (val)
+				LINE_CHECK("hidessid");
 			else if (verbose)
-				LINE_CHECK("ssid SHOW");
+				LINE_CHECK("-hidessid");
 		}
-
-		ireq.i_type = IEEE80211_IOC_APBRIDGE;
-		if (ioctl(s, SIOCG80211, &ireq) != -1) {
-			if (!ireq.i_val)
+		if (get80211val(s, IEEE80211_IOC_APBRIDGE, &val) != -1) {
+			if (!val)
 				LINE_CHECK("-apbridge");
 			else if (verbose)
 				LINE_CHECK("apbridge");
 		}
+		if (get80211val(s, IEEE80211_IOC_DTIM_PERIOD, &val) != -1)
+			LINE_CHECK("dtimperiod %u", val);
 
-		ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
-		if (ioctl(s, SIOCG80211, &ireq) != -1)
-			LINE_CHECK("dtimperiod %u", ireq.i_val);
+		if (get80211val(s, IEEE80211_IOC_DOTH, &val) != -1) {
+			if (!val)
+				LINE_CHECK("-doth");
+			else if (verbose)
+				LINE_CHECK("doth");
+		}
+		if (get80211val(s, IEEE80211_IOC_INACTIVITY, &val) != -1) {
+			if (!val)
+				LINE_CHECK("-inact");
+			else if (verbose)
+				LINE_CHECK("inact");
+		}
 	} else {
-		ireq.i_type = IEEE80211_IOC_ROAMING;
-		if (ioctl(s, SIOCG80211, &ireq) != -1) {
-			if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) {
-				switch (ireq.i_val) {
+		if (get80211val(s, IEEE80211_IOC_ROAMING, &val) != -1) {
+			if (val != IEEE80211_ROAMING_AUTO || verbose) {
+				switch (val) {
 				case IEEE80211_ROAMING_DEVICE:
 					LINE_CHECK("roaming DEVICE");
 					break;
@@ -1726,74 +3155,70 @@
 					break;
 				default:
 					LINE_CHECK("roaming UNKNOWN (0x%x)",
-						ireq.i_val);
+						val);
 					break;
 				}
 			}
 		}
 	}
-	ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
-	if (ioctl(s, SIOCG80211, &ireq) != -1) {
-		if (ireq.i_val)
-			LINE_CHECK("bintval %u", ireq.i_val);
-		else if (verbose)
-			LINE_CHECK("bintval %u", ireq.i_val);
+	if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) {
+		/* XXX default define not visible */
+		if (val != 100 || verbose)
+			LINE_CHECK("bintval %u", val);
 	}
 
 	if (wme && verbose) {
 		LINE_BREAK();
 		list_wme(s);
 	}
+	LINE_BREAK();
+}
 
-	if (wpa) {
-		ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
-		if (ioctl(s, SIOCG80211, &ireq) != -1) {
-			if (ireq.i_val)
-				LINE_CHECK("countermeasures");
-			else if (verbose)
-				LINE_CHECK("-countermeasures");
-		}
-#if 0
-		/* XXX not interesting with WPA done in user space */
-		ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
-		if (ioctl(s, SIOCG80211, &ireq) != -1) {
-		}
+static int
+get80211(int s, int type, void *data, int len)
+{
+	struct ieee80211req ireq;
 
-		ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
-		if (ioctl(s, SIOCG80211, &ireq) != -1) {
-			LINE_CHECK("mcastcipher ");
-			printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
-			spacer = ' ';
-		}
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+	ireq.i_type = type;
+	ireq.i_data = data;
+	ireq.i_len = len;
+	return ioctl(s, SIOCG80211, &ireq);
+}
 
-		ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
-		if (ioctl(s, SIOCG80211, &ireq) != -1) {
-			LINE_CHECK("ucastcipher ");
-			printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
-		}
+static int
+get80211len(int s, int type, void *data, int len, int *plen)
+{
+	struct ieee80211req ireq;
 
-		if (wpa & 2) {
-			ireq.i_type = IEEE80211_IOC_RSNCAPS;
-			if (ioctl(s, SIOCG80211, &ireq) != -1) {
-				LINE_CHECK("RSN caps 0x%x", ireq.i_val);
-				spacer = ' ';
-			}
-		}
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+	ireq.i_type = type;
+	ireq.i_len = len;
+	ireq.i_data = data;
+	if (ioctl(s, SIOCG80211, &ireq) < 0)
+		return -1;
+	*plen = ireq.i_len;
+	return 0;
+}
 
-		ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
-		if (ioctl(s, SIOCG80211, &ireq) != -1) {
-		}
-#endif
-		LINE_BREAK();
-	}
-	LINE_BREAK();
+static int
+get80211val(int s, int type, int *val)
+{
+	struct ieee80211req ireq;
 
-end:
-	return;
+	(void) memset(&ireq, 0, sizeof(ireq));
+	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+	ireq.i_type = type;
+	if (ioctl(s, SIOCG80211, &ireq) < 0)
+		return -1;
+	*val = ireq.i_val;
+	return 0;
 }
 
 static void
-set80211(int s, int type, int val, int len, u_int8_t *data)
+set80211(int s, int type, int val, int len, void *data)
 {
 	struct ieee80211req	ireq;
 
@@ -1854,9 +3279,10 @@
 	}
 	len = p - buf;
 	/* The string "-" is treated as the empty string. */
-	if (!hexstr && len == 1 && buf[0] == '-')
+	if (!hexstr && len == 1 && buf[0] == '-') {
 		len = 0;
-	if (len < *lenp)
+		memset(buf, 0, *lenp);
+	} else if (len < *lenp)
 		memset(p, 0, *lenp - len);
 	*lenp = len;
 	return val;
@@ -1946,10 +3372,59 @@
 	DEF_CMD_ARG("mac:kick",		set80211kickmac),
 	DEF_CMD("pureg",	1,	set80211pureg),
 	DEF_CMD("-pureg",	0,	set80211pureg),
+	DEF_CMD("ff",		1,	set80211fastframes),
+	DEF_CMD("-ff",		0,	set80211fastframes),
+	DEF_CMD("dturbo",	1,	set80211dturbo),
+	DEF_CMD("-dturbo",	0,	set80211dturbo),
+	DEF_CMD("bgscan",	1,	set80211bgscan),
+	DEF_CMD("-bgscan",	0,	set80211bgscan),
+	DEF_CMD_ARG("bgscanidle",	set80211bgscanidle),
+	DEF_CMD_ARG("bgscanintvl",	set80211bgscanintvl),
+	DEF_CMD_ARG("scanvalid",	set80211scanvalid),
+	DEF_CMD_ARG("roam:rssi11a",	set80211roamrssi11a),
+	DEF_CMD_ARG("roam:rssi11b",	set80211roamrssi11b),
+	DEF_CMD_ARG("roam:rssi11g",	set80211roamrssi11g),
+	DEF_CMD_ARG("roam:rate11a",	set80211roamrate11a),
+	DEF_CMD_ARG("roam:rate11b",	set80211roamrate11b),
+	DEF_CMD_ARG("roam:rate11g",	set80211roamrate11g),
 	DEF_CMD_ARG("mcastrate",	set80211mcastrate),
 	DEF_CMD_ARG("fragthreshold",	set80211fragthreshold),
 	DEF_CMD("burst",	1,	set80211burst),
 	DEF_CMD("-burst",	0,	set80211burst),
+	DEF_CMD_ARG("bmiss",		set80211bmissthreshold),
+	DEF_CMD_ARG("bmissthreshold",	set80211bmissthreshold),
+	DEF_CMD("shortgi",	1,	set80211shortgi),
+	DEF_CMD("-shortgi",	0,	set80211shortgi),
+	DEF_CMD("ampdurx",	2,	set80211ampdu),
+	DEF_CMD("-ampdurx",	-2,	set80211ampdu),
+	DEF_CMD("ampdutx",	1,	set80211ampdu),
+	DEF_CMD("-ampdutx",	-1,	set80211ampdu),
+	DEF_CMD("ampdu",	3,	set80211ampdu),		/* NB: tx+rx */
+	DEF_CMD("-ampdu",	-3,	set80211ampdu),
+	DEF_CMD_ARG("ampdulimit",	set80211ampdulimit),
+	DEF_CMD_ARG("ampdudensity",	set80211ampdudensity),
+	DEF_CMD("amsdurx",	2,	set80211amsdu),
+	DEF_CMD("-amsdurx",	-2,	set80211amsdu),
+	DEF_CMD("amsdutx",	1,	set80211amsdu),
+	DEF_CMD("-amsdutx",	-1,	set80211amsdu),
+	DEF_CMD("amsdu",	3,	set80211amsdu),		/* NB: tx+rx */
+	DEF_CMD("-amsdu",	-3,	set80211amsdu),
+	DEF_CMD_ARG("amsdulimit",	set80211amsdulimit),
+	DEF_CMD("puren",	1,	set80211puren),
+	DEF_CMD("-puren",	0,	set80211puren),
+	DEF_CMD("doth",		1,	set80211doth),
+	DEF_CMD("-doth",	0,	set80211doth),
+	DEF_CMD("htcompat",	1,	set80211htcompat),
+	DEF_CMD("-htcompat",	0,	set80211htcompat),
+	DEF_CMD("inact",	1,	set80211inact),
+	DEF_CMD("-inact",	0,	set80211inact),
+	DEF_CMD_ARG("htprotmode",	set80211htprotmode),
+	DEF_CMD("ht20",		1,	set80211htconf),
+	DEF_CMD("-ht20",	0,	set80211htconf),
+	DEF_CMD("ht40",		3,	set80211htconf),	/* NB: 20+40 */
+	DEF_CMD("-ht40",	0,	set80211htconf),
+	DEF_CMD("ht",		3,	set80211htconf),	/* NB: 20+40 */
+	DEF_CMD("-ht",		0,	set80211htconf),
 };
 static struct afswtch af_ieee80211 = {
 	.af_name	= "af_ieee80211",


More information about the Midnightbsd-cvs mailing list