Broadcom IOCTLs on OSX

I figured out how to call all the nice ioctls the Broadcom linux driver provides (for linksys APs, cf. http://openwrt.org/) under OS X. This is possible since they use one driver source for everything.

This is based on the code found at http://www.macstumbler.com/airport.tar.gz

You can call arbitrary IOCTLs with this. What they do and what parameters they expect you'll need to figure out yourself.

The wlioctl.h file might give you a hint on what parameters each call expects, I have a list of implemented commands.

The airport.m tool as given must be called when Airport is turned OFF and will perform a loopback test, returning with an error if it fails.

First of all, add this to Apple80211.h

extern WIErr WirelessPrivate(
        WirelessContextPtr inContext,
        void* in_ptr,
        int in_bytes,
        void* out_ptr,
        int out_bytes);

It's the private command call. You can do lots more with it, but I'll leave it at calling the ioctls.

Next, find wlioctl.h, for example from http://files.wl500g.info/asus/wl500g/gpl/broadcom/src/include/wlioctl.h.

And finally, here's airport.m, based on the code from http://www.macstumbler.com/airport.tar.gz It's not clean at all. But you can make it so :)

#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/Foundation.h>
#include <stdio.h>

#include "Apple80211.h"

/* you'll need to strip that file down as it doesn't compile as-is */
#include "wlioctl.h"

WirelessContextPtr gWCtxt = NULL;
char *gProgname;

WIErr
wlDetach(void)
{
  WIErr err = 0;

  if(gWCtxt != NULL) {
    err = WirelessDetach(gWCtxt);
    if(err) fprintf(stderr, "Error: WirelessDetach: %d\n", (int) err);
  }

  return err;
}

void
wlCheckAvail(int avail)
{
  if(avail)
    return;

  fprintf(stderr, "%s: Error: Wireless interface not available!\n",
          gProgname);

  exit(-2);
}

WIErr
wlc_ioctl(int command, int bufsize, void* buffer, int outsize, void* out) {
        if (!buffer) bufsize = 0;
        int* buf = malloc(bufsize+8);
        buf[0] = 3; /* private ioctl command code */
        buf[1] = command;
        if (bufsize && buffer)
                memcpy(&buf[2], buffer, bufsize);
        return WirelessPrivate(gWCtxt, buf, bufsize+8, out, outsize);
}

int
main(int argc, char **argv)
{
  WIErr err = 0;
  NSAutoreleasePool *pool;
  int retVal = 0;
  int avail = 0;

  gProgname = argv[0];

  pool = [[NSAutoreleasePool alloc] init];

  avail = WirelessIsAvailable();

  if(avail) {
    err = WirelessAttach(&gWCtxt, 0);
    if(err) {
      fprintf(stderr, "Error: WirelessAttach: %d\n", (int) err);
      exit(-1);
    }
  }
  wlCheckAvail(avail);

  int cookie, tmp;
  if (wlc_ioctl(WLC_GET_MAGIC, 0, NULL, 4, &cookie)) {
        fprintf(stderr, "%s: Error: %d\n", gProgname, (int) err);
    wlDetach();
        return -1;
  }

  if (cookie != 0x14e46c77) {
    fprintf(stderr, "cookie mismatch\n");
        wlDetach();
        return -1;
  }

  tmp = 1;
  wlc_ioctl(WLC_SET_CLK, 4, &tmp, 0, NULL);
  err = wlc_ioctl(WLC_DIAG_LOOPBACK, 4, &tmp, 0, NULL);
  tmp = 0;
  wlc_ioctl(WLC_SET_CLK, 4, &tmp, 0, NULL);

  if(err != noErr) {
    fprintf(stderr, "%s: Error: %d\n", gProgname, (int) err);
    retVal = -1;
  }

  wlDetach();

  return retVal;
}

For a Makefile, copy the one from airport.tar.gz and remove all the hermes stuff.