/*! Creates a permanent local entry for the interface belonging to this protocol. You need to hold the cache lock when calling this function. */ static status_t arp_update_local(arp_protocol *protocol) { ASSERT_LOCKED_MUTEX(&sCacheLock); net_interface *interface = protocol->interface; in_addr_t inetAddress; if (interface->address == NULL) { // interface has not yet been set inetAddress = INADDR_ANY; } else inetAddress = ((sockaddr_in *)interface->address)->sin_addr.s_addr; sockaddr_dl address; address.sdl_len = sizeof(sockaddr_dl); address.sdl_family = AF_LINK; address.sdl_type = IFT_ETHER; address.sdl_e_type = ETHER_TYPE_IP; address.sdl_nlen = 0; address.sdl_slen = 0; address.sdl_alen = interface->device->address.length; memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen); memcpy(&protocol->hardware_address, &address, sizeof(sockaddr_dl)); // cache the address in our protocol arp_entry *entry; status_t status = arp_update_entry(inetAddress, &address, ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry); if (status == B_OK) entry->protocol = protocol; return status; }
static void handle_arp_reply(net_buffer *buffer, arp_header &header) { if (sIgnoreReplies) return; MutexLocker locker(sCacheLock); arp_update_entry(header.protocol_sender, (sockaddr_dl *)buffer->source, 0); }
static status_t handle_arp_request(net_buffer *buffer, arp_header &header) { MutexLocker locker(sCacheLock); if (!sIgnoreReplies) { arp_update_entry(header.protocol_sender, (sockaddr_dl *)buffer->source, 0); // remember the address of the sender as we might need it later } // check if this request is for us arp_entry *entry = arp_entry::Lookup(header.protocol_target); if (entry == NULL || (entry->flags & (ARP_FLAG_LOCAL | ARP_FLAG_PUBLISH)) == 0) { // We're not the one to answer this request // TODO: instead of letting the other's request time-out, can we reply // failure somehow? TRACE((" not for us\n")); return B_ERROR; } // send a reply (by reusing the buffer we got) TRACE((" send reply!\n")); header.opcode = htons(ARP_OPCODE_REPLY); memcpy(header.hardware_target, header.hardware_sender, ETHER_ADDRESS_LENGTH); header.protocol_target = header.protocol_sender; memcpy(header.hardware_sender, LLADDR(&entry->hardware_address), ETHER_ADDRESS_LENGTH); header.protocol_sender = entry->protocol_address; // exchange source and destination address memcpy(LLADDR((sockaddr_dl *)buffer->source), header.hardware_sender, ETHER_ADDRESS_LENGTH); memcpy(LLADDR((sockaddr_dl *)buffer->destination), header.hardware_target, ETHER_ADDRESS_LENGTH); buffer->flags = 0; // make sure this won't be a broadcast message return entry->protocol->next->module->send_data(entry->protocol->next, buffer); }
static status_t arp_set_local_entry(arp_protocol* protocol, const sockaddr* local) { MutexLocker locker(sCacheLock); net_interface* interface = protocol->interface; in_addr_t inetAddress; if (local == NULL) { // interface has not yet been set inetAddress = INADDR_ANY; } else inetAddress = ((sockaddr_in*)local)->sin_addr.s_addr; TRACE(("%s(): address %s\n", __FUNCTION__, inet_to_string(inetAddress))); if (protocol->local_address == 0) protocol->local_address = inetAddress; sockaddr_dl address; address.sdl_len = sizeof(sockaddr_dl); address.sdl_family = AF_LINK; address.sdl_type = IFT_ETHER; address.sdl_e_type = htons(ETHER_TYPE_IP); address.sdl_nlen = 0; address.sdl_slen = 0; address.sdl_alen = interface->device->address.length; memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen); memcpy(&protocol->hardware_address, &address, sizeof(sockaddr_dl)); // cache the address in our protocol arp_entry* entry; status_t status = arp_update_entry(inetAddress, &address, ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry); if (status == B_OK) entry->protocol = protocol; return status; }
static status_t arp_control(const char *subsystem, uint32 function, void *buffer, size_t bufferSize) { struct arp_control control; if (bufferSize != sizeof(struct arp_control)) return B_BAD_VALUE; if (user_memcpy(&control, buffer, sizeof(struct arp_control)) < B_OK) return B_BAD_ADDRESS; MutexLocker locker(sCacheLock); switch (function) { case ARP_SET_ENTRY: { sockaddr_dl hardwareAddress; hardwareAddress.sdl_len = sizeof(sockaddr_dl); hardwareAddress.sdl_family = AF_LINK; hardwareAddress.sdl_index = 0; hardwareAddress.sdl_type = IFT_ETHER; hardwareAddress.sdl_e_type = ETHER_TYPE_IP; hardwareAddress.sdl_nlen = hardwareAddress.sdl_slen = 0; hardwareAddress.sdl_alen = ETHER_ADDRESS_LENGTH; memcpy(hardwareAddress.sdl_data, control.ethernet_address, ETHER_ADDRESS_LENGTH); return arp_update_entry(control.address, &hardwareAddress, control.flags & (ARP_FLAG_PUBLISH | ARP_FLAG_PERMANENT | ARP_FLAG_REJECT)); } case ARP_GET_ENTRY: { arp_entry *entry = arp_entry::Lookup(control.address); if (entry == NULL || !(entry->flags & ARP_FLAG_VALID)) return B_ENTRY_NOT_FOUND; if (entry->hardware_address.sdl_alen == ETHER_ADDRESS_LENGTH) { memcpy(control.ethernet_address, entry->hardware_address.sdl_data, ETHER_ADDRESS_LENGTH); } else memset(control.ethernet_address, 0, ETHER_ADDRESS_LENGTH); control.flags = entry->flags & ARP_PUBLIC_FLAG_MASK; return user_memcpy(buffer, &control, sizeof(struct arp_control)); } case ARP_GET_ENTRIES: { hash_iterator iterator; hash_open(sCache, &iterator); arp_entry *entry; uint32 i = 0; while ((entry = (arp_entry *)hash_next(sCache, &iterator)) != NULL && i < control.cookie) { i++; } hash_close(sCache, &iterator, false); if (entry == NULL) return B_ENTRY_NOT_FOUND; control.cookie++; control.address = entry->protocol_address; if (entry->hardware_address.sdl_alen == ETHER_ADDRESS_LENGTH) { memcpy(control.ethernet_address, entry->hardware_address.sdl_data, ETHER_ADDRESS_LENGTH); } else memset(control.ethernet_address, 0, ETHER_ADDRESS_LENGTH); control.flags = entry->flags & ARP_PUBLIC_FLAG_MASK; return user_memcpy(buffer, &control, sizeof(struct arp_control)); } case ARP_DELETE_ENTRY: { arp_entry *entry = arp_entry::Lookup(control.address); if (entry == NULL) return B_ENTRY_NOT_FOUND; if ((entry->flags & ARP_FLAG_LOCAL) != 0) return B_BAD_VALUE; entry->ScheduleRemoval(); return B_OK; } case ARP_FLUSH_ENTRIES: { hash_iterator iterator; hash_open(sCache, &iterator); arp_entry *entry; while ((entry = (arp_entry *)hash_next(sCache, &iterator)) != NULL) { // we never flush local ARP entries if ((entry->flags & ARP_FLAG_LOCAL) != 0) continue; entry->ScheduleRemoval(); } hash_close(sCache, &iterator, false); return B_OK; } case ARP_IGNORE_REPLIES: sIgnoreReplies = control.flags != 0; return B_OK; } return B_BAD_VALUE; }