Code builds, basic handlers in place, some documentation

This commit is contained in:
farhan 2023-11-29 17:32:36 -05:00
commit a32a5403e7
Signed by: farhan
GPG Key ID: 45FE45AD7E54F59B
6 changed files with 555 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
opt_global.h
exort_syms
*.swp
*.ko
*.o

24
LICENSE Normal file
View File

@ -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.

6
Makefile Normal file
View File

@ -0,0 +1,6 @@
KMOD= i3e_template_driver
SRCS= i3e_template_driver.c
DCOPTFLAGS+= -g -O0
.include <bsd.kmod.mk>

41
README.md Normal file
View File

@ -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)

367
i3e_template_driver.c Normal file
View File

@ -0,0 +1,367 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* 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.
*/
/*
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/endian.h>
#include <sys/kdb.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_regdomain.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_ratectl.h>
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <sys/malloc.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
#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);

112
i3e_template_driver.h Normal file
View File

@ -0,0 +1,112 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* 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.
*/
/*
* 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 <sys/cdefs.h>
#include <sys/param.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/socket.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/endian.h>
#include <sys/kdb.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_regdomain.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_ratectl.h>
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <sys/malloc.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
/////////////////////////// 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))