Teach if_smsc to get MAC from bootargs.

Some Raspberry Pi pass smsc95xx.macaddr=XX:XX:XX:XX:XX:XX as bootargs.
Use this if no ethernet address is found in an EEPROM.
As last resort fall back to ether_gen_addr() instead of random MAC.

PR:	274092
Reported by:	Patrick M. Hausen (via ML)
Reviewed by:	imp, karels, zlei
Tested by:	Patrick M. Hausen
Approved by:	karels
MFC after:	1 month
Relnotes:	yes
Differential Revision: https://reviews.freebsd.org/D42463
This commit is contained in:
Ronald Klop 2023-11-04 15:14:00 +01:00
parent 5c8b07fe84
commit 3878bbf1bb
3 changed files with 92 additions and 5 deletions

View file

@ -179,6 +179,8 @@ static const struct usb_device_id smsc_devs[] = {
#define ETHER_IS_VALID(addr) \
(!ETHER_IS_MULTICAST(addr) && !ETHER_IS_ZERO(addr))
#define BOOTARGS_SMSC95XX "smsc95xx.macaddr"
static device_probe_t smsc_probe;
static device_attach_t smsc_attach;
static device_detach_t smsc_detach;
@ -1538,6 +1540,76 @@ smsc_ioctl(if_t ifp, u_long cmd, caddr_t data)
return (rc);
}
#ifdef FDT
static bool
smsc_get_smsc95xx_macaddr(char* bootargs, size_t len, struct usb_ether *ue)
{
int values[6];
int i;
char* p;
p = strnstr(bootargs, BOOTARGS_SMSC95XX, len);
if (p == NULL)
return (false);
if (sscanf(p, BOOTARGS_SMSC95XX "=%x:%x:%x:%x:%x:%x%*c",
&values[0], &values[1], &values[2],
&values[3], &values[4], &values[5]) != 6) {
smsc_warn_printf((struct smsc_softc *)ue->ue_sc,
"invalid mac from bootargs '%s'.\n", p);
return (false);
}
for (i = 0; i < ETHER_ADDR_LEN; ++i)
ue->ue_eaddr[i] = values[i];
smsc_dbg_printf((struct smsc_softc *)ue->ue_sc,
"bootargs mac=%6D.\n", ue->ue_eaddr, ":");
return (true);
}
/**
* Raspberry Pi is known to pass smsc95xx.macaddr=XX:XX:XX:XX:XX:XX via
* bootargs.
*/
static bool
smsc_bootargs_get_mac_addr(device_t dev, struct usb_ether *ue)
{
char *bootargs;
ssize_t len;
phandle_t node;
/* only use bootargs for the first device
* to prevent duplicate mac addresses */
if (device_get_unit(dev) != 0)
return (false);
node = OF_finddevice("/chosen");
if (node == -1)
return (false);
if (OF_hasprop(node, "bootargs") == 0) {
smsc_dbg_printf((struct smsc_softc *)ue->ue_sc,
"bootargs not found");
return (false);
}
len = OF_getprop_alloc(node, "bootargs", (void **)&bootargs);
if (len == -1 || bootargs == NULL) {
smsc_warn_printf((struct smsc_softc *)ue->ue_sc,
"failed alloc for bootargs (%lu)", len);
return (false);
}
smsc_dbg_printf((struct smsc_softc *)ue->ue_sc, "bootargs: %s.\n",
bootargs);
if (!smsc_get_smsc95xx_macaddr(bootargs, len, ue)) {
OF_prop_free(bootargs);
return (false);
}
OF_prop_free(bootargs);
device_printf(dev, "MAC address found in bootargs %6D.\n",
ue->ue_eaddr, ":");
return (true);
}
#endif
/**
* smsc_attach_post - Called after the driver attached to the USB interface
* @ue: the USB ethernet device
@ -1552,8 +1624,10 @@ static void
smsc_attach_post(struct usb_ether *ue)
{
struct smsc_softc *sc = uether_getsc(ue);
struct ether_addr eaddr;
uint32_t mac_h, mac_l;
int err;
int i;
smsc_dbg_printf(sc, "smsc_attach_post\n");
@ -1585,11 +1659,17 @@ smsc_attach_post(struct usb_ether *ue)
#ifdef FDT
if ((err != 0) || (!ETHER_IS_VALID(sc->sc_ue.ue_eaddr)))
err = usb_fdt_get_mac_addr(sc->sc_ue.ue_dev, &sc->sc_ue);
if ((err != 0) || (!ETHER_IS_VALID(sc->sc_ue.ue_eaddr)))
err = smsc_bootargs_get_mac_addr(sc->sc_ue.ue_dev,
&sc->sc_ue) ? (0) : (1);
#endif
if ((err != 0) || (!ETHER_IS_VALID(sc->sc_ue.ue_eaddr))) {
read_random(sc->sc_ue.ue_eaddr, ETHER_ADDR_LEN);
sc->sc_ue.ue_eaddr[0] &= ~0x01; /* unicast */
sc->sc_ue.ue_eaddr[0] |= 0x02; /* locally administered */
smsc_dbg_printf(sc, "No MAC address found."
" Using ether_gen_addr().\n");
ether_gen_addr_byname(device_get_nameunit(ue->ue_dev),
&eaddr);
for (i = 0; i < ETHER_ADDR_LEN; i++)
sc->sc_ue.ue_eaddr[i] = eaddr.octet[i];
}
}

View file

@ -448,6 +448,7 @@ struct mbuf *ether_vlanencap_proto(struct mbuf *, uint16_t, uint16_t);
bool ether_8021q_frame(struct mbuf **mp, struct ifnet *ife,
struct ifnet *p, const struct ether_8021q_tag *);
void ether_gen_addr(struct ifnet *ifp, struct ether_addr *hwaddr);
void ether_gen_addr_byname(const char *nameunit, struct ether_addr *hwaddr);
static __inline struct mbuf *ether_vlanencap(struct mbuf *m, uint16_t tag)
{

View file

@ -1487,7 +1487,7 @@ ether_8021q_frame(struct mbuf **mp, struct ifnet *ife, struct ifnet *p,
* allocate non-locally-administered addresses.
*/
void
ether_gen_addr(struct ifnet *ifp, struct ether_addr *hwaddr)
ether_gen_addr_byname(const char *nameunit, struct ether_addr *hwaddr)
{
SHA1_CTX ctx;
char *buf;
@ -1506,7 +1506,7 @@ ether_gen_addr(struct ifnet *ifp, struct ether_addr *hwaddr)
/* If each (vnet) jail would also have a unique hostuuid this would not
* be necessary. */
getjailname(curthread->td_ucred, jailname, sizeof(jailname));
sz = asprintf(&buf, M_TEMP, "%s-%s-%s", uuid, if_name(ifp),
sz = asprintf(&buf, M_TEMP, "%s-%s-%s", uuid, nameunit,
jailname);
if (sz < 0) {
/* Fall back to a random mac address. */
@ -1535,5 +1535,11 @@ ether_gen_addr(struct ifnet *ifp, struct ether_addr *hwaddr)
hwaddr->octet[0] |= 0x02;
}
void
ether_gen_addr(struct ifnet *ifp, struct ether_addr *hwaddr)
{
ether_gen_addr_byname(if_name(ifp), hwaddr);
}
DECLARE_MODULE(ether, ether_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
MODULE_VERSION(ether, 1);