From a32a5403e7a7d1ed33dd5ba8353df1f9a383fe3c Mon Sep 17 00:00:00 2001 From: Farhan Khan Date: Wed, 29 Nov 2023 17:32:36 -0500 Subject: [PATCH] Code builds, basic handlers in place, some documentation --- .gitignore | 5 + LICENSE | 24 +++ Makefile | 6 + README.md | 41 +++++ i3e_template_driver.c | 367 ++++++++++++++++++++++++++++++++++++++++++ i3e_template_driver.h | 112 +++++++++++++ 6 files changed, 555 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 i3e_template_driver.c create mode 100644 i3e_template_driver.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..33d5b8f --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +opt_global.h +exort_syms +*.swp +*.ko +*.o diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ff7baf1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +BSD 2-Clause License + +Copyright (c) 2023, Farhan Khan (farhan@farhan.codes) + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6715841 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +KMOD= i3e_template_driver +SRCS= i3e_template_driver.c + +DCOPTFLAGS+= -g -O0 + +.include diff --git a/README.md b/README.md new file mode 100644 index 0000000..d3f95f6 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# i3e_template_driver + +## Introduction + +This is a templated implementation of FreeBSD's 15-CURRENT net80211 layer. This driver is intended as a learning resource. +This driver is as much a project for myself as it is for any future readers :) +The driver does not implement PCIe, USB or SDIO layers. Rather, everything is implemented in software. + +## How to Test code + +On a FreeBSD host, run the following: + +``` +git clone https://github.com/khanzf/i3e_temlate_driver +cd i3e_template_driver +make +make load +``` + +To create a `wlan0` VAP, run the following command: +``` +ifconfig wlan create wlandev i3e0 +``` + +## How to read + +### Explanation + +## Source Files + +## ieee80211com + +## ieee80211vap + +## LICENSE + +This code is licensed under the 2-Clause BSD. + +## Author + +The author of this is code Farhan Khan (farhan@farhan.codes) diff --git a/i3e_template_driver.c b/i3e_template_driver.c new file mode 100644 index 0000000..c9bc08b --- /dev/null +++ b/i3e_template_driver.c @@ -0,0 +1,367 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Farhan Khan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This is a template driver for FreeBSD's net80211 layer. + * This is intended as a learning tool on the minimum implementation + * of the net80211 layer entirely in software. + * + * This driver does not implement the USB, PCIe or SDIO layers, which would ordinarily + * be responsible for the match, power on/off, state management, etc. Instead, this code + * implements everything in software. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i3e_template_driver.h" + +// This function triggers whenever you run ifconfig wlan0 destroy +static void +i3e_template_vap_delete(struct ieee80211vap *vap) +{ + struct i3e_template_vap *ivp = I3E_TEMPLATE_VAP(vap); + ieee80211_vap_detach(vap); // Minimum needed to delete the VAP + free(ivp, M_80211_VAP); +} + +static int +i3e_template_detach(struct i3e_template_softc *sc) +{ + I3E_TEMPLATE_LOCK(sc); + sc->sc_detached = 1; + I3E_TEMPLATE_UNLOCK(sc); + + return (0); +} + +static int +i3e_template_init(struct i3e_template_softc *sc) +{ + printf("i3e_template_init\n"); + return (0); +} + +static void +i3e_template_stop(struct i3e_template_softc *sc) +{ + printf("i3e_template_stop\n"); +} + +static void +i3e_template_set_channel(struct ieee80211com *ic) +{ + struct i3e_template_softc *sc = ic->ic_softc; + + I3E_TEMPLATE_LOCK(sc); + printf("i3e_template_set_channel\n"); + I3E_TEMPLATE_UNLOCK(sc); +} + +/* + * Raw Transmission is handled here + * Come back to this, needs more detail +*/ +static int +i3e_template_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params) +{ + struct ieee80211com *ic = ni->ni_ic; + struct i3e_template_softc *sc = ic->ic_softc; + int ret = 0; + + + /* this prevents management frames from being sent if we are not ready */ + I3E_TEMPLATE_LOCK(sc); + if (!(sc->sc_running)) { + ret = ENETDOWN; + goto fail; + } + /* Raw transmission happens here */ +fail: + printf("i3e_template_raw_xmit, return with %d\n", ret); + I3E_TEMPLATE_UNLOCK(sc); + return (ret); +} + +static void +i3e_template_update_mcast(struct ieee80211com *ic) +{ + printf("i3e_template_updadte_mcast unimplemented.\n"); +} + +/* + * This function is triggered when the device is brought up or down + * For example, `ifconfig wlan0 up` or `ifconfig wlan0 down` + * The basic structure below is replicated in most drivers + */ +static void +i3e_template_parent(struct ieee80211com *ic) +{ + struct i3e_template_softc *sc = ic->ic_softc; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + printf("i3e_template_parent\n"); + + I3E_TEMPLATE_LOCK(sc); + if (sc->sc_detached) { // If the device is already detached, + I3E_TEMPLATE_UNLOCK(sc); + return; + } + I3E_TEMPLATE_UNLOCK(sc); + + if (ic->ic_nrunning > 0) { + if (i3e_template_init(sc) == 0) + ieee80211_start_all(ic); + else + ieee80211_stop(vap); + } else + i3e_template_stop(sc); +} + +static void +i3e_template_scan_start(struct ieee80211com *ic) +{ + struct i3e_template_softc *sc = ic->ic_softc; + + I3E_TEMPLATE_LOCK(sc); + // Typically here we would send a command to the device to Start the device into scan-mode + printf("%s: Scan Start\n", sc->sc_ic.ic_name); + I3E_TEMPLATE_UNLOCK(sc); +} + +static void +i3e_template_scan_end(struct ieee80211com *ic) +{ + struct i3e_template_softc *sc = ic->ic_softc; + + I3E_TEMPLATE_LOCK(sc); + // Typically here we would send a command to the device to stop the device into scan-mode + printf("%s: Scan End\n", sc->sc_ic.ic_name); + I3E_TEMPLATE_UNLOCK(sc); +} + +static struct ieee80211vap * +i3e_template_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, + enum ieee80211_opmode opmode, int flags, + const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + struct ieee80211vap *vap; + struct i3e_template_vap *ivp; + + switch(opmode) { + case IEEE80211_M_IBSS: + printf("opmode = IEEE80211_M_IBSS, Adhoc mode\n"); + break; + case IEEE80211_M_STA: + printf("opmode = IEEE80211_M_IBSS, infrastructure station\n"); + break; + case IEEE80211_M_WDS: + printf("opmode = IEEE80211_M_WDS, WDS Link\n"); + break; + case IEEE80211_M_AHDEMO: + printf("opmode = IEEE80211_M_AHDEMO, Old lucent compatible adhoc demo\n"); + break; + case IEEE80211_M_HOSTAP: + printf("opmode = IEEE80211_M_HOSTAP, Software Access Point\n"); + break; + case IEEE80211_M_MONITOR: + printf("opmdoe = IEEE80211_M_MONITOR\n"); + break; + case IEEE80211_M_MBSS: + printf("opmode = IEEE80211_M_MBSS\n"); + break; + default: + printf("opmode = Unknown (%d)\n", opmode); + break; + } + + ivp = malloc(sizeof(struct i3e_template_vap), M_80211_VAP, M_WAITOK | M_ZERO); + vap = &ivp->vap; + + if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid) != 0) { + uprintf("i3e_vap_setup failed\n"); + free(ivp, M_80211_VAP); + return (NULL); + } + + ivp->newstate = vap->iv_newstate; + + ieee80211_vap_attach(vap, ieee80211_media_change, + ieee80211_media_status, mac); + ic->ic_opmode = opmode; + + return (vap); +} + +static int i3e_template_attach(struct i3e_template_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + I3E_TEMPLATE_LOCK_INIT(sc); // Initialize the Mutex lock + + ic->ic_softc = sc; + ic->ic_name = "i3e0"; /* Ordinarily this would be device_get_nameunit(self), but manually setting it because + * this is not a real driver */ + ic->ic_phytype = IEEE80211_T_DS; // Physical type, enum defined in sys/net/80211/_ieee80211.h + + ic->ic_caps = + IEEE80211_C_STA /* station mode supported */ + | IEEE80211_C_IBSS /* IBSS mode supported */ + | IEEE80211_C_MONITOR /* monitor mode supported */ + | IEEE80211_C_HOSTAP /* HostAp mode supported */ + | IEEE80211_C_AHDEMO /* adhoc demo mode */ + | IEEE80211_C_TXPMGT /* tx power management */ + | IEEE80211_C_SHPREAMBLE /* short preamble supported */ + | IEEE80211_C_SHSLOT /* short slot time supported */ + | IEEE80211_C_BGSCAN /* bg scanning supported */ + | IEEE80211_C_WPA /* 802.11i */ + | IEEE80211_C_WME /* 802.11e */ + | IEEE80211_C_PMGT /* Station-side power mgmt */ + ; + + ic->ic_cryptocaps = + IEEE80211_CRYPTO_WEP | + IEEE80211_CRYPTO_AES_CCM | + IEEE80211_CRYPTO_TKIPMIC | + IEEE80211_CRYPTO_TKIP; + + //ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ +//rum_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, +//559 ic->ic_channels); + + + uint8_t bands[IEEE80211_MODE_BYTES]; + memset(bands, 0, sizeof(bands)); + setbit(bands, IEEE80211_MODE_11B); +// setbit(bands, IEEE80211_MODE_11G); + ieee80211_add_channels_default_2ghz(ic->ic_channels, IEEE80211_CHAN_MAX, &ic->ic_nchans, bands, 0); + + // Set the MAC address + uint8_t macaddr[6] = {0x00, 0x12, 0x34, 0x56, 0x78, 0x9a}; + IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); + + ieee80211_ifattach(ic); + // Counter-intuitively, these must be added afterwards because there are default ieee80211com handlers + ic->ic_parent = i3e_template_parent; // Defines what happens when a driver goes up/down + ic->ic_scan_start = i3e_template_scan_start; // Puts the device into scan-mode + ic->ic_scan_end = i3e_template_scan_end; // Removes device from scan-mode + ic->ic_vap_create = i3e_template_vap_create; + ic->ic_vap_delete = i3e_template_vap_delete; + ic->ic_set_channel = i3e_template_set_channel; + ic->ic_raw_xmit = i3e_template_raw_xmit; + ic->ic_update_mcast = i3e_template_update_mcast; + + ieee80211_announce(ic); + + return 0; +} + +static int i3e_event_handler(struct module *module, int event_type, void *arg) { + + int retval = 0; // function returns an integer error code, default 0 for OK + + switch (event_type) { // event_type is an enum; let's switch on it + case MOD_LOAD: // if we're loading + sc = malloc(sizeof(struct i3e_template_softc), M_80211_VAP, M_WAITOK | M_ZERO); + i3e_template_attach(sc); + uprintf("LKM Loaded\n"); // spit out a loading message + break; + + case MOD_UNLOAD: // if were unloading + uprintf("LKM Unloaded\n"); // spit out an unloading messge + i3e_template_detach(sc); + break; + + default: // if we're doing anything else + retval = EOPNOTSUPP; // return a 'not supported' error + break; + } + + return(retval); // return the appropriate value + +} + +static moduledata_t i3e_data = { + "i3e_template", // Name of our module + i3e_event_handler, // Name of our module's 'event handler' function + NULL // Ignore for now :) +}; + +// Register the module with the kernel using: +// the module name +// our recently defined moduledata_t struct with module info +// a module type (we're daying it's a driver this time) +// a preference as to when to load the module +DECLARE_MODULE(freebsd_i3e, i3e_data, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); diff --git a/i3e_template_driver.h b/i3e_template_driver.h new file mode 100644 index 0000000..bdc54c8 --- /dev/null +++ b/i3e_template_driver.h @@ -0,0 +1,112 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Farhan Khan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This is a template driver for FreeBSD's net80211 layer. + * This is intended as a learning tool on the minimum implementation + * of the net80211 layer entirely in software. + * + * This driver does not implement the USB, PCIe or SDIO layers, which would ordinarily + * be responsible for the match, power on/off, state management, etc. Instead, this code + * implements everything in software. + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////// Header File + +/* + * BSD drivers store driver instance-specific variables in their "softc" + * structure. + */ +struct i3e_template_softc { + struct ieee80211com sc_ic; // Used to store methods of how the base OS interacts with the driver andr how it interacts with VAP + struct mtx sc_mtx; // Device-wide locking mutex + + int sc_detached; + int sc_running; +}; + +static struct i3e_template_softc *sc; + +struct i3e_template_vap { + struct ieee80211vap vap; + int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); +}; + +//#define I3E_TEMPLATE_LOCK_INIT(_sc) mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->sc_dev), MTX_NETWORK_LOCK, MTX_DEF); +#define I3E_TEMPLATE_LOCK_INIT(_sc) mtx_init(&(sc)->sc_mtx, "i3e0", MTX_NETWORK_LOCK, MTX_DEF); +#define I3E_TEMPLATE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define I3E_TEMPLATE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) + +#define I3E_TEMPLATE_VAP(vap) ((struct i3e_template_vap *)(vap))