qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Re: Re: Re: Atheros Wireless Device Emulation


From: Clemens Kolbitsch
Subject: [Qemu-devel] Re: Re: Re: Atheros Wireless Device Emulation
Date: Tue, 18 Mar 2008 09:04:56 +0100
User-agent: KMail/1.9.6 (enterprise 0.20070907.709405)

Patch #4:

Virtual access point code. It is based on a message queue and a timer that 
repeatedly injects the ingoing messages and replies into the queue. Outgoing 
messages are parsed to extract the IP-datagram from the wireless packet and 
passed on to Qemu.

There are 3 important functions here:
 - Atheros_WLAN_handle_frame, is the AP state machine. Really simplified but 
sufficient ;-)

 - Atheros_WLAN_handleRxBuffer, inject a packet into the guest driver

 - Atheros_WLAN_handleTxBuffer, extract a packet from the guest driver



diff -Naur qemu/hw/atheros_wlan_ap.c qemu-altered/hw/atheros_wlan_ap.c
--- qemu/hw/atheros_wlan_ap.c   1970-01-01 01:00:00.000000000 +0100
+++ qemu-altered/hw/atheros_wlan_ap.c   2008-03-01 12:33:11.000000000 +0100
@@ -0,0 +1,771 @@
+/**
+ * QEMU WLAN access point emulation
+ * 
+ * Copyright (c) 2008 Clemens Kolbitsch
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a 
copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the 
rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Modifications:
+ *  2008-February-24  Clemens Kolbitsch :
+ *                                  New implementation based on ne2000.c
+ *
+ */
+
+
+#include "hw.h"
+#include "pci.h"
+#include "pc.h"
+#include "net.h"
+#include "qemu-timer.h"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <signal.h>
+
+#include <time.h>
+#include <sys/time.h>
+
+/*
+ * PCI and EEPROM definitions
+ */
+#include "hw/atheros_wlan.h"
+#include "hw/atheros_wlan_ap.h"
+#include "hw/atheros_wlan_io.h"
+#include "hw/atheros_wlan_packet.h"
+
+/*
+ * MadWifi OPENHAL atheros constants
+ */
+#include "hw/ath5k_hw.h"
+#include "hw/ath5kreg.h"
+#include "hw/ath5k.h"
+
+static int semaphore_helper(int semaphore, int sem_op, int semaphore_nr, 
short flags)
+{
+       struct sembuf semp;
+       semp.sem_num = semaphore_nr;
+       semp.sem_op = sem_op;
+       semp.sem_flg = flags;
+
+       if (semaphore == -1)
+       {
+               /*
+                * We don't have a semaphore... probably not
+                * that bad, but having one is better :-)
+                */
+               return -1;
+       }
+
+       int ret;
+       while ((ret = semop(semaphore, &semp, 1)) < 0)
+       {
+               if (errno == EAGAIN && flags == IPC_NOWAIT)
+               {
+                       return errno;
+               }
+               else if (errno != EINTR)
+               {
+                       fprintf(stderr, "Semaphore error: 0x%x / %u\n", errno, 
errno);
+                       return errno;
+               }
+       }
+
+       return ret;
+}
+
+
+static int signal_semaphore(int semaphore, int semaphore_nr)
+{
+       return semaphore_helper(semaphore, 1, semaphore_nr, 0);
+}
+static int wait_semaphore(int semaphore, int semaphore_nr)
+{
+       return semaphore_helper(semaphore, -1, semaphore_nr, 0);
+}
+
+void Atheros_WLAN_insert_frame(Atheros_WLANState *s, struct mac80211_frame 
*frame)
+{
+       struct mac80211_frame *i_frame;
+
+       wait_semaphore(s->access_semaphore, 0);
+
+       s->inject_queue_size++;
+       i_frame = s->inject_queue;
+       if (!i_frame)
+       {
+               s->inject_queue = frame;
+       }
+       else
+       {
+               while (i_frame->next_frame)
+               {
+                       i_frame = i_frame->next_frame;
+               }
+
+               i_frame->next_frame = frame;
+       }
+
+       if (!s->inject_timer_running)
+       {
+               // if the injection timer is not
+               // running currently, let's schedule
+               // one run...
+               s->inject_timer_running = 1;
+               qemu_mod_timer(s->inject_timer, qemu_get_clock(rt_clock) + 5);
+       }
+
+       signal_semaphore(s->access_semaphore, 0);
+}
+
+static void Atheros_WLAN_beacon_timer(void *opaque)
+{
+       struct mac80211_frame *frame;
+       Atheros_WLANState *s = (Atheros_WLANState *)opaque;
+
+       frame = Atheros_WLAN_create_beacon_frame();
+       if (frame)
+       {
+               Atheros_WLAN_init_frame(s, frame);
+               Atheros_WLAN_insert_frame(s, frame);
+       }
+
+       qemu_mod_timer(s->beacon_timer, qemu_get_clock(rt_clock) + 500);
+}
+
+static void Atheros_WLAN_inject_timer(void *opaque)
+{
+       Atheros_WLANState *s = (Atheros_WLANState *)opaque;
+       struct mac80211_frame *frame;
+
+       wait_semaphore(s->access_semaphore, 0);
+
+       frame = s->inject_queue;
+       if (frame)
+       {
+               // remove from queue
+               s->inject_queue_size--;
+               s->inject_queue = frame->next_frame;
+       }
+       signal_semaphore(s->access_semaphore, 0);
+
+       if (!frame)
+       {
+               goto timer_done;
+       }
+
+       if (s->receive_queue_address == NULL)
+       {
+               // we drop the packet
+       }
+       else
+       {
+               Atheros_WLAN_handleRxBuffer(s, frame, frame->frame_length);
+       }
+
+       free(frame);
+
+timer_done:
+       wait_semaphore(s->access_semaphore, 0);
+
+       if (s->inject_queue_size > 0)
+       {
+               // there are more packets... schedule
+               // the timer for sending them as well
+               qemu_mod_timer(s->inject_timer, qemu_get_clock(rt_clock) + 25);
+       }
+       else
+       {
+               // we wait until a new packet schedules
+               // us again
+               s->inject_timer_running = 0;
+       }
+
+       signal_semaphore(s->access_semaphore, 0);
+}
+
+
+static int Atheros_WLAN_can_receive(void *opaque)
+{
+       Atheros_WLANState *s = (Atheros_WLANState *)opaque;
+
+       if (s->ap_state != Atheros_WLAN__STATE_ASSOCIATED)
+       {
+               // we are currently not connected
+               // to the access point
+               return 0;
+       }
+
+       if (s->inject_queue_size > Atheros_WLAN__MAX_INJECT_QUEUE_SIZE)
+       {
+               // overload, please give me some time...
+               return 0;
+       }
+
+       return 1;
+}
+
+static void Atheros_WLAN_receive(void *opaque, const uint8_t *buf, int size)
+{
+       struct mac80211_frame *frame;
+       Atheros_WLANState *s = (Atheros_WLANState *)opaque;
+
+       if (!Atheros_WLAN_can_receive(opaque))
+       {
+               // this should not happen, but in
+               // case it does, let's simply drop
+               // the packet
+               return;
+       }
+
+       if (!s)
+       {
+               return;
+       }
+
+       /*
+        * A 802.3 packet comes from the qemu network. The
+        * access points turns it into a 802.11 frame and
+        * forwards it to the wireless device
+        */
+       frame = Atheros_WLAN_create_data_packet(s, buf, size);
+       if (frame)
+       {
+               Atheros_WLAN_init_frame(s, frame);
+               Atheros_WLAN_insert_frame(s, frame);
+       }
+}
+
+void Atheros_WLAN_setup_ap(NICInfo *nd, PCIAtheros_WLANState *d)
+{
+       Atheros_WLANState *s;
+       s = &d->Atheros_WLAN;
+
+       s->ap_state = Atheros_WLAN__STATE_NOT_AUTHENTICATED;
+       s->ap_macaddr[0] = 0x00;
+       s->ap_macaddr[1] = 0x13;
+       s->ap_macaddr[2] = 0x46;
+       s->ap_macaddr[3] = 0xbf;
+       s->ap_macaddr[4] = 0x31;
+       s->ap_macaddr[5] = 0x59;
+
+       s->inject_timer_running = 0;
+       s->inject_sequence_number = 0;
+
+       s->inject_queue = NULL;
+       s->inject_queue_size = 0;
+
+       s->access_semaphore = semget(ATHEROS_WLAN_ACCESS_SEM_KEY, 1, 0666 | 
IPC_CREAT);
+       semctl(s->access_semaphore, 0, SETVAL, 1);
+
+       s->beacon_timer = qemu_new_timer(rt_clock, Atheros_WLAN_beacon_timer, 
s);
+       qemu_mod_timer(s->beacon_timer, qemu_get_clock(rt_clock));
+
+       // setup the timer but only schedule
+       // it when necessary...
+       s->inject_timer = qemu_new_timer(rt_clock, Atheros_WLAN_inject_timer, 
s);
+
+       s->vc = qemu_new_vlan_client(nd->vlan, Atheros_WLAN_receive, 
Atheros_WLAN_can_receive, s);
+
+       snprintf(s->vc->info_str, sizeof(s->vc->info_str), "atheros wireless 
lan 
(macaddr=%02x:%02x:%02x:%02x:%02x:%02x)",
+                       s->macaddr[0], s->macaddr[1], s->macaddr[2],
+                       s->macaddr[3], s->macaddr[4], s->macaddr[5]);
+}
+
+
+
+void Atheros_WLAN_disable_irq(void *arg)
+{
+       Atheros_WLANState *s = (Atheros_WLANState *)arg;
+       SET_MEM_L(s->mem, ATH_HW_IRQ_PENDING, ATH_HW_IRQ_PENDING_FALSE);
+       qemu_set_irq(s->irq, 0);
+       DEBUG_PRINT((">> Disabling irq\n"));
+}
+
+void Atheros_WLAN_enable_irq(void *arg)
+{
+       Atheros_WLANState *s = (Atheros_WLANState *)arg;
+
+       if (!s->interrupt_enabled)
+       {
+               DEBUG_PRINT((">> Wanted to enable irq, but they are 
disabled\n"));
+               Atheros_WLAN_disable_irq(s);
+               return;
+       }
+
+       DEBUG_PRINT((">> Enabling irq\n"));
+       SET_MEM_L(s->mem, ATH_HW_IRQ_PENDING, ATH_HW_IRQ_PENDING_TRUE);
+       qemu_set_irq(s->irq, 1);
+}
+
+
+void Atheros_WLAN_update_irq(void *arg)
+{
+       Atheros_WLANState *s = (Atheros_WLANState *)arg;
+       DEBUG_PRINT((">> Updating... irq-enabled is %u\n", 
s->interrupt_enabled));
+       /*
+        * NOTE: Since we use shared interrupts
+        * the device driver will check if the
+        * interrupt really comes from this hardware
+        *
+        * This is done by checking the
+        * ATH_HW_IRQ_PENDING memory...
+        */
+       if (/*(!s->interrupt_enabled) ||*/
+           (s->pending_interrupts == NULL))
+       {
+               SET_MEM_L(s->mem, AR5K_RAC_PISR, 0);
+               goto disable_further_interrupts;
+       }
+
+       /*
+        * Make sure this is done atomically!!
+        */
+       wait_semaphore(s->access_semaphore, 0);
+       uint32_t status = 0x0;
+       struct pending_interrupt *i = s->pending_interrupts;
+       struct pending_interrupt *next;
+
+       s->pending_interrupts = NULL;
+       while (i != NULL)
+       {
+               next = i->next;
+               if (1) //(s->interrupt_p_mask & i->status)
+               {
+                       status |= i->status;
+               }
+               free(i);
+
+               i = next;
+       }
+
+       SET_MEM_L(s->mem, AR5K_RAC_PISR, status);
+       DEBUG_PRINT((">> Status set to %u\n", status));
+       /*
+        * Atomic part done...
+        */
+       signal_semaphore(s->access_semaphore, 0);
+
+
+disable_further_interrupts:
+       /*
+        * NOTE: At last, it will check if any
+        * more interrupts are pending. The call
+        * to check what type of interrupt was
+        * pending already put down the interrupt_pending
+        * bit for us (check the readl function for RAC)
+        *
+        * if_ath.c: 921
+        */
+       Atheros_WLAN_disable_irq(s);
+}
+
+
+void Atheros_WLAN_append_irq(Atheros_WLANState *s, struct pending_interrupt 
intr)
+{
+       struct pending_interrupt *new_intr;
+       new_intr = (struct pending_interrupt *)malloc(sizeof(struct 
pending_interrupt));
+       memcpy(new_intr, &intr, sizeof(intr));
+
+       /*
+        * Make sure this is done atomically!!
+        */
+       wait_semaphore(s->access_semaphore, 0);
+
+       if (s->pending_interrupts == NULL)
+       {
+               s->pending_interrupts = new_intr;
+       }
+       else
+       {
+               /*
+                * Insert at the end of the
+                * list to assure correct order
+                * of interrupts!
+                */
+               struct pending_interrupt *i = s->pending_interrupts;
+               while (i->next != NULL)
+               {
+                       i = i->next;
+               }
+
+               new_intr->next = NULL;
+               i->next = new_intr;
+       }
+
+       /*
+        * Atomic part done...
+        */
+       signal_semaphore(s->access_semaphore, 0);
+}
+
+
+
+
+
+
+
+
+void Atheros_WLAN_handleRxBuffer(Atheros_WLANState *s, struct mac80211_frame 
*frame, uint32_t frame_length)
+{
+       struct ath_desc desc;
+       struct ath5k_ar5212_rx_status *rx_status;
+       rx_status = (struct ath5k_ar5212_rx_status*)&desc.ds_hw[0];
+
+       if (s->receive_queue_address == NULL)
+       {
+               return;
+       }
+
+       cpu_physical_memory_read((target_phys_addr_t)s->receive_queue_address, 
(uint8_t*)&desc, sizeof(desc));
+
+       /*
+        * Put some good base-data into
+        * the descriptor. Length & co
+        * will be modified below...
+        *
+        * NOTE: Better set everything correctly
+        *
+        * Look at ath5k_hw.c: proc_tx_desc
+        */
+       desc.ds_ctl0 = 0x0;
+       desc.ds_ctl1 = 0x9c0;
+       desc.ds_hw[0] = 0x126d806a;
+       desc.ds_hw[1] = 0x49860003;
+       desc.ds_hw[2] = 0x0;
+       desc.ds_hw[3] = 0x0;
+
+
+       /*
+        * Filter out old length and put in correct value...
+        */
+       rx_status->rx_status_0 &= ~AR5K_AR5212_DESC_RX_STATUS0_DATA_LEN;
+       rx_status->rx_status_0 |= frame_length;
+       rx_status->rx_status_0 &= ~AR5K_AR5211_DESC_RX_STATUS0_MORE;
+
+       /*
+        * Write descriptor and packet back to DMA memory...
+        */
+       cpu_physical_memory_write((target_phys_addr_t)s->receive_queue_address, 
(uint8_t*)&desc, sizeof(desc));
+       cpu_physical_memory_write((target_phys_addr_t)desc.ds_data, 
(uint8_t*)frame, 
sizeof(struct mac80211_frame));
+       
+       /*
+        * Set address to next position
+        * in single-linked list
+        *
+        * The receive list's last element
+        * points to itself to avoid overruns.
+        * This way, at some point no more
+        * packets will be received, but (I
+        * ASSUME) that it is the drivers
+        * responsibility to reset the address
+        * list!
+        *
+        *
+        * NOTE: It seems the real madwifi cannot
+        * handle multiple packets at once. so we
+        * set the buffer to NULL to make the injection
+        * fail next time until an interrupt was
+        * received by the driver and a new buffer
+        * is registered!!
+        */
+       s->receive_queue_address =
+               ((++s->receive_queue_count) > MAX_CONCURRENT_RX_FRAMES)
+                       ? NULL 
+                       : (uint32_t *)desc.ds_link;
+
+
+       DEBUG_PRINT((">> Enabling rx\n"));
+       /*
+        * Notify the driver about the new packet
+        */
+       struct pending_interrupt intr;
+       intr.status = AR5K_INT_RX;
+       Atheros_WLAN_append_irq(s, intr);
+       Atheros_WLAN_enable_irq(s);
+}
+
+
+
+void Atheros_WLAN_handleTxBuffer(Atheros_WLANState *s, uint32_t queue)
+{
+       struct ath_desc desc;
+       struct mac80211_frame frame;
+
+       if (s->transmit_queue_address[queue] == NULL)
+       {
+               return;
+       }
+
+       
cpu_physical_memory_read((target_phys_addr_t)s->transmit_queue_address[queue], 
(uint8_t*)&desc, sizeof(desc));
+
+       if (s->transmit_queue_processed[queue])
+       {
+               /*
+                * Maybe we already processed the frame
+                * and have not gotten the address of the
+                * next frame buffer but still got a call
+                * to send the next frame
+                *
+                * this way we have to process the next
+                * frame in the single linked list!!
+                */
+               s->transmit_queue_address[queue] = (uint32_t *)desc.ds_link;
+
+               /*
+                * And now get the frame we really have to process...
+                */
+               
cpu_physical_memory_read((target_phys_addr_t)s->transmit_queue_address[queue], 
(uint8_t*)&desc, sizeof(desc));
+       }
+
+       uint32_t segment_len, frame_length = 0, more;
+       uint8_t *frame_pos = (uint8_t*)&frame;
+       struct ath5k_ar5212_tx_desc *tx_desc;
+       tx_desc = (struct ath5k_ar5212_tx_desc*)&desc.ds_ctl0;
+       do
+       {
+               more = tx_desc->tx_control_1 & AR5K_AR5211_DESC_TX_CTL1_MORE;
+               segment_len = tx_desc->tx_control_1 & 
AR5K_AR5212_DESC_TX_CTL1_BUF_LEN;
+
+               cpu_physical_memory_read((target_phys_addr_t)desc.ds_data, 
frame_pos, 
segment_len);
+               frame_pos += segment_len;
+               frame_length += segment_len;
+
+
+               /*
+                * Notify successful transmission
+                *
+                * NOTE: It'd be better to leave the
+                * descriptor as it is and only modify
+                * the transmit-ok-bits --> this way
+                * the timestamp and co. would stay
+                * valid...
+                *
+                * Look at ath5k_hw.c: proc_tx_desc
+                *
+                * NOTE: Not sure if this acknowledgement
+                * must be copied back for every single
+                * descriptor in a multi-segment frame,
+                * but better safe than sorry!!
+                */
+               desc.ds_ctl0 = 0x213f002f;
+               desc.ds_ctl1 = 0x2b;
+               desc.ds_hw[0] = 0xf0000;
+               desc.ds_hw[1] = 0x1b;
+               desc.ds_hw[2] = 0xab640001;
+               desc.ds_hw[3] = 0x4a019;
+       
+               /*
+                *
+                * struct ath5k_tx_status *tx_status = (struct 
ath5k_tx_status*)&desc.ds_hw[2];
+                * tx_status->tx_status_1 |= AR5K_DESC_TX_STATUS1_DONE;
+                * tx_status->tx_status_0 |= AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK;
+                *
+                *
+                * Write descriptor back to DMA memory...
+                */
+               
cpu_physical_memory_write((target_phys_addr_t)s->transmit_queue_address[queue], 
(uint8_t*)&desc, sizeof(desc));
+
+               if (more && frame_length < sizeof(frame))
+               {
+                       /*
+                        * This is done at the end of the loop
+                        * since sometimes the next-link is not
+                        * yet set (assuming frame is a 1-segment
+                        * frame)!!
+                        *
+                        * This is very strange (and maybe obsolete
+                        * by this version) but let's do it the safe
+                        * way and not mess it up :-)
+                        */
+                       s->transmit_queue_address[queue] = (uint32_t 
*)desc.ds_link;
+                       
cpu_physical_memory_read((target_phys_addr_t)s->transmit_queue_address[queue], 
(uint8_t*)&desc, sizeof(desc));
+               }
+       }
+       while (more && frame_length < sizeof(frame));
+
+
+       struct pending_interrupt intr;
+       intr.status = AR5K_INT_TX;
+       Atheros_WLAN_append_irq(s, intr);
+       Atheros_WLAN_enable_irq(s);
+
+       /*
+        * Set address to next position
+        * in single-linked list
+        *
+        * The transmit list's last element
+        * points to itself to avoid overruns.
+        * This way, at some point no more
+        * packets will be received, but (I
+        * ASSUME) that it is the drivers
+        * responsibility to reset the address
+        * list!
+        */
+       s->transmit_queue_processed[queue] = 1;
+
+       frame.frame_length = frame_length + 4;
+       Atheros_WLAN_handle_frame(s, &frame);
+}
+
+
+void Atheros_WLAN_handle_frame(Atheros_WLANState *s, struct mac80211_frame 
*frame)
+{
+       struct mac80211_frame *reply = NULL;
+       unsigned long ethernet_frame_size;
+       unsigned char ethernet_frame[1518];
+
+       if ((frame->frame_control.type == IEEE80211_TYPE_MGT) &&
+           (frame->frame_control.sub_type == 
IEEE80211_TYPE_MGT_SUBTYPE_PROBE_REQ))
+       {
+               reply = Atheros_WLAN_create_probe_response();
+       }
+       else if ((frame->frame_control.type == IEEE80211_TYPE_MGT) &&
+                (frame->frame_control.sub_type == 
IEEE80211_TYPE_MGT_SUBTYPE_AUTHENTICATION))
+       {
+               DEBUG_PRINT_AP(("Received authentication!\n"));
+               reply = Atheros_WLAN_create_authentication();
+
+               if (s->ap_state == Atheros_WLAN__STATE_NOT_AUTHENTICATED)
+               {
+                       // if everything is going according to
+                       // the state machine, let's jump into the
+                       // next state
+                       s->ap_state = Atheros_WLAN__STATE_AUTHENTICATED;
+               }
+       }
+       else if ((frame->frame_control.type == IEEE80211_TYPE_MGT) &&
+                (frame->frame_control.sub_type == 
IEEE80211_TYPE_MGT_SUBTYPE_DEAUTHENTICATION))
+       {
+               DEBUG_PRINT_AP(("Received deauthentication!\n"));
+               reply = Atheros_WLAN_create_deauthentication();
+
+               // some systems (e.g. WinXP) won't send a
+               // disassociation. just believe that the
+               // deauthentication is ok... nothing bad
+               // can happen anyways ;-)
+               s->ap_state = Atheros_WLAN__STATE_NOT_AUTHENTICATED;
+       }
+       else if ((frame->frame_control.type == IEEE80211_TYPE_MGT) &&
+                (frame->frame_control.sub_type == 
IEEE80211_TYPE_MGT_SUBTYPE_ASSOCIATION_REQ))
+       {
+               DEBUG_PRINT_AP(("Received association request!\n"));
+               reply = Atheros_WLAN_create_association_response();
+
+               if (s->ap_state == Atheros_WLAN__STATE_AUTHENTICATED)
+               {
+                       // if everything is going according to
+                       // the state machine, let's jump into the
+                       // next state
+                       s->ap_state = Atheros_WLAN__STATE_ASSOCIATED;
+               }
+       }
+       else if ((frame->frame_control.type == IEEE80211_TYPE_MGT) &&
+                (frame->frame_control.sub_type == 
IEEE80211_TYPE_MGT_SUBTYPE_DISASSOCIATION))
+       {
+               DEBUG_PRINT_AP(("Received disassociation!\n"));
+               reply = Atheros_WLAN_create_disassociation();
+
+               if (s->ap_state == Atheros_WLAN__STATE_ASSOCIATED)
+               {
+                       // if everything is going according to
+                       // the state machine, let's jump into the
+                       // next state
+                       s->ap_state = Atheros_WLAN__STATE_AUTHENTICATED;
+               }
+       }
+       else if ((frame->frame_control.type == IEEE80211_TYPE_DATA) &&
+                (s->ap_state == Atheros_WLAN__STATE_ASSOCIATED))
+       {
+               /*
+                * The access point uses the 802.11 frame
+                * and sends a 802.3 frame into the network...
+                * This packet is then understandable by
+                * qemu-slirp
+                *
+                * If we ever want the access point to offer
+                * some services, it can be added here!!
+                */
+               // ethernet header type
+               ethernet_frame[12] = frame->data_and_fcs[6];
+               ethernet_frame[13] = frame->data_and_fcs[7];
+
+               // the new originator of the packet is
+               // the access point
+               memcpy(&ethernet_frame[6], s->ap_macaddr, 6);
+
+               if (ethernet_frame[12] == 0x08 && ethernet_frame[13] == 0x06)
+               {
+                       // for arp request, we use a broadcast
+                       memset(&ethernet_frame[0], 0xff, 6);
+               }
+               else
+               {
+                       // otherwise we forward the packet to
+                       // where it really belongs
+                       memcpy(&ethernet_frame[0], frame->destination_address, 
6);
+               }
+
+               // add packet content
+               ethernet_frame_size = frame->frame_length - 24 - 4 - 8;
+
+               // for some reason, the packet is 22 bytes too small (??)
+               ethernet_frame_size += 22;
+               if (ethernet_frame_size > sizeof(ethernet_frame))
+               {
+                       ethernet_frame_size = sizeof(ethernet_frame);
+               }
+               memcpy(&ethernet_frame[14], &frame->data_and_fcs[8], 
ethernet_frame_size);
+
+               // add size of ethernet header
+               ethernet_frame_size += 14;
+
+               /*
+                * Send 802.3 frame
+                */
+               qemu_send_packet(s->vc, ethernet_frame, ethernet_frame_size);
+       }
+
+       if (reply)
+       {
+               memcpy(reply->destination_address, frame->source_address, 6);
+               Atheros_WLAN_init_frame(s, reply);
+               Atheros_WLAN_insert_frame(s, reply);
+       }
+}
+
+
+
+
+
+
+
diff -Naur qemu/hw/atheros_wlan_ap.h qemu-altered/hw/atheros_wlan_ap.h
--- qemu/hw/atheros_wlan_ap.h   1970-01-01 01:00:00.000000000 +0100
+++ qemu-altered/hw/atheros_wlan_ap.h   2008-03-01 12:33:11.000000000 +0100
@@ -0,0 +1,47 @@
+/**
+ * QEMU WLAN access point emulation
+ * 
+ * Copyright (c) 2008 Clemens Kolbitsch
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a 
copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the 
rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Modifications:
+ *  2008-February-24  Clemens Kolbitsch :
+ *                                  New implementation based on ne2000.c
+ *
+ */
+
+#ifndef atheros_wlan_ap_h
+#define atheros_wlan_ap_h 1
+
+void Atheros_WLAN_setup_ap(NICInfo *nd, PCIAtheros_WLANState *d);
+
+void Atheros_WLAN_handleTxBuffer(Atheros_WLANState *s, uint32_t queue);
+void Atheros_WLAN_handleRxBuffer(Atheros_WLANState *s, struct mac80211_frame 
*frame, uint32_t frame_length);
+
+void Atheros_WLAN_handle_frame(Atheros_WLANState *s, struct mac80211_frame 
*frame);
+
+void Atheros_WLAN_insert_frame(Atheros_WLANState *s, struct mac80211_frame 
*frame);
+
+void Atheros_WLAN_disable_irq(void *arg);
+void Atheros_WLAN_enable_irq(void *arg);
+void Atheros_WLAN_update_irq(void *arg);
+void Atheros_WLAN_append_irq(Atheros_WLANState *s, struct pending_interrupt 
intr);
+
+#endif // atheros_wlan_ap_h








reply via email to

[Prev in Thread] Current Thread [Next in Thread]