diff --git a/headers/private/net/net_datalink_protocol.h b/headers/private/net/net_datalink_protocol.h index 9d7caee966..edaa94b4d4 100644 --- a/headers/private/net/net_datalink_protocol.h +++ b/headers/private/net/net_datalink_protocol.h @@ -30,6 +30,11 @@ struct net_datalink_protocol_module_info { status_t (*control)(net_datalink_protocol *self, int32 op, void *argument, size_t length); + + status_t (*join_multicast)(net_datalink_protocol *self, + const sockaddr *address); + status_t (*leave_multicast)(net_datalink_protocol *self, + const sockaddr *address); }; #endif // NET_DATALINK_PROTOCOL_H diff --git a/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp b/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp index 691593fa33..b8e9b6eadc 100644 --- a/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp +++ b/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp @@ -248,6 +248,32 @@ arp_entry::MarkValid() } +static void +ipv4_to_ether_multicast(sockaddr_dl *destination, const sockaddr_in *source) +{ + // RFC 1112 - Host extensions for IP multicasting + // + // ``An IP host group address is mapped to an Ethernet multicast + // address by placing the low-order 23-bits of the IP address into + // the low-order 23 bits of the Ethernet multicast address + // 01-00-5E-00-00-00 (hex).'' + + memcpy(((uint8 *)destination->sdl_data) + 2, &source->sin_addr, + sizeof(in_addr)); + + destination->sdl_len = sizeof(sockaddr_dl); + destination->sdl_family = AF_DLI; + destination->sdl_index = 0; + destination->sdl_type = IFT_ETHER; + destination->sdl_e_type = ETHER_TYPE_IP; + destination->sdl_nlen = destination->sdl_slen = 0; + destination->sdl_alen = ETHER_ADDRESS_LENGTH; + + uint32 *data = (uint32 *)destination->sdl_data; + data[0] = (data[0] & htonl(0x7f)) | htonl(0x01005e00); +} + + // #pragma mark - @@ -791,28 +817,11 @@ arp_send_data(net_datalink_protocol *protocol, entry->hardware_address.sdl_len); if (buffer->flags & MSG_MCAST) { - // RFC 1112 - Host extensions for IP multicasting - // - // ``An IP host group address is mapped to an Ethernet multicast - // address by placing the low-order 23-bits of the IP address into - // the low-order 23 bits of the Ethernet multicast address - // 01-00-5E-00-00-00 (hex).'' - - sockaddr_dl *destination = (sockaddr_dl *)&buffer->destination; - - memmove(((uint8 *)destination->sdl_data) + 2, - &((sockaddr_in *)&buffer->destination)->sin_addr, sizeof(in_addr)); - - destination->sdl_len = sizeof(sockaddr_dl); - destination->sdl_family = AF_DLI; - destination->sdl_index = 0; - destination->sdl_type = IFT_ETHER; - destination->sdl_e_type = ETHER_TYPE_IP; - destination->sdl_nlen = destination->sdl_slen = 0; - destination->sdl_alen = ETHER_ADDRESS_LENGTH; - - uint32 *data = (uint32 *)destination->sdl_data; - data[0] = (data[0] & htonl(0x7f)) | htonl(0x01005e00); + sockaddr_dl multicastDestination; + ipv4_to_ether_multicast(&multicastDestination, + (sockaddr_in *)&buffer->destination); + memcpy(&buffer->destination, &multicastDestination, + sizeof(multicastDestination)); } else if ((buffer->flags & MSG_BCAST) == 0) { // Lookup destination (we may need to wait for this) entry = arp_entry::Lookup( @@ -927,6 +936,34 @@ arp_control(net_datalink_protocol *protocol, } +static status_t +arp_join_multicast(net_datalink_protocol *protocol, const sockaddr *address) +{ + if (address->sa_family != AF_INET) + return EINVAL; + + sockaddr_dl multicastAddress; + ipv4_to_ether_multicast(&multicastAddress, (const sockaddr_in *)address); + + return protocol->next->module->join_multicast(protocol->next, + (sockaddr *)&multicastAddress); +} + + +static status_t +arp_leave_multicast(net_datalink_protocol *protocol, const sockaddr *address) +{ + if (address->sa_family != AF_INET) + return EINVAL; + + sockaddr_dl multicastAddress; + ipv4_to_ether_multicast(&multicastAddress, (const sockaddr_in *)address); + + return protocol->next->module->leave_multicast(protocol->next, + (sockaddr *)&multicastAddress); +} + + static status_t arp_std_ops(int32 op, ...) { @@ -954,6 +991,8 @@ static net_datalink_protocol_module_info sARPModule = { arp_up, arp_down, arp_control, + arp_join_multicast, + arp_leave_multicast, }; diff --git a/src/add-ons/kernel/network/datalink_protocols/ethernet_frame/ethernet_frame.cpp b/src/add-ons/kernel/network/datalink_protocols/ethernet_frame/ethernet_frame.cpp index 9668e6fbf7..3708d33e8f 100644 --- a/src/add-ons/kernel/network/datalink_protocols/ethernet_frame/ethernet_frame.cpp +++ b/src/add-ons/kernel/network/datalink_protocols/ethernet_frame/ethernet_frame.cpp @@ -169,6 +169,22 @@ ethernet_frame_control(net_datalink_protocol *protocol, } +static status_t +ethernet_frame_join_multicast(net_datalink_protocol *protocol, + const sockaddr *address) +{ + return protocol->next->module->join_multicast(protocol, address); +} + + +static status_t +ethernet_frame_leave_multicast(net_datalink_protocol *protocol, + const sockaddr *address) +{ + return protocol->next->module->leave_multicast(protocol, address); +} + + static status_t ethernet_frame_std_ops(int32 op, ...) { @@ -197,6 +213,8 @@ static net_datalink_protocol_module_info sEthernetFrameModule = { ethernet_frame_up, ethernet_frame_down, ethernet_frame_control, + ethernet_frame_join_multicast, + ethernet_frame_leave_multicast, }; module_info *modules[] = { diff --git a/src/add-ons/kernel/network/datalink_protocols/loopback_frame/loopback_frame.cpp b/src/add-ons/kernel/network/datalink_protocols/loopback_frame/loopback_frame.cpp index c7af0a51a5..8d78514f85 100644 --- a/src/add-ons/kernel/network/datalink_protocols/loopback_frame/loopback_frame.cpp +++ b/src/add-ons/kernel/network/datalink_protocols/loopback_frame/loopback_frame.cpp @@ -130,6 +130,22 @@ loopback_frame_control(net_datalink_protocol *protocol, } +static status_t +loopback_frame_join_multicast(net_datalink_protocol *protocol, + const sockaddr *address) +{ + return protocol->next->module->join_multicast(protocol, address); +} + + +static status_t +loopback_frame_leave_multicast(net_datalink_protocol *protocol, + const sockaddr *address) +{ + return protocol->next->module->leave_multicast(protocol, address); +} + + static status_t loopback_frame_std_ops(int32 op, ...) { @@ -158,6 +174,8 @@ static net_datalink_protocol_module_info sLoopbackFrameModule = { loopback_frame_up, loopback_frame_down, loopback_frame_control, + loopback_frame_join_multicast, + loopback_frame_leave_multicast, }; module_info *modules[] = { diff --git a/src/add-ons/kernel/network/stack/datalink.cpp b/src/add-ons/kernel/network/stack/datalink.cpp index 78ab15cbcd..8de2541fda 100644 --- a/src/add-ons/kernel/network/stack/datalink.cpp +++ b/src/add-ons/kernel/network/stack/datalink.cpp @@ -799,6 +799,24 @@ interface_protocol_control(net_datalink_protocol *_protocol, } +static status_t +interface_protocol_join_multicast(net_datalink_protocol *_protocol, + const sockaddr *address) +{ + // TODO + return EINVAL; +} + + +static status_t +interface_protocol_leave_multicast(net_datalink_protocol *_protocol, + const sockaddr *address) +{ + // TODO + return EINVAL; +} + + net_datalink_module_info gNetDatalinkModule = { { NET_DATALINK_MODULE_NAME, @@ -835,4 +853,6 @@ net_datalink_protocol_module_info gDatalinkInterfaceProtocolModule = { interface_protocol_up, interface_protocol_down, interface_protocol_control, + interface_protocol_join_multicast, + interface_protocol_leave_multicast, };