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); }
status_t arp_send_data(net_datalink_protocol *_protocol, net_buffer *buffer) { arp_protocol *protocol = (arp_protocol *)_protocol; { MutexLocker locker(sCacheLock); // Set buffer target and destination address memcpy(buffer->source, &protocol->hardware_address, protocol->hardware_address.sdl_len); if ((buffer->flags & MSG_MCAST) != 0) { 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) arp_entry *entry = arp_entry::Lookup( ((struct sockaddr_in *)buffer->destination)->sin_addr.s_addr); if (entry == NULL) { status_t status = arp_start_resolve(protocol, ((struct sockaddr_in*)buffer->destination)->sin_addr.s_addr, &entry); if (status != B_OK) return status; } if ((entry->flags & ARP_FLAG_REJECT) != 0) return EHOSTUNREACH; if ((entry->flags & ARP_FLAG_VALID) == 0) { // entry is still being resolved. TRACE(("ARP Queuing packet %p, entry still being resolved.\n", buffer)); entry->queue.Add(buffer); return B_OK; } memcpy(buffer->destination, &entry->hardware_address, entry->hardware_address.sdl_len); } // the broadcast address is set in the ethernet frame module } TRACE(("%s(%p): from %s\n", __FUNCTION__, buffer, mac_to_string(LLADDR((sockaddr_dl*)buffer->source)))); TRACE((" to %s\n", mac_to_string(LLADDR((sockaddr_dl*)buffer->destination)))); return protocol->next->module->send_data(protocol->next, buffer); }