I would suggest starting by trying to configure and build a NetBSD kernel.
BSD kernels have a unique and cool (imo :3) file format that defines a kind of device tree for setting compile-time options and drivers built into the kernel or as modules (in the case of FreeBSD and NetBSD). See here for the file format: https://man.netbsd.org/config.5 and here: https://man.netbsd.org/NetBSD-11.0/options.4 for misc but important compile-time options (which are set as preprocessor defines like #define BEANIS). Traditionally, machine-specific kernel configurations (like the NetBSD amd64 kernel config) include a more generic configuration that contains options that are set for all architectures. The reason I bring this up is because the way device drivers are compiled by the bespoke BSD build system (collection of makefiles primary found under /src/share/mk relative to the CVS repo root) and made known to the kernel at runtime is via that file (indirectly, it tells the autoconfiguration framework that walks down the device tree what drivers it should attach if it matches a device ID or what drivers it should call to probe for their respective devices).
So, basically, if you want to add your new network interface driver you would insert a line into the kernel configuration (usually the architecture specific one) like:
cupcakeif* at pci? dev ? function ? (assuming your interface is attached via PCI bus ^w^)
which, when the relevant bus is configured, causes the autoconf framework to call that driver's "match" function (assuming you can directly configure your driver without having to probe for it) for every device on the bus. If your driver thinks it's relevant to that device and should be loaded your match function would return > 0. At which point that driver's "attach" function is called to setup the device. You can refer to this manpage for more details on device driver definition and how it interacts with the autoconf framework: https://man.netbsd.org/driver.9 (as well as how all this info and function pointers even get to the autoconf framework >w< it's a structure initialized with the CFATTACH_DECL_NEW macro described in that manpage)
You can see an example of all of this in the already existing WiFi interface drivers under /src/sys/dev/pci.
For example, the classic athn Atheros wifi interface defined in if_athn_pci.c (which I would suggest generously copy-pasting from :3):
long (edited for brevity)
/* ... */
CFATTACH_DECL_NEW(athn_pci, sizeof(struct athn_pci_softc), athn_pci_match,
athn_pci_attach, athn_pci_detach, athn_pci_activate);
/* ... */
Static int
athn_pci_match(device_t parent, cfdata_t match, void *aux)
{
static const struct {
pci_vendor_id_t apd_vendor;
pci_product_id_t apd_product;
} athn_pci_devices[] = {
{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5416 },
{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR5418 },
{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9160 },
{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9280 },
{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9281 },
{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9285 },
{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR2427 },
{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9227 },
{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9287 },
{ PCI_VENDOR_ATHEROS, PCI_PRODUCT_ATHEROS_AR9300 }
};
struct pci_attach_args *pa = aux;
size_t i;
for (i = 0; i < __arraycount(athn_pci_devices); i++) {
if (PCI_VENDOR(pa->pa_id) == athn_pci_devices[i].apd_vendor &&
PCI_PRODUCT(pa->pa_id) == athn_pci_devices[i].apd_product)
/*
* Match better than 1, we prefer this driver
* over ath(4)
*/
return 10;
}
return 0;
}
Static void
athn_pci_attach(device_t parent, device_t self, void *aux)
{
/* ... */
}
Besides the generic device driver infrastructure, the other kernel infrastructure you will probably most interact with is the WiFi specific network interface glue/helper code described in https://man.netbsd.org/ieee80211.9 which does varies things like allow userspace to set encryption keys, specify access points to associate with, set media modes, etc, implement the generic ethernet interface API, etc etc
It's getting late and I rly need to go to bed but I hope this helps a little >w< It can get very complicated cuz this codebase is older than Linux and prolly even older than most surviving commercial Unixes. The ppl on the NetBSD IRC and mailing list (also maybe a Telegram group or two) will help you out if you need! Also I'll be around later. My experience is mainly in the OpenBSD codebase but OpenBSD is a fork of NetBSD and although they've diverged significantly they still share a lot of code and there are a few ppl that have copy-pasted code between them over the years (in a comradely manner)
Oh, one last tip! If you get confused or stuck with documentation, consider referring to OpenBSD documentation or code cuz the coverage (at least with userspace stuff.......) and quality tends to be better
If there's a Linux driver for your device, referring to it could help u a lot too as long as you're willing to put up with uhhhhh less than good code quality x3
Also, also: the index for the NetBSD kernel documentation: https://man.netbsd.org/intro.9 :3
Happy hacking!!