Post

Replies

Boosts

Views

Activity

Reply to Access to MAC addresses of local network interfaces in macOS 27
AVDECC has been renamed to ATDECC a while ago, since AVB (Audio Video Bridging) was renamed to TSN (Time Sensitive Networking). ATDECC is basically an evolution of AVDECC. So your search was spot on. Sometimes both therms are used as synonyms. AVDECC / ATDECC is using the AVTP Ethertype 0x22f0, so I would assume that this should work for us. I will give it a try and see how far I can get with it. Thanks again!
Aug ’26
Reply to Access to MAC addresses of local network interfaces in macOS 27
Hi Quinn, thanks for the quick reply. We will look into using this entitlement, then. While we were investigating this, we stumbeeld upon NWEthernetChannel. It seems like it might be a good idea to migrate to using NWEthernetChannel in the future onmacOS. If so, what about the entitlement com.apple.developer.networking.custom-protocol. Is this available to all Apple developers, too? And further: if we moved to using NWEthernetChannel, would we still have to keep using access_bpf group and LaunchDaemon to grant access to the bpf interfaces? Or would this be covered by the entitlement? Thanks Arno
Aug ’26
Reply to Access to MAC addresses of local network interfaces in macOS 27
Looks like the file content doesn't display correctly. Here it is again. // clang++ -std=c++23 -o ifprobe ifprobe.cpp && ./ifprobe #include <ifaddrs.h> #include <net/bpf.h> #include <net/if.h> #include <net/if_dl.h> #include <net/route.h> #include <sys/ioctl.h> #include <sys/sockio.h> #include <sys/sysctl.h> #include <fcntl.h> #include <unistd.h> #include <cerrno> #include <cstdio> #include <cstring> #include <string> #include <vector> static int open_bpf() { for ( int i = 0; i < 256; ++i ) { std::string p = "/dev/bpf" + std::to_string( i ); int fd = open( p.c_str(), O_RDWR ); if ( fd != -1 ) return fd; if ( errno != EBUSY ) break; } return -1; } static const char* functional_type_name( unsigned t ) { switch ( t ) { case IFRTYPE_FUNCTIONAL_LOOPBACK: return "LOOPBACK"; case IFRTYPE_FUNCTIONAL_WIRED: return "WIRED"; case IFRTYPE_FUNCTIONAL_WIFI_INFRA: return "WIFI_INFRA"; case IFRTYPE_FUNCTIONAL_WIFI_AWDL: return "WIFI_AWDL"; case IFRTYPE_FUNCTIONAL_CELLULAR: return "CELLULAR"; default: return "UNKNOWN"; } } static size_t sockaddr_aligned_size(const sockaddr* address) { if (address->sa_len == 0) return sizeof(long); return (address->sa_len + sizeof(long) - 1) & ~(sizeof(long) - 1); } static void print_sysctl_mac(const char* name) { const unsigned int index = if_nametoindex(name); if (index == 0) { printf(" sysctl_mac=<unknown interface>"); return; } int mib[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, static_cast<int>(index) }; size_t length = 0; if (sysctl(mib, 6, nullptr, &length, nullptr, 0) != 0) { printf(" sysctl_mac=<size query failed errno=%d>", errno); return; } std::vector<unsigned char> buffer(length); if (sysctl(mib, 6, buffer.data(), &length, nullptr, 0) != 0) { printf(" sysctl_mac=<read failed errno=%d>", errno); return; } auto* message = reinterpret_cast<const if_msghdr*>(buffer.data()); const auto* address = reinterpret_cast<const sockaddr*>( message + 1); for (int address_index = 0; address_index < RTAX_MAX; ++address_index) { if ((message->ifm_addrs & (1 << address_index)) == 0) continue; if (address_index == RTAX_IFP && address->sa_family == AF_LINK) { auto* link_address = reinterpret_cast<const sockaddr_dl*>(address); if (link_address->sdl_alen == 6) { const auto* mac = reinterpret_cast<const unsigned char*>( LLADDR(link_address)); printf(" sysctl_mac=%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return; } } address = reinterpret_cast<const sockaddr*>( reinterpret_cast<const unsigned char*>(address) + sockaddr_aligned_size(address)); } printf(" sysctl_mac=<unavailable>"); } int main() { ifaddrs* ifap = nullptr; if ( getifaddrs( &ifap ) != 0 ) return 1; int probe = socket( AF_INET, SOCK_DGRAM, 0 ); for ( ifaddrs* p = ifap; p; p = p->ifa_next ) { if ( !p->ifa_addr || p->ifa_addr->sa_family != AF_LINK ) continue; auto* dl = reinterpret_cast< sockaddr_dl* >( p->ifa_addr ); unsigned ftype = 0; ifreq fr{}; strncpy( fr.ifr_name, p->ifa_name, IFNAMSIZ - 1 ); if ( ioctl( probe, SIOCGIFFUNCTIONALTYPE, &fr ) == 0 ) ftype = fr.ifr_ifru.ifru_functional_type; // BIOCGDLT is the decisive check: DLT_EN10MB means our 14-byte Ethernet header is correct framing. int dlt = -1; int fd = open_bpf(); if ( fd >= 0 ) { ifreq br{}; strncpy( br.ifr_name, p->ifa_name, IFNAMSIZ - 1 ); if ( ioctl( fd, BIOCSETIF, &br ) == 0 ) ioctl( fd, BIOCGDLT, &dlt ); close( fd ); } printf( "%-10s maclen=%-2u ftype=%-11s dlt=%-3d up=%d running=%d ", p->ifa_name, dl->sdl_alen, functional_type_name( ftype ), dlt, ( p->ifa_flags & IFF_UP ) != 0, ( p->ifa_flags & IFF_RUNNING ) != 0 ); print_sysctl_mac(p->ifa_name); printf("\n"); } close( probe ); freeifaddrs( ifap ); }
Aug ’26
Reply to Network Framework Broadcast Support
Hi Quinn, yeah, I know... :-) These devices are still in use by our customers, but have been out of support for quite some time. The last firmware update was 7 years ago. So, it is, what it is. :-) But thanks for the clarification anyways. Do you think, that there will be changes in the Network Framework to support this kind of traffic? Or is this out of scope? Thanks Arno
Sep ’24
Reply to Access to MAC addresses of local network interfaces in macOS 27
AVDECC has been renamed to ATDECC a while ago, since AVB (Audio Video Bridging) was renamed to TSN (Time Sensitive Networking). ATDECC is basically an evolution of AVDECC. So your search was spot on. Sometimes both therms are used as synonyms. AVDECC / ATDECC is using the AVTP Ethertype 0x22f0, so I would assume that this should work for us. I will give it a try and see how far I can get with it. Thanks again!
Replies
Boosts
Views
Activity
Aug ’26
Reply to Access to MAC addresses of local network interfaces in macOS 27
Hi Quinn, thanks for the quick reply. We will look into using this entitlement, then. While we were investigating this, we stumbeeld upon NWEthernetChannel. It seems like it might be a good idea to migrate to using NWEthernetChannel in the future onmacOS. If so, what about the entitlement com.apple.developer.networking.custom-protocol. Is this available to all Apple developers, too? And further: if we moved to using NWEthernetChannel, would we still have to keep using access_bpf group and LaunchDaemon to grant access to the bpf interfaces? Or would this be covered by the entitlement? Thanks Arno
Replies
Boosts
Views
Activity
Aug ’26
Reply to Access to MAC addresses of local network interfaces in macOS 27
Looks like the file content doesn't display correctly. Here it is again. // clang++ -std=c++23 -o ifprobe ifprobe.cpp && ./ifprobe #include <ifaddrs.h> #include <net/bpf.h> #include <net/if.h> #include <net/if_dl.h> #include <net/route.h> #include <sys/ioctl.h> #include <sys/sockio.h> #include <sys/sysctl.h> #include <fcntl.h> #include <unistd.h> #include <cerrno> #include <cstdio> #include <cstring> #include <string> #include <vector> static int open_bpf() { for ( int i = 0; i < 256; ++i ) { std::string p = "/dev/bpf" + std::to_string( i ); int fd = open( p.c_str(), O_RDWR ); if ( fd != -1 ) return fd; if ( errno != EBUSY ) break; } return -1; } static const char* functional_type_name( unsigned t ) { switch ( t ) { case IFRTYPE_FUNCTIONAL_LOOPBACK: return "LOOPBACK"; case IFRTYPE_FUNCTIONAL_WIRED: return "WIRED"; case IFRTYPE_FUNCTIONAL_WIFI_INFRA: return "WIFI_INFRA"; case IFRTYPE_FUNCTIONAL_WIFI_AWDL: return "WIFI_AWDL"; case IFRTYPE_FUNCTIONAL_CELLULAR: return "CELLULAR"; default: return "UNKNOWN"; } } static size_t sockaddr_aligned_size(const sockaddr* address) { if (address->sa_len == 0) return sizeof(long); return (address->sa_len + sizeof(long) - 1) & ~(sizeof(long) - 1); } static void print_sysctl_mac(const char* name) { const unsigned int index = if_nametoindex(name); if (index == 0) { printf(" sysctl_mac=<unknown interface>"); return; } int mib[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, static_cast<int>(index) }; size_t length = 0; if (sysctl(mib, 6, nullptr, &length, nullptr, 0) != 0) { printf(" sysctl_mac=<size query failed errno=%d>", errno); return; } std::vector<unsigned char> buffer(length); if (sysctl(mib, 6, buffer.data(), &length, nullptr, 0) != 0) { printf(" sysctl_mac=<read failed errno=%d>", errno); return; } auto* message = reinterpret_cast<const if_msghdr*>(buffer.data()); const auto* address = reinterpret_cast<const sockaddr*>( message + 1); for (int address_index = 0; address_index < RTAX_MAX; ++address_index) { if ((message->ifm_addrs & (1 << address_index)) == 0) continue; if (address_index == RTAX_IFP && address->sa_family == AF_LINK) { auto* link_address = reinterpret_cast<const sockaddr_dl*>(address); if (link_address->sdl_alen == 6) { const auto* mac = reinterpret_cast<const unsigned char*>( LLADDR(link_address)); printf(" sysctl_mac=%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return; } } address = reinterpret_cast<const sockaddr*>( reinterpret_cast<const unsigned char*>(address) + sockaddr_aligned_size(address)); } printf(" sysctl_mac=<unavailable>"); } int main() { ifaddrs* ifap = nullptr; if ( getifaddrs( &ifap ) != 0 ) return 1; int probe = socket( AF_INET, SOCK_DGRAM, 0 ); for ( ifaddrs* p = ifap; p; p = p->ifa_next ) { if ( !p->ifa_addr || p->ifa_addr->sa_family != AF_LINK ) continue; auto* dl = reinterpret_cast< sockaddr_dl* >( p->ifa_addr ); unsigned ftype = 0; ifreq fr{}; strncpy( fr.ifr_name, p->ifa_name, IFNAMSIZ - 1 ); if ( ioctl( probe, SIOCGIFFUNCTIONALTYPE, &fr ) == 0 ) ftype = fr.ifr_ifru.ifru_functional_type; // BIOCGDLT is the decisive check: DLT_EN10MB means our 14-byte Ethernet header is correct framing. int dlt = -1; int fd = open_bpf(); if ( fd >= 0 ) { ifreq br{}; strncpy( br.ifr_name, p->ifa_name, IFNAMSIZ - 1 ); if ( ioctl( fd, BIOCSETIF, &br ) == 0 ) ioctl( fd, BIOCGDLT, &dlt ); close( fd ); } printf( "%-10s maclen=%-2u ftype=%-11s dlt=%-3d up=%d running=%d ", p->ifa_name, dl->sdl_alen, functional_type_name( ftype ), dlt, ( p->ifa_flags & IFF_UP ) != 0, ( p->ifa_flags & IFF_RUNNING ) != 0 ); print_sysctl_mac(p->ifa_name); printf("\n"); } close( probe ); freeifaddrs( ifap ); }
Replies
Boosts
Views
Activity
Aug ’26
Reply to Network Framework Broadcast Support
Hi Quinn, yeah, I know... :-) These devices are still in use by our customers, but have been out of support for quite some time. The last firmware update was 7 years ago. So, it is, what it is. :-) But thanks for the clarification anyways. Do you think, that there will be changes in the Network Framework to support this kind of traffic? Or is this out of scope? Thanks Arno
Replies
Boosts
Views
Activity
Sep ’24