Saturday, July 30, 2011

FreeBSD: DFS update

I've spent the last few weeks sorting out the DFS support in FreeBSD. I've made some decent progress with it however there's still a long way to go. This has been paid work and I'm glad to see increasing interest in 802.11 support under FreeBSD.

I've debugged DFS channel switching behaviour in station and access point mode. This now functions correctly in both instances.

The ath driver now behaves "better" when doing a DFS channel change. The driver would change channels and wait for the first beacon to program the beacon timers - which are then used to signal when there's a lack of beacons (and thus net80211 marks the state as "SCAN" and begins hunting for another AP.) If a channel change occured to a channel that required a CAC (clear access check) and a radar event occured, a second channel switch would occur - and there'd never be any beacons on that channel. The NIC would sit there forever waiting to hear a first beacon that never came.

I've updated the FCC3 regulatory domain to include frequency bands that require DFS.

I've also introduced some radar device setup and event parsing code into the ath HAL layer which would allow an interested party to tinker with radar detection/classification code on the AR5212 series NICs. I don't have permission to commit the radar frame decoding code for the 11N NICs - I'm working on this.

Finally, I've introduced a radar detection layer - called "ath_dfs" - which currently does nothing (hence the only module is "dfs_null".) This provides all the hooks needed to do radar detection, classification and signaling.

Now, what I haven't done:
  • The project also includes working porting the radar classification code and getting it to work. This unfortunately won't be open sourced. I'm going to try and get as much of the radar hardware setup and radar event frame parsing code committed to FreeBSD so an interested party can begin tinkering with this.
  • I haven't yet ported a lot of the "channel interference" support. It's there, but I haven't really fleshed it out to be useful and then used it.
  • There's no DFS support for 11N yet - in particular, 11N HT/40 channels aren't correctly marked as "interference" or "radar"; 11N channels also aren't scanned for during DFS channel selection. That's a later project.
  • I need to extend things a bit to handle the weather radar stuff when doing DFS - the ETSI requirements include different channel quiet/scan times.
  • There's no support in net80211 (yet) for the DFS, TPC and Quiet elements. This is going to be required for a fully compliant DFS implementation.
  • I've not investigated implementing/fixing up the DFS support for IBSS and mesh modes.
However, even though there are shortcomings and some missing support in the DFS support, FreeBSD-9.0 will support DFS STA mode well enough to correctly obey instructions from a DFS-compliant access point.

Monday, July 11, 2011

Unintentional side-effects - IPv4/IPv6 load balancing..

Here's a fun one:

1310397101.830 416 X TCP_MISS/200 700 GET adrian DIRECT/[2001:4f8:fff6::22] image/png
1310397101.835 413 X TCP_MISS/200 851 GET adrian DIRECT/ image/png

Since the ipcache code already balances outbound connections between multiple hosts, any IPv6 hosts get similarly load balanced.. between IPv4 hosts as well.

I may end up adding in logic to connect to "only v4" and "only v6" in forward.c...

Lusca update: IPv6 server work is now working

I'm now using the Lusca IPv6 branch for browsing both IPv4 and IPv6 sites.

There's a bunch of little things to update and test, including testing the neighbor selection, peer and ICP code. It's still not yet doing transparent interception or TPROXY - that'll be among the last thing to work on. Finally, there's a bunch of connection timeout handling code which currently is being ignored - there's no convenient place to attach a timeout handler now since the file descriptor isn't created up front; it's created only once the DNS resolution is complete.

My main focus at the moment is testing and verifying the peer, neighbor selection and ICP code out.

But yes, it is actually working!

Thursday, July 7, 2011

Lusca development update - IPv6 is almost working

Now that I've (hopefully!) completely finished with university, I can get back into using my hard-earned money from Xenion to get more Lusca development done. (And yes, I'll also be doing wireless development too, fear not.)

The IPv6 branch is a bit messy at the moment, but it's almost able to handle IPv6 server requests.

The problem? The existing code which handles connecting to remote hosts (ie, src/comm.c) doesn't "know" about IPv6. It assumes all sockets are IPv4 and that all hostnames which are returned are also IPv4.

There's unfortunately a lot of dirty code in there - commReuseFD() is the main culprit and a good example of this. The 30 second version - since the commConnectStart() API assumes the socket is already created before the connect() occurs, any "connect retry" (for multiple hostnames and multiple attempts at the same end-host) requires the socket to be closed and recreated. But the FD has to stay the same. So commReuseFD() manually creates a new FD, makes it look like the old FD, then calls dup2() to get it into the same FD as the old one.

The "Correct" Fix is to modify the API to not take an FD, but to return an FD on successful connect() to the remote destination. There's some problems with this though, most notably in the request forwarding layer where the FD is created and comm close handlers are assigned before the connection is attempted. I need to make sure that there's no code which calls comm_close() on the active connection whilst connect() is going on - as said code expects the FD to be valid and assigned by this point.

The "Dirty" fix is to modify commConnectStart() and commReuseFD() to check the FD address family and destroy/create a "new" socket with the correct address family.

The "Problem" is that the code allows the outgoing address to be specified, both for transparent interception (source address spoofing) and to be set via an ACL match. Since IPv4 and IPv6 addresses are now possible, the API will have to be modified to handle this case.

What I'm likely going to do is something inspired by Squid-3. I'll teach the forwarding layer about "try v4 destinations" and "try v6 destinations". The administrator can then configure whether to try v4 or v6 destinations first. Only one outgoing address has to be provided - either "v4" or "v6"; and commConnectStart() will only try connecting to IP addresses that match the family of the outgoing address. That way if a host resolves to a mix of v4 and v6 addresses, they'll be tried in a "v4" group, then a "v6" group (or vice versa.) It's a bit dirty, but it's likely doable in the short-term.

In the long term, I'd like to fix the API up to be less messy and return an FD, rather than take an existing FD and abuse that. But that can come later.