firmware icon indicating copy to clipboard operation
firmware copied to clipboard

g_ether wont apply host mac address

Open xbipin opened this issue 8 years ago • 35 comments

i have the below in my cmdline.txt file modules-load=dwc2,g_ether g_ether.dev_addr=8e:7a:7e:37:6f:bb g_ether.host_addr=8e:7a:7e:37:6f:aa

the problem is it applies the dev_addr mac id to usb0 but the host_addr doesnt apply at all so the PC sees a random mac id always.

im on the latest kernel 4.9.37

xbipin avatar Jul 18 '17 10:07 xbipin

it does on a windows machine but not on a freebsd machine even though its recognized as a RNDIS gadget

xbipin avatar Jul 18 '17 10:07 xbipin

When I had a similar issue I needed to add g_ether.use_eem=0 so the other (Linux in my case) end used cdc_ether rather than cdc_eem where IIRC the protocol doesn't support passing a MAC address - might be worth a try.

burtyb avatar Jul 18 '17 12:07 burtyb

i tried but its still same, below is what appears in freebsd

ugen0.2: <Linux 4.9.37+ with 20980000.usb> at usbus0 cdce0: <RNDIS Communications Control> on usbus0 cdce0: No valid alternate setting found device_attach: cdce0 attach returned 6 cdce0: <RNDIS Ethernet Data> on usbus0 cdce0: faking MAC address ue0: <USB Ethernet> on cdce0 ue0: Ethernet address: 2a:3f:38:a3:80:00

i added that inline in the cmdline.txt, correct me if im wrong

xbipin avatar Jul 18 '17 13:07 xbipin

is there a way to set a vendor and product id so freebsd can recognize it as a know device so it can read the mac id which the rndis gadget supplies?

xbipin avatar Jul 19 '17 06:07 xbipin

Hi, I am starting using usb gadget, and if I understand well, there are 2 ways to configure gadget mode. First is yours (in first post), the other is by using libcomposite. I followed this tutorial for gadget configuration, and it seams that you can easily replace each bits...

maitredede avatar Nov 22 '17 02:11 maitredede

This issue will be closed within 30 days unless further interactions are posted. If you wish this issue to remain open, please add a comment. A closed issue may be reopened if requested.

JamesH65 avatar Jan 11 '19 16:01 JamesH65

I can confirm that this bug still exists on Raspberry Pi Zero. The g_ether module will randomly not respect the host_addr option given to it, regardless if using the kernel command line, an option file in modprobe.d or simply "modprobe g_ether host_addr=00:11:22:33:44:55". All three approaches work only intermittently. More often than not, the host will have a randomly generated MAC regardless of what was specified.

Interestingly, the syslog output of the module seems to reflect that soemthing is wrong with the MAC generation internally:

Jul 23 08:50:59 raspberrypi kernel: [   82.963954] using random self ethernet address
Jul 23 08:50:59 raspberrypi kernel: [   82.963978] using random host ethernet address
Jul 23 08:50:59 raspberrypi kernel: [   82.963994] using host ethernet address: 00:22:82:ff:ff:20 **## This is the one I manually specified, so should be correct**
Jul 23 08:50:59 raspberrypi kernel: [   82.964000] using self ethernet address: 16:78:91:65:a2:e9
Jul 23 08:50:59 raspberrypi kernel: [   82.965526] usb0: HOST MAC 00:22:82:ff:ff:20
Jul 23 08:50:59 raspberrypi kernel: [   82.966796] usb0: MAC 16:78:91:65:a2:e9
Jul 23 08:50:59 raspberrypi kernel: [   82.966870] using random self ethernet address
Jul 23 08:50:59 raspberrypi kernel: [   82.966885] using random host ethernet address **## contradictory**
Jul 23 08:50:59 raspberrypi kernel: [   82.966992] g_ether gadget: Ethernet Gadget, version: Memorial Day 2008
Jul 23 08:50:59 raspberrypi kernel: [   82.967005] g_ether gadget: g_ether ready
Jul 23 08:50:59 raspberrypi kernel: [   82.967025] dwc2 20980000.usb: bound driver g_ether

