From b8ff248f6595067ef9a31d5d4cec5fb9b9052fc3 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Wed, 30 Nov 2022 15:10:05 -0700 Subject: [PATCH] stand/ofw: Subclass devnet to cope with ofw's unique needs We need to match devices in a slightly special way: We have to look up the path and see if the device is a 'network' device in order to use it. Sponsored by: Netflix Tested by: grehan@ (with tweaks to my original patch) Differential Revision: https://reviews.freebsd.org/D37557 --- stand/libofw/libofw.h | 1 + stand/libofw/ofw_net.c | 75 ++++++++++++++++++++++++++++++++++++++++ stand/powerpc/ofw/conf.c | 2 +- 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/stand/libofw/libofw.h b/stand/libofw/libofw.h index 0494a78135e7..ce7e6e986029 100644 --- a/stand/libofw/libofw.h +++ b/stand/libofw/libofw.h @@ -48,6 +48,7 @@ extern int ofw_getdev(void **vdev, const char *devspec, const char **path); extern ev_sethook_t ofw_setcurrdev; extern struct devsw ofwdisk; +extern struct devsw ofw_netdev; extern struct netif_driver ofwnet; int ofwn_getunit(const char *); diff --git a/stand/libofw/ofw_net.c b/stand/libofw/ofw_net.c index fa4a3abd88e8..59b9f8de7efb 100644 --- a/stand/libofw/ofw_net.c +++ b/stand/libofw/ofw_net.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include "libofw.h" #include "openfirm.h" static int ofwn_probe(struct netif *, void *); @@ -267,3 +268,77 @@ ofwn_getunit(const char *path) return -1; } #endif + +/* + * To properly match network devices, we have to subclass the netdev device. + * It has a different devdesc than a normal network device (which is fine: + * it's a struct superset) and different matching criteria (since it has to + * look at the path, find a handle and see if that handle is a network node + * or not). + */ + +static int ofwnd_init(void); +static int ofwnd_parsedev(struct devdesc **, const char *, const char **); +static bool ofwnd_match(struct devsw *, const char *); +static char *ofwnd_fmtdev(struct devdesc *); + +struct devsw ofw_netdev = { + .dv_name = "network", + .dv_type = DEVT_NET, + .dv_init = ofwnd_init, + .dv_match = ofwnd_match, + .dv_fmtdev = ofwnd_fmtdev, + .dv_parsedev = ofwnd_parsedev, +}; + +static int ofwnd_init(void) +{ + netdev.dv_init(); + ofw_netdev.dv_strategy = netdev.dv_strategy; + ofw_netdev.dv_open = netdev.dv_open; + ofw_netdev.dv_close = netdev.dv_close; + ofw_netdev.dv_ioctl = netdev.dv_ioctl; + ofw_netdev.dv_print = netdev.dv_print; + ofw_netdev.dv_fmtdev = netdev.dv_fmtdev; + /* parsedev is unique to ofwnd */ + /* match is unique to ofwnd */ + return (0); +} + +static int +ofwnd_parsedev(struct devdesc **dev, const char *devspec, const char **path) +{ + const char *rem_path; + struct ofw_devdesc *idev; + + if (ofw_path_to_handle(devspec, ofw_netdev.dv_name, &rem_path) == -1) + return (ENOENT); + idev = malloc(sizeof(struct ofw_devdesc)); + if (idev == NULL) { + printf("ofw_parsedev: malloc failed\n"); + return ENOMEM; + }; + strlcpy(idev->d_path, devspec, min(rem_path - devspec + 1, + sizeof(idev->d_path))); + if (dev != NULL) + *dev = &idev->dd; + if (path != NULL) + *path = rem_path; + return 0; +} + +static bool +ofwnd_match(struct devsw *devsw, const char *devspec) +{ + const char *path; + + return (ofw_path_to_handle(devspec, devsw->dv_name, &path) != -1); +} + +static char * +ofwnd_fmtdev(struct devdesc *idev) +{ + struct ofw_devdesc *dev = (struct ofw_devdesc *)idev; + + return (dev->d_path); +} diff --git a/stand/powerpc/ofw/conf.c b/stand/powerpc/ofw/conf.c index a472faeed97b..c2b28f4fe0f0 100644 --- a/stand/powerpc/ofw/conf.c +++ b/stand/powerpc/ofw/conf.c @@ -54,7 +54,7 @@ struct devsw *devsw[] = { &ofwdisk, #endif #if defined(LOADER_NET_SUPPORT) - &netdev, + &ofw_netdev, #endif NULL };