summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordmlb <dmlb@FreeBSD.org>2000-05-21 21:20:18 +0000
committerdmlb <dmlb@FreeBSD.org>2000-05-21 21:20:18 +0000
commit82793e31dc89b5afc9b2b0723f8f4ce0ea3bcbf1 (patch)
tree11b0d904b73c5adb1575d907e7448bbe18f99dc7
parent1927bea4073fb4851d843e2b55c1f0853b3cff1f (diff)
downloadFreeBSD-src-82793e31dc89b5afc9b2b0723f8f4ce0ea3bcbf1.zip
FreeBSD-src-82793e31dc89b5afc9b2b0723f8f4ce0ea3bcbf1.tar.gz
MFRELENG_3
-rw-r--r--sys/dev/ray/if_ray.c812
1 files changed, 625 insertions, 187 deletions
diff --git a/sys/dev/ray/if_ray.c b/sys/dev/ray/if_ray.c
index 7e6544c..b018aef 100644
--- a/sys/dev/ray/if_ray.c
+++ b/sys/dev/ray/if_ray.c
@@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: if_ray.c,v 1.24 2000/04/24 15:49:20 dmlb Exp $
+ * $Id: if_ray.c,v 1.29 2000/05/11 18:55:38 dmlb Exp $
*
*/
@@ -106,7 +106,7 @@
* power saving etc. is easy.
*
*
- * Packet translation/encapsulation
+ * Packet framing/encapsulation
* ================================
*
* Currently we only support the Webgear encapsulation
@@ -121,7 +121,7 @@
* rayctl.c Linux Webgear, RFC1042
* also whatever we can divine from the NDC Access points and Kanda's boxes.
*
- * Most drivers appear to have a RFC1042 translation. The incoming packet is
+ * Most drivers appear to have a RFC1042 framing. The incoming packet is
* 802.11 header <net/if_ieee80211.h>struct ieee80211_header
* 802.2 LLC header
* 802.2 SNAP header
@@ -131,11 +131,26 @@
* 802.2 LLC header
* 802.2 SNAP header
*
- * Linux seems to look at the SNAP org_code and do some translations
+ * Linux seems to look at the SNAP org_code and do some framings
* for IPX and APPLEARP on that. This just may be how Linux does IPX
* and NETATALK. Need to see how FreeBSD does these.
*
* Translation should be selected via if_media stuff or link types.
+ *
+ *
+ * Authentication
+ * ==============
+ *
+ * 802.11 provides two authentication mechanisms. The first is a very
+ * simple host based mechanism (like xhost) called Open System and the
+ * second is a more complex challenge/response called Shared Key built
+ * ontop of WEP.
+ *
+ * This driver only supports Open System and does not implement any
+ * host based control lists. In otherwords authentication is always
+ * granted to hosts wanting to authenticate with this station. This is
+ * the only sensible behaviour as the Open System mechanism uses MAC
+ * addresses to identify hosts. Send me patches if you need it!
*/
/*
@@ -204,6 +219,9 @@
* the rest is ansi anyway
* macroize the attribute read/write and 3.x driver - done
* like the SRAM macros?
+ * rename "translation" to framing for consitency with Webgear - done
+ * severe breakage with CCS allocation - done
+ * ccs are now allocated in a sleepable context with error recovery
*
* ***stop/unload needs to drain comq
* ***stop/unload checks in more routines
@@ -214,6 +232,9 @@
* ***check and rationalise CM mappings
* ***should the desired nw parameters move into the comq entry to maintain
* correct sequencing?
+ * resource allocation should be be in attach and not probe
+ * resources allocated in probe hould be released before probe exits
+ * use /sys/net/if_ieee80211.h and update it
* why can't download use sc_promisc?
* macro for gone and check is at head of all externally called routines
* for ALLMULTI must go into PROMISC and filter unicast packets
@@ -234,6 +255,7 @@
* infrastructure mode
* needs handling of basic rate set
* all ray_sj, ray_assoc sequencues need a "nicer" solution as we
+ * remember association and authentication
* need to consider WEP
* acting as ap - should be able to get working from the manual
* differeniate between parameters set in attach and init
@@ -251,13 +273,15 @@
#define XXX 0
#define XXX_CLEARCCS_IN_INIT 0
#define XXX_ASSOC 0
+#define XXX_ACTING_AP 0
+#define XXX_INFRA 0
#define XXX_MCAST 0
#define XXX_RESET 0
#define XXX_IFQ_PEEK 0
#define RAY_DEBUG ( \
- /* RAY_DBG_RECERR | */ \
+ RAY_DBG_RECERR | \
/* RAY_DBG_SUBR | */ \
- RAY_DBG_BOOTPARAM | \
+ /* RAY_DBG_BOOTPARAM | */ \
/* RAY_DBG_STARTJOIN | */ \
/* RAY_DBG_CCS | */ \
/* RAY_DBG_IOCTL | */ \
@@ -266,6 +290,9 @@
/* RAY_DBG_CM | */ \
/* RAY_DBG_COM | */ \
/* RAY_DBG_STOP | */ \
+ /* RAY_DBG_CTL | */ \
+ /* RAY_DBG_MGT | */ \
+ /* RAY_DBG_TX | */ \
0 \
)
@@ -286,6 +313,7 @@
#endif /* RAY_DEBUG */
#include "ray.h"
+#include "opt_inet.h"
#if NRAY > 0
@@ -313,6 +341,13 @@
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_mib.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/if_ether.h>
+#endif /* INET */
+
#include <net/bpf.h>
#include <machine/bus.h>
@@ -337,8 +372,10 @@
* Prototyping
*/
static int ray_attach (device_t);
-static int ray_ccs_alloc (struct ray_softc *sc, size_t *ccsp, u_int cmd, int timo);
-static u_int8_t ray_ccs_free (struct ray_softc *sc, size_t ccs);
+static int ray_ccs_alloc (struct ray_softc *sc, size_t *ccsp, char *wmesg);
+static void ray_ccs_fill (struct ray_softc *sc, size_t ccs, u_int cmd);
+static u_int8_t ray_ccs_free (struct ray_softc *sc, size_t ccs);
+static int ray_ccs_tx (struct ray_softc *sc, size_t *ccsp, size_t *bufpp);
static void ray_com_ecf (struct ray_softc *sc, struct ray_comq_entry *com);
static void ray_com_ecf_done (struct ray_softc *sc);
static void ray_com_ecf_timo (void *xsc);
@@ -351,10 +388,10 @@ static struct ray_comq_entry *
#endif /* RAY_DEBUG & RAY_DBG_COM */
static void ray_com_runq (struct ray_softc *sc);
static void ray_com_runq_add (struct ray_softc *sc, struct ray_comq_entry *com);
-static void ray_com_runq_arr (struct ray_softc *sc, struct ray_comq_entry *com[], int ncom, char *wmesg);
+static int ray_com_runq_arr (struct ray_softc *sc, struct ray_comq_entry *com[], int ncom, char *wmesg);
static void ray_com_runq_done (struct ray_softc *sc);
static int ray_detach (device_t);
-static void ray_init_user (void *xsc);
+static int ray_init_user (struct ray_softc *sc);
static void ray_init_assoc (struct ray_softc *sc, struct ray_comq_entry *com);
static void ray_init_assoc_done (struct ray_softc *sc, size_t ccs);
static void ray_init_download (struct ray_softc *sc, struct ray_comq_entry *com);
@@ -383,12 +420,16 @@ static int ray_res_alloc_cm (struct ray_softc *sc);
static int ray_res_alloc_irq (struct ray_softc *sc);
static void ray_res_release (struct ray_softc *sc);
static void ray_rx (struct ray_softc *sc, size_t rcs);
+static void ray_rx_ctl (struct ray_softc *sc, struct mbuf *m0);
+static void ray_rx_mgt (struct ray_softc *sc, struct mbuf *m0);
+static void ray_rx_mgt_auth (struct ray_softc *sc, struct mbuf *m0);
static void ray_rx_update_cache (struct ray_softc *sc, u_int8_t *src, u_int8_t siglev, u_int8_t antenna);
static void ray_stop (struct ray_softc *sc);
static void ray_tx (struct ifnet *ifp);
static void ray_tx_done (struct ray_softc *sc, size_t ccs);
static void ray_tx_timo (void *xsc);
-static size_t ray_tx_wrhdr (struct ray_softc *sc, struct ether_header *eh, size_t bufp);
+static int ray_tx_send (struct ray_softc *sc, size_t ccs, u_int8_t pktlen, u_int8_t *dst);
+static size_t ray_tx_wrhdr (struct ray_softc *sc, size_t bufp, u_int8_t type, u_int8_t fc1, u_int8_t *addr1, u_int8_t *addr2, u_int8_t *addr3);
static void ray_upparams (struct ray_softc *sc, struct ray_comq_entry *com);
static void ray_upparams_done (struct ray_softc *sc, size_t ccs);
static int ray_upparams_user (struct ray_softc *sc, struct ray_param_req *pr);
@@ -582,7 +623,6 @@ ray_attach(device_t dev)
ifp->if_start = ray_tx;
ifp->if_ioctl = ray_ioctl;
ifp->if_watchdog = ray_watchdog;
- ifp->if_init = ray_init_user;
ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
if_attach(ifp);
@@ -676,8 +716,7 @@ ray_detach(device_t dev)
/*
* Mark as not running
*/
- ifp->if_flags &= ~IFF_RUNNING;
- ifp->if_flags &= ~IFF_OACTIVE;
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
/*
* Cleardown interface
@@ -704,6 +743,7 @@ ray_ioctl(register struct ifnet *ifp, u_long command, caddr_t data)
struct ray_param_req pr;
struct ray_stats_req sr;
struct ifreq *ifr = (struct ifreq *)data;
+ struct ifaddr *ifa = (struct ifaddr *)data;
int s, error, error2;
RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_IOCTL, "");
@@ -722,13 +762,24 @@ ray_ioctl(register struct ifnet *ifp, u_long command, caddr_t data)
switch (command) {
- case SIOCSIFADDR:
case SIOCGIFADDR:
case SIOCSIFMTU:
- RAY_DPRINTF(sc, RAY_DBG_IOCTL, "SIFADDR/GIFADDR/SIFMTU");
+ RAY_DPRINTF(sc, RAY_DBG_IOCTL, "GIFADDR/SIFMTU");
error = ether_ioctl(ifp, command, data);
break;
+ case SIOCSIFADDR:
+ RAY_DPRINTF(sc, RAY_DBG_IOCTL, "SIFADDR");
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ arp_ifinit((struct arpcom *)ifp, ifa);
+ break;
+#endif
+ }
+ /* FALLTHROUGH */
+
case SIOCSIFFLAGS:
RAY_DPRINTF(sc, RAY_DBG_IOCTL, "SIFFLAGS");
/*
@@ -737,7 +788,7 @@ ray_ioctl(register struct ifnet *ifp, u_long command, caddr_t data)
*/
if (ifp->if_flags & IFF_UP) {
if (!(ifp->if_flags & IFF_RUNNING))
- ray_init_user(sc);
+ error = ray_init_user(sc);
else
if (sc->sc_promisc !=
!!(ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)))
@@ -826,11 +877,9 @@ ray_ioctl(register struct ifnet *ifp, u_long command, caddr_t data)
}
/*
- * User land entry to network initialisation.
- *
- * An ioctl calls ray_init_user.
+ * User land entry to network initialisation. Called by ray_ioctl
*
- * ray_init_user does a bit of house keeping before calling ray_download
+ * First do a bit of house keeping before calling ray_download
*
* ray_init_download fills the startup parameter structure out and
* sends it to the card.
@@ -841,21 +890,23 @@ ray_ioctl(register struct ifnet *ifp, u_long command, caddr_t data)
* ray_init_sj_done checks a few parameters and we are ready to process packets
*
* the promiscuous and multi-cast modes are then set
+ *
+ * Returns values are either 0 for success, a varity of resource allocation
+ * failures or errors in the command sent to the card.
*/
-static void
-ray_init_user(void *xsc)
+static int
+ray_init_user(struct ray_softc *sc)
{
- struct ray_softc *sc = (struct ray_softc *)xsc;
struct ray_comq_entry *com[5];
struct ifnet *ifp = &sc->arpcom.ac_if;
- int i, ncom;
+ int i, ncom, error;
RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, "");
RAY_MAP_CM(sc);
if (sc->gone) {
RAY_PRINTF(sc, "unloaded");
- return;
+ return (ENODEV);
}
if ((ifp->if_flags & IFF_RUNNING))
@@ -893,7 +944,7 @@ ray_init_user(void *xsc)
sc->sc_promisc = !!(ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI));
sc->sc_havenet = 0;
- sc->translation = SC_TRANSLATE_WEBGEAR;
+ sc->framing = SC_FRAMING_WEBGEAR;
#if XXX_CLEARCCS_IN_INIT > 0
/* Set all ccs to be free */
@@ -932,12 +983,16 @@ ray_init_user(void *xsc)
com[ncom++] = RAY_COM_MALLOC(ray_mcast, 0);
#endif /* XXX_MCAST */
- ray_com_runq_arr(sc, com, ncom, "rayinit");
+ error = ray_com_runq_arr(sc, com, ncom, "rayinit");
+ if ((error == EINTR) || (error == ERESTART))
+ return (error);
- /* XXX no error processing from anything yet! */
+ /* XXX no real error processing from anything yet! */
for (i = 0; i < ncom; i++)
FREE(com[i], M_RAYCOM);
+
+ return (error);
}
/*
@@ -1066,7 +1121,7 @@ ray_init_download(struct ray_softc *sc, struct ray_comq_entry *com)
SRAM_WRITE_REGION(sc, RAY_HOST_TO_ECF_BASE,
&ray_mib_5_default, sizeof(ray_mib_5_default));
- (void)ray_ccs_alloc(sc, &com->c_ccs, RAY_CMD_DOWNLOAD_PARAMS, 0);
+ ray_ccs_fill(sc, com->c_ccs, RAY_CMD_DOWNLOAD_PARAMS);
ray_com_ecf(sc, com);
}
@@ -1104,9 +1159,9 @@ ray_init_sj(struct ray_softc *sc, struct ray_comq_entry *com)
sc->sc_havenet = 0;
if (sc->sc_d.np_net_type == RAY_MIB_NET_TYPE_ADHOC)
- (void)ray_ccs_alloc(sc, &com->c_ccs, RAY_CMD_START_NET, 0);
+ ray_ccs_fill(sc, com->c_ccs, RAY_CMD_START_NET);
else
- (void)ray_ccs_alloc(sc, &com->c_ccs, RAY_CMD_JOIN_NET, 0);
+ ray_ccs_fill(sc, com->c_ccs, RAY_CMD_JOIN_NET);
update = 0;
if (sc->sc_c.np_net_type != sc->sc_d.np_net_type)
@@ -1190,7 +1245,7 @@ ray_init_assoc(struct ray_softc *sc, struct ray_comq_entry *com)
RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_STARTJOIN, "");
RAY_MAP_CM(sc);
- (void)ray_ccs_alloc(sc, &com->c_ccs, RAY_CMD_START_ASSOC, 0);
+ ray_ccs_fill(sc, com->c_ccs, RAY_CMD_START_ASSOC);
ray_com_ecf(sc, com);
}
@@ -1363,7 +1418,7 @@ ray_watchdog(struct ifnet *ifp)
*/
/*
- * Start sending a packet.
+ * Send a packet.
*
* We make two assumptions here:
* 1) That the current priority is set to splimp _before_ this code
@@ -1420,12 +1475,11 @@ ray_tx(struct ifnet *ifp)
struct mbuf *m0, *m;
struct ether_header *eh;
size_t ccs, bufp;
- int i, pktlen, len;
- u_int8_t status;
+ int pktlen, len;
sc = ifp->if_softc;
- RAY_DPRINTF(sc, RAY_DBG_SUBR, "");
+ RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_TX, "");
RAY_MAP_CM(sc);
/*
@@ -1452,50 +1506,15 @@ ray_tx(struct ifnet *ifp)
untimeout(ray_tx_timo, sc, sc->tx_timerh);
/*
- * Find a free ccs; if none available wave good bye and exit.
- *
* We find a ccs before we process the mbuf so that we are sure it
* is worthwhile processing the packet. All errors in the mbuf
* processing are either errors in the mbuf or gross configuration
* errors and the packet wouldn't get through anyway.
- *
- * Don't forget to clear the ccs on errors.
*/
- i = RAY_CCS_TX_FIRST;
- do {
- status = SRAM_READ_FIELD_1(sc,
- RAY_CCS_ADDRESS(i), ray_cmd, c_status);
- if (status == RAY_CCS_STATUS_FREE)
- break;
- i++;
- } while (i <= RAY_CCS_TX_LAST);
- if (i > RAY_CCS_TX_LAST) {
+ if (ray_ccs_tx(sc, &ccs, &bufp)) {
ifp->if_flags |= IFF_OACTIVE;
return;
}
- RAY_DPRINTF(sc, RAY_DBG_CCS, "using ccs 0x%02x", i);
-
- /*
- * Reserve and fill the ccs - must do the length later.
- *
- * Even though build 4 and build 5 have different fields all these
- * are common apart from tx_rate. Neither the NetBSD driver or Linux
- * driver bother to overwrite this for build 4 cards.
- *
- * The start of the buffer must be aligned to a 256 byte boundary
- * (least significant byte of address = 0x00).
- */
- ccs = RAY_CCS_ADDRESS(i);
- bufp = RAY_TX_BASE + i * RAY_TX_BUF_SIZE;
- bufp += sc->sc_tibsize;
- SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_status, RAY_CCS_STATUS_BUSY);
- SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_cmd, RAY_CMD_TX_REQ);
- SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_link, RAY_CCS_LINK_NULL);
- SRAM_WRITE_FIELD_2(sc, ccs, ray_cmd_tx, c_bufp, bufp);
- SRAM_WRITE_FIELD_1(sc,
- ccs, ray_cmd_tx, c_tx_rate, sc->sc_c.np_def_txrate);
- SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_apm_mode, 0); /* XXX */
- bufp += sizeof(struct ray_tx_phy_header);
/*
* Get the mbuf and process it - we have to remember to free the
@@ -1529,17 +1548,37 @@ ray_tx(struct ifnet *ifp)
* as needed. This way, tcpdump -w can be used to grab the raw data. If
* needed the 802.11 aware program can "translate" the .11 to ethernet
* for tcpdump -r.
+ *
+ * XXX see /sys/dev/awi/awi.c:AWI_BPF_NORM stuff
*/
if (ifp->if_bpf)
bpf_mtap(ifp, m0);
/*
+ * Write the header according to network type etc.
+ */
+ if (sc->sc_c.np_net_type == RAY_MIB_NET_TYPE_ADHOC)
+ bufp = ray_tx_wrhdr(sc, bufp,
+ IEEE80211_FC0_TYPE_DATA,
+ IEEE80211_FC1_STA_TO_STA,
+ eh->ether_dhost,
+ eh->ether_shost,
+ sc->sc_c.np_bss_id);
+ else
+ if (sc->sc_c.np_ap_status == RAY_MIB_AP_STATUS_TERMINAL)
+ bufp = ray_tx_wrhdr(sc, bufp,
+ IEEE80211_FC0_TYPE_DATA,
+ IEEE80211_FC1_STA_TO_AP,
+ sc->sc_c.np_bss_id,
+ eh->ether_shost,
+ eh->ether_dhost);
+ else
+ RAY_PANIC(sc, "can't be an AP yet"); /* XXX_ACTING_AP */
+
+ /*
* Translation - capability as described earlier
*
- * Each case must write the 802.11 header using ray_tx_wrhdr,
- * passing a pointer to the ethernet header in and getting a new
- * tc buffer pointer. Next remove/modify/addto the 802.3 and 802.2
- * headers as needed.
+ * Remove/modify/addto the 802.3 and 802.2 headers as needed.
*
* We've pulled up the mbuf for you.
*
@@ -1552,14 +1591,14 @@ ray_tx(struct ifnet *ifp)
ifp->if_oerrors++;
return;
}
- switch (sc->translation) {
+ switch (sc->framing) {
- case SC_TRANSLATE_WEBGEAR:
- bufp = ray_tx_wrhdr(sc, eh, bufp);
+ case SC_FRAMING_WEBGEAR:
+ /* Nice and easy - nothing! (just add an 802.11 header) */
break;
default:
- RAY_PRINTF(sc, "unknown translation type %d", sc->translation);
+ RAY_PRINTF(sc, "unknown framing type %d", sc->framing);
RAY_CCS_FREE(sc, ccs);
ifp->if_oerrors++;
m_freem(m0);
@@ -1592,31 +1631,15 @@ ray_tx(struct ifnet *ifp)
RAY_PANIC(sc, "tx buffer overflow");
bufp += len;
}
- RAY_MBUF_DUMP(sc, m0, "ray_tx");
+ RAY_MBUF_DUMP(sc, RAY_DBG_TX, m0, "ray_tx");
/*
- * Fill in a few loose ends and kick the card to send the packet
+ * Send it off
*/
- if (!RAY_ECF_READY(sc)) {
- /*
- * XXX From NetBSD code:
- *
- * XXX If this can really happen perhaps we need to save
- * XXX the chain and use it later. I think this might
- * XXX be a confused state though because we check above
- * XXX and don't issue any commands between.
- */
- RAY_PRINTF(sc, "ECF busy, dropping packet");
- RAY_CCS_FREE(sc, ccs);
+ if (ray_tx_send(sc, ccs, pktlen, eh->ether_dhost))
ifp->if_oerrors++;
- return;
- }
- SRAM_WRITE_FIELD_2(sc, ccs, ray_cmd_tx, c_len, pktlen);
- SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_antenna,
- ray_tx_best_antenna(sc, eh->ether_dhost));
- SRAM_WRITE_1(sc, RAY_SCB_CCSI, RAY_CCS_INDEX(ccs));
- RAY_ECF_START_CMD(sc);
- ifp->if_opackets++;
+ else
+ ifp->if_opackets++;
m_freem(m0);
}
@@ -1643,44 +1666,61 @@ ray_tx_timo(void *xsc)
}
/*
- * Write an 802.11 header into the TX buffer and return the
+ * Write an 802.11 header into the Tx buffer space and return the
* adjusted buffer pointer.
*/
static size_t
-ray_tx_wrhdr(struct ray_softc *sc, struct ether_header *eh, size_t bufp)
+ray_tx_wrhdr(struct ray_softc *sc, size_t bufp, u_int8_t type, u_int8_t fc1, u_int8_t *addr1, u_int8_t *addr2, u_int8_t *addr3)
{
struct ieee80211_header header;
- RAY_DPRINTF(sc, RAY_DBG_SUBR, "");
+ RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_TX, "");
RAY_MAP_CM(sc);
bzero(&header, sizeof(struct ieee80211_header));
+ header.i_fc[0] = (IEEE80211_FC0_VERSION_0 | type);
+ header.i_fc[1] = fc1;
+ bcopy(addr1, header.i_addr1, ETHER_ADDR_LEN);
+ bcopy(addr2, header.i_addr2, ETHER_ADDR_LEN);
+ bcopy(addr3, header.i_addr3, ETHER_ADDR_LEN);
- header.i_fc[0] = (IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA);
- if (sc->sc_c.np_net_type == RAY_MIB_NET_TYPE_ADHOC) {
+ SRAM_WRITE_REGION(sc, bufp, (u_int8_t *)&header,
+ sizeof(struct ieee80211_header));
- header.i_fc[1] = IEEE80211_FC1_STA_TO_STA;
- bcopy(eh->ether_dhost, header.i_addr1, ETHER_ADDR_LEN);
- bcopy(eh->ether_shost, header.i_addr2, ETHER_ADDR_LEN);
- bcopy(sc->sc_c.np_bss_id, header.i_addr3, ETHER_ADDR_LEN);
+ return (bufp + sizeof(struct ieee80211_header));
+}
- } else {
- if (sc->sc_c.np_ap_status == RAY_MIB_AP_STATUS_TERMINAL) {
-
- header.i_fc[1] = IEEE80211_FC1_STA_TO_AP;
- bcopy(sc->sc_c.np_bss_id, header.i_addr1,
- ETHER_ADDR_LEN);
- bcopy(eh->ether_shost, header.i_addr2, ETHER_ADDR_LEN);
- bcopy(eh->ether_dhost, header.i_addr3, ETHER_ADDR_LEN);
+/*
+ * Fill in a few loose ends and kick the card to send the packet
+ *
+ * Returns 0 on success, 1 on failure
+ */
+static int
+ray_tx_send(struct ray_softc *sc, size_t ccs, u_int8_t pktlen, u_int8_t *dst)
+{
+ RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_TX, "");
+ RAY_MAP_CM(sc);
- } else
- RAY_PANIC(sc, "can't be an AP yet");
+ if (!RAY_ECF_READY(sc)) {
+ /*
+ * XXX From NetBSD code:
+ *
+ * XXX If this can really happen perhaps we need to save
+ * XXX the chain and use it later. I think this might
+ * XXX be a confused state though because we check above
+ * XXX and don't issue any commands between.
+ */
+ RAY_PRINTF(sc, "ECF busy, dropping packet");
+ RAY_CCS_FREE(sc, ccs);
+ return (1);
}
+ SRAM_WRITE_FIELD_2(sc, ccs, ray_cmd_tx, c_len, pktlen);
+ SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_antenna,
+ ray_tx_best_antenna(sc, dst));
+ SRAM_WRITE_1(sc, RAY_SCB_CCSI, RAY_CCS_INDEX(ccs));
+ RAY_ECF_START_CMD(sc);
- SRAM_WRITE_REGION(sc, bufp, (u_int8_t *)&header,
- sizeof(struct ieee80211_header));
-
- return (bufp + sizeof(struct ieee80211_header));
+ return (0);
}
/*
@@ -1693,7 +1733,7 @@ ray_tx_best_antenna(struct ray_softc *sc, u_int8_t *dst)
int i;
u_int8_t antenna;
- RAY_DPRINTF(sc, RAY_DBG_SUBR, "");
+ RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_TX, "");
RAY_MAP_CM(sc);
if (sc->sc_version == RAY_ECFS_BUILD_4)
@@ -1733,7 +1773,7 @@ ray_tx_done(struct ray_softc *sc, size_t ccs)
char *ss[] = RAY_CCS_STATUS_STRINGS;
u_int8_t status;
- RAY_DPRINTF(sc, RAY_DBG_SUBR, "");
+ RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_TX, "");
RAY_MAP_CM(sc);
status = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_status);
@@ -1765,7 +1805,6 @@ ray_rx(struct ray_softc *sc, size_t rcs)
size_t pktlen, fraglen, readlen, tmplen;
size_t bufp, ebufp;
u_int8_t *dst, *src;
- u_int8_t fc;
u_int8_t siglev, antenna;
u_int first, ni, i;
@@ -1876,82 +1915,114 @@ skip_read:
if (m0 == NULL)
return;
- RAY_MBUF_DUMP(sc, m0, "ray_rx");
-
/*
- * Check the 802.11 packet type and obtain the .11 src addresses.
- *
- * XXX CTL and MGT packets will have separate functions, DATA here
+ * Check the 802.11 packet type
*
- * XXX This needs some work for INFRA mode
+ * DATA packets are dealt with below, CTL and MGT packets
+ * are handled in their own functions.
*/
header = mtod(m0, struct ieee80211_header *);
- fc = header->i_fc[0];
- if ((fc & IEEE80211_FC0_VERSION_MASK) != IEEE80211_FC0_VERSION_0) {
+ if ((header->i_fc[0] & IEEE80211_FC0_VERSION_MASK)
+ != IEEE80211_FC0_VERSION_0) {
RAY_DPRINTF(sc, RAY_DBG_RECERR,
- "header not version 0 fc 0x%x", fc);
+ "header not version 0 fc0 0x%x", header->i_fc[0]);
ifp->if_ierrors++;
m_freem(m0);
return;
}
- switch (fc & IEEE80211_FC0_TYPE_MASK) {
+ switch (header->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
case IEEE80211_FC0_TYPE_MGT:
- RAY_PRINTF(sc, "unexpected MGT packet");
- ifp->if_ierrors++;
+ ray_rx_mgt(sc, m0);
m_freem(m0);
return;
+ break;
case IEEE80211_FC0_TYPE_CTL:
- RAY_PRINTF(sc, "unexpected CTL packet");
- ifp->if_ierrors++;
+ ray_rx_ctl(sc, m0);
m_freem(m0);
return;
+ break;
case IEEE80211_FC0_TYPE_DATA:
- RAY_DPRINTF(sc, RAY_DBG_RX, "got a DATA packet");
break;
default:
- RAY_PRINTF(sc, "unknown packet fc0 0x%x", fc);
+ RAY_PRINTF(sc, "unknown packet fc0 0x%x", header->i_fc[0]);
ifp->if_ierrors++;
m_freem(m0);
return;
}
- fc = header->i_fc[1];
+
+ /*
+ * Check the the data packet subtype, some packets have
+ * nothing in them so we will drop them here.
+ */
+ switch (header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
+
+ case IEEE80211_FC0_SUBTYPE_DATA_DATA:
+ case IEEE80211_FC0_SUBTYPE_DATA_DATA_CFACK:
+ case IEEE80211_FC0_SUBTYPE_DATA_DATA_CFPOLL:
+ case IEEE80211_FC0_SUBTYPE_DATA_DATA_CFACPL:
+ RAY_DPRINTF(sc, RAY_DBG_RX, "DATA packet");
+ break;
+
+ case IEEE80211_FC0_SUBTYPE_DATA_NULL:
+ case IEEE80211_FC0_SUBTYPE_DATA_CFACK:
+ case IEEE80211_FC0_SUBTYPE_DATA_CFPOLL:
+ case IEEE80211_FC0_SUBTYPE_DATA_CFACK_CFACK:
+ RAY_DPRINTF(sc, RAY_DBG_RX, "NULL packet");
+ m_freem(m0);
+ return;
+ break;
+
+ default:
+ RAY_PRINTF(sc, "reserved DATA packet subtype 0x%x",
+ header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
+ ifp->if_ierrors++;
+ m_freem(m0);
+ return;
+ }
+
+ /*
+ * Obtain the .11 src addresses.
+ *
+ * XXX This needs some work for INFRA mode
+ * XXX Do I need this at all? MGT and CTL is far easier.
+ */
src = header->i_addr2;
- switch (fc & IEEE80211_FC1_DS_MASK) {
+ switch (header->i_fc[1] & IEEE80211_FC1_DS_MASK) {
case IEEE80211_FC1_STA_TO_STA:
RAY_DPRINTF(sc, RAY_DBG_RX, "packet from sta %6D",
src, ":");
break;
- case IEEE80211_FC1_STA_TO_AP:
+ case IEEE80211_FC1_STA_TO_AP: /* XXX XXX_ACTING_AP */
RAY_DPRINTF(sc, RAY_DBG_RX, "packet from sta to ap %6D %6D",
src, ":", header->i_addr3, ":");
ifp->if_ierrors++;
m_freem(m0);
break;
- case IEEE80211_FC1_AP_TO_STA:
+ case IEEE80211_FC1_AP_TO_STA: /* XXX_INFRA */
RAY_DPRINTF(sc, RAY_DBG_RX, "packet from ap %6D",
src, ":");
ifp->if_ierrors++;
m_freem(m0);
break;
- case IEEE80211_FC1_AP_TO_AP:
+ case IEEE80211_FC1_AP_TO_AP: /* XXX XXX_ACTING_AP */
RAY_DPRINTF(sc, RAY_DBG_RX, "packet between aps %6D %6D",
src, ":", header->i_addr2, ":");
ifp->if_ierrors++;
m_freem(m0);
return;
+ break;
default:
- src = NULL;
- RAY_PRINTF(sc, "unknown packet fc1 0x%x", fc);
+ RAY_PRINTF(sc, "unknown packet fc1 0x%x", header->i_fc[1]);
ifp->if_ierrors++;
m_freem(m0);
return;
@@ -1963,15 +2034,16 @@ skip_read:
* Each case must remove the 802.11 header and leave an 802.3
* header in the mbuf copy addresses as needed.
*/
- switch (sc->translation) {
+ RAY_MBUF_DUMP(sc, RAY_DBG_RX, m0, "DATA packet before framing");
+ switch (sc->framing) {
- case SC_TRANSLATE_WEBGEAR:
+ case SC_FRAMING_WEBGEAR:
/* Nice and easy - just trim the 802.11 header */
m_adj(m0, sizeof(struct ieee80211_header));
break;
default:
- RAY_PRINTF(sc, "unknown translation type %d", sc->translation);
+ RAY_PRINTF(sc, "unknown framing type %d", sc->framing);
ifp->if_ierrors++;
m_freem(m0);
return;
@@ -1994,6 +2066,242 @@ skip_read:
}
/*
+ * Deal with MGT packet types
+ */
+static void
+ray_rx_mgt(struct ray_softc *sc, struct mbuf *m0)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ieee80211_header *header = mtod(m0, struct ieee80211_header *);
+
+ RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_MGT, "");
+
+ if ((header->i_fc[1] & IEEE80211_FC1_DS_MASK) !=
+ IEEE80211_FC1_STA_TO_STA) {
+ RAY_DPRINTF(sc, RAY_DBG_RECERR,
+ "MGT TODS/FROMDS wrong fc1 0x%x",
+ header->i_fc[1] & IEEE80211_FC1_DS_MASK);
+ ifp->if_ierrors++;
+ return;
+ }
+
+ /*
+ * Check the the mgt packet subtype, some packets should be
+ * dropped depending on the mode the station is in.
+ *
+ * XXX investigations of v5 firmware See pg 52(60) of docs
+ *
+ * P - proccess, J - Junk, E - ECF deals with, I - Illegal
+ * ECF Proccesses
+ * AHDOC procces or junk
+ * INFRA STA process or junk
+ * INFRA AP process or jumk
+ *
+ * +PPP IEEE80211_FC0_SUBTYPE_MGT_BEACON
+ * +EEE IEEE80211_FC0_SUBTYPE_MGT_PROBE_REQ
+ * +EEE IEEE80211_FC0_SUBTYPE_MGT_PROBE_RESP
+ * PPP IEEE80211_FC0_SUBTYPE_MGT_AUTH
+ * PPP IEEE80211_FC0_SUBTYPE_MGT_DEAUTH
+ * JJP IEEE80211_FC0_SUBTYPE_MGT_ASSOC_REQ
+ * JPJ IEEE80211_FC0_SUBTYPE_MGT_ASSOC_RESP
+ * JPP IEEE80211_FC0_SUBTYPE_MGT_DISASSOC
+ * JJP IEEE80211_FC0_SUBTYPE_MGT_REASSOC_REQ
+ * JPJ IEEE80211_FC0_SUBTYPE_MGT_REASSOC_RESP
+ * +EEE IEEE80211_FC0_SUBTYPE_MGT_ATIM
+ */
+ RAY_MBUF_DUMP(sc, RAY_DBG_RX, m0, "MGT packet");
+ switch (header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
+
+ case IEEE80211_FC0_SUBTYPE_MGT_BEACON:
+ RAY_DPRINTF(sc, RAY_DBG_MGT, "BEACON MGT packet");
+ /* XXX furtle anything interesting out */
+ /* Note that there are rules governing what beacons to
+ read, see 8802 S7.2.3, S11.1.2.3 */
+ break;
+
+ case IEEE80211_FC0_SUBTYPE_MGT_AUTH:
+ RAY_DPRINTF(sc, RAY_DBG_MGT, "AUTH MGT packet");
+ ray_rx_mgt_auth(sc, m0);
+ break;
+
+ case IEEE80211_FC0_SUBTYPE_MGT_DEAUTH:
+ RAY_DPRINTF(sc, RAY_DBG_MGT, "DEAUTH MGT packet");
+ break;
+
+ case IEEE80211_FC0_SUBTYPE_MGT_ASSOC_REQ:
+ case IEEE80211_FC0_SUBTYPE_MGT_REASSOC_REQ:
+ RAY_DPRINTF(sc, RAY_DBG_MGT, "(RE)ASSOC_REQ MGT packet");
+ if (sc->sc_c.np_ap_status != RAY_MIB_AP_STATUS_AP)
+ return;
+ else
+ RAY_PANIC(sc, "can't be an AP yet"); /* XXX_ACTING_AP */
+ break;
+
+ case IEEE80211_FC0_SUBTYPE_MGT_ASSOC_RESP:
+ case IEEE80211_FC0_SUBTYPE_MGT_REASSOC_RESP:
+ RAY_DPRINTF(sc, RAY_DBG_MGT, "(RE)ASSOC_RESP MGT packet");
+ if ((sc->sc_d.np_net_type == RAY_MIB_NET_TYPE_ADHOC) ||
+ (sc->sc_c.np_ap_status == RAY_MIB_AP_STATUS_AP))
+ return;
+ else
+ RAY_PANIC(sc, "can't be in INFRA yet"); /* XXX_INFRA */
+ break;
+
+ case IEEE80211_FC0_SUBTYPE_MGT_DISASSOC:
+ RAY_DPRINTF(sc, RAY_DBG_MGT, "DISASSOC MGT packet");
+ if (sc->sc_d.np_net_type == RAY_MIB_NET_TYPE_ADHOC)
+ return;
+ else
+ RAY_PANIC(sc, "can't be in INFRA yet"); /* XXX_INFRA */
+ break;
+
+ case IEEE80211_FC0_SUBTYPE_MGT_PROBE_REQ:
+ case IEEE80211_FC0_SUBTYPE_MGT_PROBE_RESP:
+ case IEEE80211_FC0_SUBTYPE_MGT_ATIM:
+ RAY_PRINTF(sc, "unexpected MGT packet subtype 0x%0x",
+ header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
+ ifp->if_ierrors++;
+ break;
+
+ default:
+ RAY_PRINTF(sc, "reserved MGT packet subtype 0x%x",
+ header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
+ ifp->if_ierrors++;
+ return;
+ }
+}
+
+/*
+ * Deal with AUTH management packet types
+ */
+static void
+ray_rx_mgt_auth(struct ray_softc *sc, struct mbuf *m0)
+{
+ struct ieee80211_header *header = mtod(m0, struct ieee80211_header *);
+ ieee80211_mgt_auth_t auth = (u_int8_t *)(header+1);
+ size_t ccs, bufp;
+ int pktlen;
+
+ RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_MGT, "");
+ RAY_MAP_CM(sc);
+
+ switch (IEEE80211_AUTH_ALGORITHM(auth)) {
+
+ case IEEE80211_AUTH_OPENSYSTEM:
+ if (IEEE80211_AUTH_TRANSACTION(auth) == 1) {
+ /* XXX see sys/dev/awi/awk.c:awi_{recv|send}_auth */
+
+ /*
+ * Send authentication response if possible. If
+ * we are out of CCSs we don't to anything, the
+ * other end will try again.
+ */
+ if (ray_ccs_tx(sc, &ccs, &bufp)) {
+ return;
+ }
+RAY_DPRINTF(sc, RAY_DBG_MGT, "bufp %x", bufp);
+
+ bufp = ray_tx_wrhdr(sc, bufp,
+ IEEE80211_FC0_TYPE_MGT |
+ IEEE80211_FC0_SUBTYPE_MGT_AUTH,
+ IEEE80211_FC1_STA_TO_STA,
+ header->i_addr2,
+ header->i_addr1,
+ header->i_addr3);
+
+ for (pktlen = 0; pktlen < 6; pktlen++)
+ SRAM_WRITE_1(sc, bufp+pktlen, 0);
+ pktlen += sizeof(struct ieee80211_header);
+ SRAM_WRITE_1(sc, bufp+2, 2);
+
+RAY_DPRINTF(sc, RAY_DBG_MGT, "dump start %x", bufp-pktlen+6);
+RAY_DHEX8(sc, RAY_DBG_MGT, bufp-pktlen+6, pktlen, "AUTH MGT response to Open System request");
+ (void)ray_tx_send(sc, ccs, pktlen, header->i_addr2);
+
+ } else if (IEEE80211_AUTH_TRANSACTION(auth) == 2) {
+
+ if (IEEE80211_AUTH_STATUS(auth) !=
+ IEEE80211_STATUS_SUCCESS)
+ RAY_PRINTF(sc,
+ "authentication failed with status %d",
+ IEEE80211_AUTH_STATUS(auth));
+
+ /* XXX probably need a lot more than this */
+
+ }
+ break;
+
+ case IEEE80211_AUTH_SHAREDKEYS:
+ RAY_PRINTF(sc, "shared key authentication requested");
+ break;
+
+ default:
+ RAY_PRINTF(sc,
+ "unknown authentication subtype 0x%04hx",
+ IEEE80211_AUTH_ALGORITHM(auth));
+ break;
+ }
+}
+
+/*
+ * Deal with CTL packet types
+ */
+static void
+ray_rx_ctl(struct ray_softc *sc, struct mbuf *m0)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ieee80211_header *header = mtod(m0, struct ieee80211_header *);
+
+ RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_CTL, "");
+
+ if ((header->i_fc[1] & IEEE80211_FC1_DS_MASK) !=
+ IEEE80211_FC1_STA_TO_STA) {
+ RAY_DPRINTF(sc, RAY_DBG_RECERR,
+ "CTL TODS/FROMDS wrong fc1 0x%x",
+ header->i_fc[1] & IEEE80211_FC1_DS_MASK);
+ ifp->if_ierrors++;
+ return;
+ }
+
+ /*
+ * Check the the ctl packet subtype, some packets should be
+ * dropped depending on the mode the station is in. The ECF
+ * should deal with everything but the power save poll to an
+ * AP
+ *
+ * XXX investigations of v5 firmware See pg 52(60) of docs
+ *
+ */
+ RAY_MBUF_DUMP(sc, RAY_DBG_CTL, m0, "CTL packet");
+ switch (header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
+
+ case IEEE80211_FC0_SUBTYPE_CTL_PS_POLL:
+ RAY_DPRINTF(sc, RAY_DBG_CTL, "PS_POLL CTL packet");
+ if (sc->sc_c.np_ap_status != RAY_MIB_AP_STATUS_AP)
+ return;
+ else
+ RAY_PANIC(sc, "can't be an AP yet"); /* XXX_ACTING_AP */
+ break;
+
+ case IEEE80211_FC0_SUBTYPE_CTL_RTS:
+ case IEEE80211_FC0_SUBTYPE_CTL_CTS:
+ case IEEE80211_FC0_SUBTYPE_CTL_ACK:
+ case IEEE80211_FC0_SUBTYPE_CTL_CFEND:
+ case IEEE80211_FC0_SUBTYPE_CTL_CFEND_CFACK:
+ RAY_PRINTF(sc, "unexpected CTL packet subtype 0x%0x",
+ header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
+ ifp->if_ierrors++;
+ break;
+
+ default:
+ RAY_PRINTF(sc, "reserved CTL packet subtype 0x%x",
+ header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
+ ifp->if_ierrors++;
+ return;
+ }
+}
+
+/*
* Update rx level and antenna cache
*/
static void
@@ -2227,17 +2535,17 @@ ray_intr_rcs(struct ray_softc *sc, u_int8_t cmd, size_t rcs)
switch (cmd) {
case RAY_ECMD_RX_DONE:
- RAY_DPRINTF(sc, RAY_DBG_CCS, "RX_DONE");
+ RAY_DPRINTF(sc, RAY_DBG_RX, "RX_DONE");
ray_rx(sc, rcs);
break;
case RAY_ECMD_REJOIN_DONE:
- RAY_DPRINTF(sc, RAY_DBG_CCS, "REJOIN_DONE");
+ RAY_DPRINTF(sc, RAY_DBG_RX, "REJOIN_DONE");
sc->sc_havenet = 1; /* XXX Should not be here but in function */
break;
case RAY_ECMD_ROAM_START:
- RAY_DPRINTF(sc, RAY_DBG_CCS, "ROAM_START");
+ RAY_DPRINTF(sc, RAY_DBG_RX, "ROAM_START");
sc->sc_havenet = 0; /* XXX Should not be here but in function */
break;
@@ -2261,6 +2569,7 @@ ray_intr_rcs(struct ray_softc *sc, u_int8_t cmd, size_t rcs)
* XXX for now.
* XXX Don't like the code bloat to set promisc up - we use it here, ray_init,
* XXX ray_promisc_user and ray_upparams_user...
+ * XXX need to use the runq_array
*/
/*
@@ -2349,8 +2658,8 @@ ray_mcast(struct ray_softc *sc, struct ray_comq_entry *com)
RAY_DPRINTF(sc, RAY_DBG_SUBR, "");
RAY_MAP_CM(sc);
- (void)ray_ccs_alloc(sc, &com->c_ccs, RAY_CMD_UPDATE_MCAST, 0);
- SRAM_WRITE_FIELD_1(sc, &com->c_ccs,
+ ray_ccs_fill(sc, com->c_ccs, RAY_CMD_UPDATE_MCAST);
+ SRAM_WRITE_FIELD_1(sc, com->c_ccs
ray_cmd_update_mcast, c_nmcast, count);
bufp = RAY_HOST_TO_ECF_BASE;
for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
@@ -2398,8 +2707,11 @@ ray_promisc_user(struct ray_softc *sc)
ncom = 0;
com[ncom++] = RAY_COM_MALLOC(ray_promisc, RAY_COM_FWOK);
- ray_com_runq_arr(sc, com, ncom, "raypromisc");
+ error = ray_com_runq_arr(sc, com, ncom, "raypromisc");
+ if ((error == EINTR) || (error == ERESTART))
+ return (error);
+ /* XXX no real error processing from anything yet! */
error = com[0]->c_retval;
for (i = 0; i < ncom; i++)
@@ -2419,7 +2731,7 @@ ray_promisc(struct ray_softc *sc, struct ray_comq_entry *com)
RAY_DPRINTF(sc, RAY_DBG_SUBR, "");
RAY_MAP_CM(sc);
- (void)ray_ccs_alloc(sc, &com->c_ccs, RAY_CMD_UPDATE_PARAMS, 0);
+ ray_ccs_fill(sc, com->c_ccs, RAY_CMD_UPDATE_PARAMS);
SRAM_WRITE_FIELD_1(sc, com->c_ccs,
ray_cmd_update, c_paramid, RAY_MIB_PROMISC);
SRAM_WRITE_FIELD_1(sc, com->c_ccs, ray_cmd_update, c_nparam, 1);
@@ -2532,8 +2844,11 @@ ray_repparams_user(struct ray_softc *sc, struct ray_param_req *pr)
com[ncom++] = RAY_COM_MALLOC(ray_repparams, RAY_COM_FWOK);
com[ncom-1]->c_pr = pr;
- ray_com_runq_arr(sc, com, ncom, "rayrepparams");
+ error = ray_com_runq_arr(sc, com, ncom, "rayrepparams");
+ if ((error == EINTR) || (error == ERESTART))
+ return (error);
+ /* XXX no real error processing from anything yet! */
error = com[0]->c_retval;
if (!error && pr->r_failcause)
error = EINVAL;
@@ -2553,7 +2868,7 @@ ray_repparams(struct ray_softc *sc, struct ray_comq_entry *com)
RAY_DPRINTF(sc, RAY_DBG_SUBR, "");
RAY_MAP_CM(sc);
- (void)ray_ccs_alloc(sc, &com->c_ccs, RAY_CMD_REPORT_PARAMS, 0);
+ ray_ccs_fill(sc, com->c_ccs, RAY_CMD_REPORT_PARAMS);
SRAM_WRITE_FIELD_1(sc, com->c_ccs,
ray_cmd_report, c_paramid, com->c_pr->r_paramid);
@@ -2703,12 +3018,15 @@ ray_upparams_user(struct ray_softc *sc, struct ray_param_req *pr)
#endif /* XXX_ASSOC */
}
- ray_com_runq_arr(sc, com, ncom, "rayupparams");
+ error = ray_com_runq_arr(sc, com, ncom, "rayupparams");
+ if ((error == EINTR) || (error == ERESTART))
+ return (error);
+
+ /* XXX no real error processing from anything yet! */
error = com[0]->c_retval;
if (!error && pr->r_failcause)
error = EINVAL;
- /* XXX no error processing from ray_init_sj yet! */
for (i = 0; i < ncom; i++)
FREE(com[i], M_RAYCOM);
@@ -2725,7 +3043,7 @@ ray_upparams(struct ray_softc *sc, struct ray_comq_entry *com)
RAY_DPRINTF(sc, RAY_DBG_SUBR, "");
RAY_MAP_CM(sc);
- (void)ray_ccs_alloc(sc, &com->c_ccs, RAY_CMD_UPDATE_PARAMS, 0);
+ ray_ccs_fill(sc, com->c_ccs, RAY_CMD_UPDATE_PARAMS);
SRAM_WRITE_FIELD_1(sc, com->c_ccs,
ray_cmd_update, c_paramid, com->c_pr->r_paramid);
@@ -2802,26 +3120,63 @@ ray_com_malloc(ray_comqfn_t function, int flags)
}
/*
- * Add an array of commands to the runq and then run them, waiting on
- * the last command
+ * Add an array of commands to the runq, get some ccs's for them and
+ * then run, waiting on the last command.
+ *
+ * We add the commands to the queue first to serialise ioctls, as the
+ * ccs allocation may wait. The ccs allocation may timeout, in which
+ * case the ccs and comq entries are freed.
*/
-static void
+static int
ray_com_runq_arr(struct ray_softc *sc, struct ray_comq_entry *com[], int ncom, char *wmesg)
{
- int i;
+ int i, error;
RAY_DPRINTF(sc, RAY_DBG_SUBR, "");
+ error = 0;
+ /*
+ * Add the commands to the runq but don't let it run until
+ * the ccs's are allocated successfully
+ */
+ com[0]->c_flags |= RAY_COM_FWAIT;
for (i = 0; i < ncom; i++) {
com[i]->c_wakeup = com[ncom-1];
ray_com_runq_add(sc, com[i]);
}
com[ncom-1]->c_flags = RAY_COM_FWOK;
+ /*
+ * Allocate ccs's for each command. If we fail, clean up
+ * and return.
+ */
+ for (i = 0; i < ncom; i++) {
+ error = ray_ccs_alloc(sc, &com[i]->c_ccs, wmesg);
+ if (error)
+ break;
+ }
+ if (error) {
+ for (i = 0; i < ncom; i++) {
+ if (com[i]->c_ccs != NULL)
+ ray_ccs_free(sc, com[i]->c_ccs);
+ TAILQ_REMOVE(&sc->sc_comq, com[i], c_chain);
+ FREE(com[i], M_RAYCOM);
+ }
+ return (error);
+ }
+
+ /*
+ * Allow the queue to run
+ */
+ com[0]->c_flags &= ~RAY_COM_FWAIT;
ray_com_runq(sc);
RAY_DPRINTF(sc, RAY_DBG_COM, "sleeping");
- (void)tsleep(com[ncom-1], 0, wmesg, 0);
+ error = tsleep(com[ncom-1], PCATCH, wmesg, 0);
RAY_DPRINTF(sc, RAY_DBG_COM, "awakened");
+ if (error)
+ RAY_PRINTF(sc, "sleep error 0x%0x", error);
+
+ return (error);
}
/*
@@ -2857,8 +3212,14 @@ ray_com_runq(struct ray_softc *sc)
RAY_DPRINTF(sc, RAY_DBG_COM, "command already running");
return;
}
+ if (com->c_flags & RAY_COM_FWAIT) {
+ RAY_DPRINTF(sc, RAY_DBG_COM, "command not ready");
+ return;
+ }
#else
- if ((com == NULL) || (com->c_flags & RAY_COM_FRUNNING))
+ if ((com == NULL) ||
+ (com->c_flags & RAY_COM_FRUNNING) ||
+ (com->c_flags & RAY_COM_FWAIT))
return;
#endif /* RAY_DEBUG & RAY_DBG_COM */
@@ -3089,21 +3450,22 @@ ray_com_ecf_check(struct ray_softc *sc, size_t ccs, char *mesg)
#endif /* RAY_DEBUG & RAY_DBG_COM */
/*
- * CCS allocator for commands
+ * CCS allocators
*/
/*
- * Obtain a ccs and fill easy bits in
+ * Obtain a ccs for a commmand
*
- * Returns 1 and in `ccsp' the bus offset of the free ccs. Will block
- * awaiting free ccs if needed, timo is passed to tsleep and will
- * return 0 if the timeout expired.
+ * Returns 0 and in `ccsp' the bus offset of the free ccs. Will block
+ * awaiting free ccs if needed - if the sleep is interrupted EINTR/ERESTART
+ * is returned.
*/
static int
-ray_ccs_alloc(struct ray_softc *sc, size_t *ccsp, u_int cmd, int timo)
+ray_ccs_alloc(struct ray_softc *sc, size_t *ccsp, char *wmesg)
{
size_t ccs;
u_int i;
+ int error;
RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_CCS, "");
RAY_MAP_CM(sc);
@@ -3117,20 +3479,37 @@ ray_ccs_alloc(struct ray_softc *sc, size_t *ccsp, u_int cmd, int timo)
break;
}
if (i > RAY_CCS_CMD_LAST) {
- RAY_PANIC(sc, "out of CCS's");
+ RAY_DPRINTF(sc, RAY_DBG_CCS, "sleeping");
+ error = tsleep(ray_ccs_alloc, PCATCH, wmesg, 0);
+ RAY_DPRINTF(sc, RAY_DBG_CCS, "awakened");
+ if (error)
+ return (error);
} else
break;
}
-
+ RAY_DPRINTF(sc, RAY_DBG_CCS, "allocated 0x%02x", i);
sc->sc_ccsinuse[i] = 1;
ccs = RAY_CCS_ADDRESS(i);
- RAY_DPRINTF(sc, RAY_DBG_CCS, "allocated 0x%02x", i);
+ *ccsp = ccs;
+
+ return (0);
+}
+
+/*
+ * Fill the easy bits in of a pre-allocated CCS
+ */
+static void
+ray_ccs_fill(struct ray_softc *sc, size_t ccs, u_int cmd)
+{
+ RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_CCS, "");
+ RAY_MAP_CM(sc);
+
+ if (ccs == NULL)
+ RAY_PANIC(sc, "ccs not allocated");
+
SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_status, RAY_CCS_STATUS_BUSY);
SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_cmd, cmd);
SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd, c_link, RAY_CCS_LINK_NULL);
-
- *ccsp = ccs;
- return (1);
}
/*
@@ -3150,13 +3529,72 @@ ray_ccs_free(struct ray_softc *sc, size_t ccs)
status = SRAM_READ_FIELD_1(sc, ccs, ray_cmd, c_status);
RAY_CCS_FREE(sc, ccs);
sc->sc_ccsinuse[RAY_CCS_INDEX(ccs)] = 0;
- wakeup(ray_ccs_alloc);
RAY_DPRINTF(sc, RAY_DBG_CCS, "freed 0x%02x", RAY_CCS_INDEX(ccs));
+ wakeup(ray_ccs_alloc);
return (status);
}
/*
+ * Obtain a ccs and tx buffer to transmit with and fill them in.
+ *
+ * Returns 0 and in `ccsp' the bus offset of the free ccs. Will not block
+ * and if none available and will returns EAGAIN.
+ *
+ * The caller must fill in the length later.
+ * The caller must clear the ccs on errors.
+ */
+static int
+ray_ccs_tx(struct ray_softc *sc, size_t *ccsp, size_t *bufpp)
+{
+ size_t ccs, bufp;
+ int i;
+ u_int8_t status;
+
+ RAY_DPRINTF(sc, RAY_DBG_SUBR | RAY_DBG_CCS, "");
+ RAY_MAP_CM(sc);
+
+ i = RAY_CCS_TX_FIRST;
+ do {
+ status = SRAM_READ_FIELD_1(sc, RAY_CCS_ADDRESS(i),
+ ray_cmd, c_status);
+ if (status == RAY_CCS_STATUS_FREE)
+ break;
+ i++;
+ } while (i <= RAY_CCS_TX_LAST);
+ if (i > RAY_CCS_TX_LAST) {
+ return (EAGAIN);
+ }
+ RAY_DPRINTF(sc, RAY_DBG_CCS, "allocated 0x%02x", i);
+
+ /*
+ * Reserve and fill the ccs - must do the length later.
+ *
+ * Even though build 4 and build 5 have different fields all these
+ * are common apart from tx_rate. Neither the NetBSD driver or Linux
+ * driver bother to overwrite this for build 4 cards.
+ *
+ * The start of the buffer must be aligned to a 256 byte boundary
+ * (least significant byte of address = 0x00).
+ */
+ ccs = RAY_CCS_ADDRESS(i);
+ bufp = RAY_TX_BASE + i * RAY_TX_BUF_SIZE;
+ bufp += sc->sc_tibsize;
+ SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_status, RAY_CCS_STATUS_BUSY);
+ SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_cmd, RAY_CMD_TX_REQ);
+ SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_link, RAY_CCS_LINK_NULL);
+ SRAM_WRITE_FIELD_2(sc, ccs, ray_cmd_tx, c_bufp, bufp);
+ SRAM_WRITE_FIELD_1(sc,
+ ccs, ray_cmd_tx, c_tx_rate, sc->sc_c.np_def_txrate);
+ SRAM_WRITE_FIELD_1(sc, ccs, ray_cmd_tx, c_apm_mode, 0); /* XXX */
+ bufp += sizeof(struct ray_tx_phy_header);
+
+ *ccsp = ccs;
+ *bufpp = bufp;
+ return (0);
+}
+
+/*
* Routines to obtain resources for the card
*/
@@ -3366,7 +3804,7 @@ ray_dump_mbuf(struct ray_softc *sc, struct mbuf *m, char *s)
u_int i;
char p[17];
- RAY_PRINTF(sc, "%s mbuf dump:", s);
+ RAY_PRINTF(sc, "%s", s);
i = 0;
bzero(p, 17);
for (; m; m = m->m_next) {
@@ -3383,7 +3821,7 @@ ray_dump_mbuf(struct ray_softc *sc, struct mbuf *m, char *s)
}
}
if ((i - 1) % 16)
- printf("%s\n", p);
+ printf(" %s\n", p);
}
#endif /* RAY_DEBUG & RAY_DBG_MBUF */
OpenPOWER on IntegriCloud