After this output usb0 had a random MAC on the host side. This makes it very hard to have a predictable DHCP setup. I would kindly ask that you reopen this issue.

gmcn42 avatar Jul 23 '20 08:07 gmcn42

Also having this issue w/most current pi zero build. host_addr is ignored.

Worked around it by manually greping dmesg after boot, mapping the port to the connected device and then configuring manually. This is not ideal and defeats the purpose of hotplugging.

Please reopen.

smanley avatar Oct 07 '20 05:10 smanley

this needs to be reopened

xbipin avatar Oct 07 '20 15:10 xbipin

I did some more looking into this; I had the specified host_addr appear once after unplugging and plugging in the pi; it isn't consistent, though suggesting some sort of race maybe. It never worked from a cold boot, e.g. booting the host system and the pi at the same time.

It would be really sweet if this worked properly, using pi zeros as camera peripherals.

It appears this issue has existed for some time?

smanley avatar Oct 07 '20 15:10 smanley

Alright - I'll take a look.

pelwell avatar Oct 07 '20 15:10 pelwell

Much appreciated and happy to help debug.

smanley avatar Oct 07 '20 15:10 smanley

I can confirm that Windows see the specified MAC address while Linux (at least running on a host Pi) doesn't.

pelwell avatar Oct 08 '20 10:10 pelwell

No - it does work. On the client side:

pi@raspberrypi:~$ ifconfig usb0
usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
...
        ether 8e:7a:7e:37:6f:bb  txqueuelen 1000  (Ethernet)

and on the host side:

pi@raspberrypi:~$ ifconfig usb0
usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
...
        ether 8e:7a:7e:37:6f:aa  txqueuelen 1000  (Ethernet)

But I'm not losing my grip (or rather, this isn't evidence of it) - scrolling back through the terminal window there is this from the host:

pi@raspberrypi:~$ ifconfig usb0
usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
...
        ether 92:82:a7:22:9f:8b  txqueuelen 1000  (Ethernet)

This suggests there is some unreset state or a race condition - more testing required.

pelwell avatar Oct 08 '20 10:10 pelwell

For me the problem cropped up seemingly randomly. Like maybe 60% of client-side boots?

gmcn42 avatar Oct 08 '20 10:10 gmcn42

I see the same variability using a Ubuntu guest OS in VirtualBox on Windows 10. After a clean boot the gadget appears as:

usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 9e:e2:45:3d:87:ef  txqueuelen 1000  (Ethernet)

And after assigning the USB device to Windows then back to VB:

enx8e7a7e376faa: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 8e:7a:7e:37:6f:aa  txqueuelen 1000  (Ethernet)

Comparing the lsusb -v dumps in both cases shows no difference apart from the device ID:

2c2
< Bus 001 Device 003: ID 0525:a4a2 Netchip Technology, Inc. Linux-USB Ethernet/RNDIS Gadget
---
> Bus 001 Device 004: ID 0525:a4a2 Netchip Technology, Inc. Linux-USB Ethernet/RNDIS Gadget

In both cases the MAC address is set correctly:

        iMacAddress                      9 8e7a7e376faa

All of this is without rebooting the device.

This suggests that the problem is with the host. not the gadget.

pelwell avatar Oct 08 '20 10:10 pelwell

Seems to be correct, I just cross-checked by connecting my setup to a Win 10 laptop and rebooting the Pi a few times. No random MACs yet.

So I guess this might actually be a bug in the cdc_ether Linux kernel module?

gmcn42 avatar Oct 08 '20 12:10 gmcn42

Something in that area. I think it might be a race between cdc_ether and cdc_subset. The first connection after rebooting the host usually fails:

[   47.208348] usb 1-2: new full-speed USB device number 3 using ohci-pci
[   47.513114] usb 1-2: config 2 interface 1 altsetting 0 endpoint 0x81 has invalid maxpacket 512, setting to 64
[   47.513120] usb 1-2: config 2 interface 1 altsetting 0 endpoint 0x1 has invalid maxpacket 512, setting to 64
[   47.524942] usb 1-2: config 1 interface 1 altsetting 1 endpoint 0x81 has invalid maxpacket 512, setting to 64
[   47.524948] usb 1-2: config 1 interface 1 altsetting 1 endpoint 0x1 has invalid maxpacket 512, setting to 64
[   47.544437] usb 1-2: New USB device found, idVendor=0525, idProduct=a4a2, bcdDevice= 5.04
[   47.544443] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[   47.544447] usb 1-2: Product: RNDIS/Ethernet Gadget
[   47.544450] usb 1-2: Manufacturer: Linux 5.4.69-v7l+ with fe980000.usb
[   47.587024] cdc_subset: probe of 1-2:1.0 failed with error -22
[   47.597021] cdc_subset 1-2:1.1 usb0: register 'cdc_subset' at usb-0000:00:06.0-2, Linux Device, 9e:c2:ca:91:86:42
[   47.597160] cdc_ether: probe of 1-2:1.0 failed with error -16
[   47.597261] usbcore: registered new interface driver cdc_ether
[   47.597696] usbcore: registered new interface driver cdc_subset

Subsequent attempts after disconnecting and reconnecting the device succeed:

[  147.137283] usb 1-2: new full-speed USB device number 4 using ohci-pci
[  147.434651] usb 1-2: config 2 interface 1 altsetting 0 endpoint 0x81 has invalid maxpacket 512, setting to 64
[  147.434653] usb 1-2: config 2 interface 1 altsetting 0 endpoint 0x1 has invalid maxpacket 512, setting to 64
[  147.444380] usb 1-2: config 1 interface 1 altsetting 1 endpoint 0x81 has invalid maxpacket 512, setting to 64
[  147.444381] usb 1-2: config 1 interface 1 altsetting 1 endpoint 0x1 has invalid maxpacket 512, setting to 64
[  147.464957] usb 1-2: New USB device found, idVendor=0525, idProduct=a4a2, bcdDevice= 5.04
[  147.464959] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[  147.464961] usb 1-2: Product: RNDIS/Ethernet Gadget
[  147.464962] usb 1-2: Manufacturer: Linux 5.4.69-v7l+ with fe980000.usb
[  147.476850] cdc_subset: probe of 1-2:1.0 failed with error -22
[  147.496033] cdc_ether 1-2:1.0 usb0: register 'cdc_ether' at usb-0000:00:06.0-2, CDC Ethernet Device, 8e:7a:7e:37:6f:aa
[  147.512149] cdc_ether 1-2:1.0 enx8e7a7e376faa: renamed from usb0

The probe by cdc_subset of 1-2:1.0 always fails with -22 (-EINVAL), but on that first attempt, it succeeds in probing 1-2:1.1. which I think is what causes cdc_ether to get -16 (-EBUSY). After then, 1-2:1.1 isn't heard of again, and cdc_ether probes successfully.

It's hard to see how the device can know that a particular connect is after a reboot, which again points the finger at the host.

pelwell avatar Oct 08 '20 12:10 pelwell

i had filed a bug request on freebsd which can be found here https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=220852

xbipin avatar Oct 09 '20 05:10 xbipin

i had filed a bug request on freebsd which can be found here https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=220852

The workaround at the end involves manually unloading the cdc ethernet module for a urndis driver to work. I am doubtful this is applicable to Linux. I guess we need to test against a current upstream host kernel and then file a report to https://bugzilla.kernel.org if the problem is still there.

cdc_ether seems to have had some recent development (https://github.com/torvalds/linux/blob/master/drivers/net/usb/cdc_ether.c). The last host Kernel version I can definitely confirm this bug on is 5.4.0. When I have time I can install a VM with current upstream Kernel and check.

gmcn42 avatar Oct 09 '20 07:10 gmcn42

I can confirm this is happening on Debian 10. (4.19.0-11-amd64)

I noticed there are different cdc drivers appearing, although the device works in all cases; just has a random mac.

I can't come up with a replicable process for the mac address appearing. The assigned mac appeared maybe 3/20 times I've been working on it. It does appear to be a race condition of some type.

smanley avatar Oct 09 '20 13:10 smanley

This issue is affecting me too, on latest Raspberry Pi OS.

martini1992 avatar Dec 04 '20 11:12 martini1992

I stand by my comment above (https://github.com/raspberrypi/firmware/issues/843#issuecomment-705493047): I think the problem is a generic Linux problem with the host, and the Pi is doing nothing wrong.

pelwell avatar Dec 04 '20 12:12 pelwell

Well in this instance my host is Openwrt 19.07, running kernel 4.14.156, still Linux I know but older than your confirmed cases. Seems odd to me that the host is causing the devices host side MAC to be randomised.

martini1992 avatar Dec 04 '20 12:12 martini1992

Ok, on my Ubuntu box kernel 5.4.0-56-generic. I'm trying the same SD image with a different Pi Zero (W this time previous one was plain Zero) and it's reliably setting the host MAC every boot (replug).

The logs seem to look identical to previous ones posted.

Dec  3 09:03:23 pihole kernel: [    7.624136] random: systemd: uninitialized urandom read (16 bytes read)
Dec  3 09:03:23 pihole kernel: [    9.615557] dwc2 20980000.usb: 20980000.usb supply vusb_d not found, using dummy regulator
Dec  3 09:03:23 pihole kernel: [    9.624512] dwc2 20980000.usb: 20980000.usb supply vusb_a not found, using dummy regulator
Dec  3 09:03:23 pihole kernel: [    9.854236] dwc2 20980000.usb: EPs: 8, dedicated fifos, 4080 entries in SPRAM
Dec  3 09:03:23 pihole kernel: [    9.857502] dwc2 20980000.usb: DWC OTG Controller
Dec  3 09:03:23 pihole kernel: [    9.859392] dwc2 20980000.usb: new USB bus registered, assigned bus number 1
Dec  3 09:03:23 pihole kernel: [    9.861271] dwc2 20980000.usb: irq 33, io mem 0x20980000
Dec  3 09:03:23 pihole kernel: [    9.914783] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 5.04
Dec  3 09:03:23 pihole kernel: [    9.918471] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
Dec  3 09:03:23 pihole kernel: [    9.920390] usb usb1: Product: DWC OTG Controller
Dec  3 09:03:23 pihole kernel: [    9.922293] usb usb1: Manufacturer: Linux 5.4.72+ dwc2_hsotg
Dec  3 09:03:23 pihole kernel: [    9.924323] usb usb1: SerialNumber: 20980000.usb
Dec  3 09:03:23 pihole kernel: [    9.975944] hub 1-0:1.0: USB hub found
Dec  3 09:03:23 pihole kernel: [    9.984057] hub 1-0:1.0: 1 port detected
Dec  3 09:03:23 pihole kernel: [   10.702167] using random self ethernet address
Dec  3 09:03:23 pihole kernel: [   10.704229] using random host ethernet address
Dec  3 09:03:23 pihole kernel: [   10.705987] using host ethernet address: 46:7a:67:a8:3f:1b
Dec  3 09:03:23 pihole kernel: [   10.726007] usb0: HOST MAC 46:7a:67:a8:3f:1b
Dec  3 09:03:23 pihole kernel: [   10.744347] usb0: MAC 0a:c0:8b:c6:b7:c7
Dec  3 09:03:23 pihole kernel: [   10.746126] using random self ethernet address
Dec  3 09:03:23 pihole kernel: [   10.747703] using random host ethernet address
Dec  3 09:03:23 pihole kernel: [   10.749330] g_ether gadget: Ethernet Gadget, version: Memorial Day 2008
Dec  3 09:03:23 pihole kernel: [   10.750906] g_ether gadget: g_ether ready
Dec  3 09:03:23 pihole kernel: [   10.752398] dwc2 20980000.usb: bound driver g_ether
Dec  3 09:03:23 pihole kernel: [   11.878106] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
Dec  3 09:03:23 pihole kernel: [   17.185194] vc_sm_cma: module is from the staging directory, the quality is unknown, you have been warned.
Dec  3 09:03:23 pihole kernel: [   17.188144] bcm2835_vc_sm_cma_probe: Videocore shared memory driver

martini1992 avatar Dec 04 '20 14:12 martini1992

Ok, so this is truly bizarre. I plugged the Zero I was having issues with into my laptop a few times, and the MAC appeared stable. Now plugging it back into my Openwrt box and its stable there too. The logs look identical to how they did above. I'll keep an eye on it and see if it starts happening again.

martini1992 avatar Dec 04 '20 14:12 martini1992

I'm experiencing the same problem, using a Raspberry Pi 4 Model B as host and four Raspberry Pi Zero devices as USB Ethernet gadgets.

I'm using the Pi4 as a base station to collect sensor data over I2C over distances of several meters. The Pi0s collect the I2C sensor data and the Pi4 in turn polls it from the Pi0s. Providing power and data connection with the same cable reduces complexity of setup and thus seemed like a win.

On the Pi0s, I use the g_ether options to set a persistent MAC address for each device. On the Pi4, I use udev rules to attribute network interface names based on the persistent MAC addresses, and the DHCP client configuration to attribute the correct point-to-point network to each Pi0. In theory, this would allow dynamic adding/removing of sensor endpoints (Pi0s) by simply plugging/unplugging, with some extra tooling.

When I unplug/replug the Pi4, the problem discussed here is reproduced with high probability. Most of the time, the first device (first udev rule, lowest network numbers) will load as usb0 instead of the custom interface name. When that happen, the MAC address on the host is random, rather than the pre-configured one.

Unplugging/replugging the Pi0 solves the problem most of the time. As there are two additional problems (unreliable booting of the Pi0, possibly due to low voltage or SD card unreliability, as well as unreachable Pi0, even if booted with correct MAC/IP) that could be solved in the same manner, I started looking into simulating unplugging/replugging through software.

Unfortunately, the Pi4 USB hubs do not support per-port power supply (PPPS), meaning that toggling power off and on again (uhubctl tool does an excellent job here) is equivalent to a reboot of all 4 Pi0 devices. I'm currently waiting for 4 external USB hubs that should support PPPS to test whether I can reliably work around the MAC address and other issues by switching the power on the respective USB ports off and on again.

If this turns out successful, I will write a tool to automatically do so until all devices are successfully connected. However, in order to reduce startup time of the system, it would be great if the problem were solved at its source. What are the next steps here? How can this be moved forward?

awfm9 avatar Jan 07 '21 15:01 awfm9

Another datapoint. I thought I was going nuts. I am nowhere as knowledgeable as the others here. Running Linux Mint 20.1 and hardcoding the MAC addresses in cmdline.txt as done by xbipin When plugging in a Zero, half of the time, it will show as usb0 and half of the time, it will have the MAC address. Unplugging and replugging will solve the problem.

ieee488 avatar Mar 07 '21 03:03 ieee488

I came across this issue after a lot of searching. Looking at the latest tree ref. It's late where I am so this analysis might suck, but let's see how this fits.

Here's where we get these debug messages in the kernel from u_ether.c:

	if (get_ether_addr(dev_addr, net->dev_addr))
		dev_warn(&g->dev,
			"using random %s ethernet address\n", "self");
	if (get_ether_addr(host_addr, dev->host_mac))
		dev_warn(&g->dev,
			"using random %s ethernet address\n", "host");

The function is expecting a return true value from the call to get_ether_addr(). Tracing that down we find:

// u_ether.c
static int get_ether_addr(const char *str, u8 *dev_addr)
{
	if (str) {
		unsigned	i;

		for (i = 0; i < 6; i++) {
			unsigned char num;

			if ((*str == '.') || (*str == ':'))
				str++;
			num = hex_to_bin(*str++) << 4;
			num |= hex_to_bin(*str++);
			dev_addr [i] = num;
		}
		if (is_valid_ether_addr(dev_addr))      // <--- this function returns 'true' if it is valid
			return 0;                                      // which means, we return 'false' to avoid the print, so we're falling through?
	}
	eth_random_addr(dev_addr);
	return 1;
}

So ... some how we're falling through. As indicated by others, it feels very random, so if you trace the is_valid_ether_addr() function, you'll find this comment:

/**
 * is_valid_ether_addr - Determine if the given Ethernet address is valid
 * @addr: Pointer to a six-byte array containing the Ethernet address
 *
 * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not
 * a multicast address, and is not FF:FF:FF:FF:FF:FF.
 *
 * Return true if the address is valid.
 *
 * Please note: addr must be aligned to u16.     //<< ----- ummmm ... i don't think that's promised by u_ether.c?
 */
static inline bool is_valid_ether_addr(const u8 *addr)
{
	/* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to
	 * explicitly check for it here. */
	return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);
}

So then we look at the is_multicast_ether_addr() and we see that indeed, we need to make sure that's aligned because ....

/**
 * is_multicast_ether_addr - Determine if the Ethernet address is a multicast.
 * @addr: Pointer to a six-byte array containing the Ethernet address
 *
 * Return true if the address is a multicast address.
 * By definition the broadcast address is also a multicast address.
 */
static inline bool is_multicast_ether_addr(const u8 *addr)
{
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
	u32 a = *(const u32 *)addr;
#else
	u16 a = *(const u16 *)addr;
#endif
#ifdef __BIG_ENDIAN
	return 0x01 & (a >> ((sizeof(a) * 8) - 8));
#else
	return 0x01 & a;
#endif
}

So I think there's two issues at play, one for the people like me not paying attention ... and then one more difficult:

  1. In my world, I tried the following MAC taken from the internet c1:12:f5:d4:a9:b4 which resulted in failure. I then updated to c4:12:f5:d4:a9:b4 and it assigned correctly because of course, it is now not really a multicast address after I remember the LSB is a 0x01 and causing the check to fail. Same with some of the other MACs that I'm seeing above because they're technically multicast.
  2. Because of the alignment, you could result in casting the incorrect 16 bits of memory and become unlucky enough and fail the check. I don't think there's any promise of 16 bit alignment unless you indicate it within the struct eth_dev: https://elixir.bootlin.com/linux/v5.11.10/source/drivers/usb/gadget/function/u_ether.c#L83 ... but that would be a super unlucky day I think.

Additionally, there is a possible oddness here that results in no checks in the gether_setup_name_default() for the dev_addr and host_addr. This functions should probably be updated to matche the gether_setup_name() that's above it.

Hope that helps.

wyattearp avatar Mar 27 '21 03:03 wyattearp

Now that I've had more time to look at the code, there's a lot of duplicated stuff in the u_ether.c which is probably what's really driving the heart of the issue. I think there's probably 3 separate updates that need to be made, but i'm not familiar enough with the gadget interface to be confident that I can make these changes without breaking the world.

Suggested updates:

  1. The g_ether usb gadget will accept a multicast mac as a parameter, but silently fail and then generate a random one. It would be easy enough to put a dmesg that stops 90% of people from picking bad addresses at the expense of an extra set of calls during setup because it's really not that expensive.
  2. The comparison has a very low probability of screwing up because the values in the struct are not promised to be u16 aligned, but the functions count on that to happen, but the function does say it should be aligned if it's used. Adding a __attribute__ ((aligned (16))) to the arrays at the end of the struct eth_dev will probably stop any of these issues from arising.
  3. The gether_setup_name_default should probably go away and be replaced with an updated call to gether_setup_name like the other functions in the u_ether.h header so that there's only 1 code path for setting up a gadget.

I'd be happy to make these patches, but again - I'm not super familiar with the rest of the gadget interface so I don't know if there are going to be unintended consequences of my recommendations. Any feedback would be appreciated.

wyattearp avatar Mar 27 '21 12:03 wyattearp