diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 5193afa2fe..064f0e1ce2 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -46,8 +46,8 @@ SYSTEM_BIN = "[" addattr alert arp base64 basename bash bc beep bootman bzip2 mkfifo mkfs mkindex mktemp modifiers mount mount_nfs mountvolume mv netcat netstat nl nohup notify nproc od open - passwd paste patch pathchk pc ping play playfile playsound playwav pr prio - printenv printf profile ps ptx pwd + passwd paste patch pathchk pc ping ping6 play playfile playsound playwav + pr prio printenv printf profile ps ptx pwd query quit rc readlink ReadOnlyBootPrompt reindex release renice rlog rm rmattr rmindex rmdir roster route @@ -105,10 +105,10 @@ SYSTEM_SERVERS = app_server cddb_daemon debug_server input_server mail_daemon ; SYSTEM_NETWORK_DEVICES = ethernet loopback ; -SYSTEM_NETWORK_DATALINK_PROTOCOLS = ethernet_frame arp loopback_frame - ipv4_datagram ; +SYSTEM_NETWORK_DATALINK_PROTOCOLS = ethernet_frame arp loopback_frame ; + #ipv6_datagram ; #SYSTEM_NETWORK_PPP = ipcp modem pap pppoe ; -SYSTEM_NETWORK_PROTOCOLS = ipv4 tcp udp icmp unix ; +SYSTEM_NETWORK_PROTOCOLS = ipv4 tcp udp icmp unix ; # icmp6 ipv6 ; SYSTEM_ADD_ONS_ACCELERANTS = $(X86_ONLY)radeon.accelerant $(X86_ONLY)nvidia.accelerant $(X86_ONLY)matrox.accelerant diff --git a/headers/posix/net/if.h b/headers/posix/net/if.h index f87648445e..4c64b8426c 100644 --- a/headers/posix/net/if.h +++ b/headers/posix/net/if.h @@ -1,5 +1,5 @@ /* - * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _NET_IF_H @@ -16,12 +16,6 @@ #define IFNAMSIZ IF_NAMESIZE -struct ifreq_parameter { - char base_name[IF_NAMESIZE]; - char device[128]; - uint8_t sub_type; -}; - struct ifreq_stream_stats { uint32_t packets; uint32_t errors; @@ -43,7 +37,6 @@ struct ifreq { struct sockaddr ifr_dstaddr; struct sockaddr ifr_broadaddr; struct sockaddr ifr_mask; - struct ifreq_parameter ifr_parameter; struct ifreq_stats ifr_stats; struct route_entry ifr_route; int ifr_flags; @@ -56,6 +49,14 @@ struct ifreq { }; }; +/* used with SIOCAIFADDR */ +struct ifaliasreq { + char ifra_name[IF_NAMESIZE]; + struct sockaddr_storage ifra_addr; + struct sockaddr_storage ifra_broadaddr; + struct sockaddr_storage ifra_mask; +}; + /* interface flags */ #define IFF_UP 0x0001 #define IFF_BROADCAST 0x0002 /* valid broadcast address */ diff --git a/headers/posix/sys/sockio.h b/headers/posix/sys/sockio.h index 0d6f4d3717..1f5ede9c13 100644 --- a/headers/posix/sys/sockio.h +++ b/headers/posix/sys/sockio.h @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007, Haiku Inc. All Rights Reserved. + * Copyright 2002-2010, Haiku Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _SYS_SOCKIO_H @@ -38,7 +38,6 @@ #define SIOCGETRT 8928 /* get route information for destination */ #define SIOCGIFSTATS 8929 /* get interface stats */ -#define SIOCGIFPARAM 8930 /* get interface parameter */ #define SIOCGIFTYPE 8931 /* get interface type */ #define SIOCSPACKETCAP 8932 /* Start capturing packets on an interface */ diff --git a/headers/private/net/net_buffer.h b/headers/private/net/net_buffer.h index 6e6deca3e0..6877c73865 100644 --- a/headers/private/net/net_buffer.h +++ b/headers/private/net/net_buffer.h @@ -18,14 +18,9 @@ typedef struct net_buffer { struct list_link link; - // TODO: we should think about moving the address fields into the buffer - // data itself via associated data or something like this. Or this - // structure as a whole, too... - struct sockaddr* source; struct sockaddr* destination; - struct net_interface* interface; - int32 type; + struct net_interface_address* interface_address; union { struct { uint16 start; @@ -33,6 +28,7 @@ typedef struct net_buffer { } fragment; uint32 sequence; uint32 offset; + int32 type; }; uint32 flags; uint32 size; diff --git a/headers/private/net/net_datalink.h b/headers/private/net/net_datalink.h index 5e905e78a0..48f8d155a1 100644 --- a/headers/private/net/net_datalink.h +++ b/headers/private/net/net_datalink.h @@ -1,5 +1,5 @@ /* - * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef NET_DATALINK_H @@ -18,84 +18,98 @@ typedef struct net_datalink_protocol net_datalink_protocol; -typedef struct net_domain { - const char *name; - int family; - struct list interfaces; - struct net_protocol_module_info *module; - struct net_address_module_info *address_module; +typedef struct net_domain { + const char* name; + int family; + + struct net_protocol_module_info* module; + struct net_address_module_info* address_module; } net_domain; -struct net_interface { - struct list_link link; - struct net_domain *domain; - struct net_device *device; - struct net_datalink_protocol *first_protocol; - struct net_datalink_protocol_module_info *first_info; +typedef struct net_interface_address { + struct net_domain* domain; + struct net_interface* interface; + struct sockaddr* local; + struct sockaddr* destination; + struct sockaddr* mask; +} net_interface_address; + +typedef struct net_interface { + struct net_device* device; char name[IF_NAMESIZE]; - struct sockaddr *address; - struct sockaddr *destination; - struct sockaddr *mask; uint32 index; uint32 flags; uint8 type; uint32 mtu; uint32 metric; -}; +} net_interface; -struct net_route { - struct sockaddr *destination; - struct sockaddr *mask; - struct sockaddr *gateway; +typedef struct net_route { + struct sockaddr* destination; + struct sockaddr* mask; + struct sockaddr* gateway; uint32 flags; uint32 mtu; - struct net_interface *interface; -}; + struct net_interface_address* interface_address; +} net_route; -struct net_route_info { +typedef struct net_route_info { struct list_link link; - struct net_route *route; + struct net_route* route; struct sockaddr address; -}; +} net_route_info; + struct net_datalink_module_info { module_info info; - status_t (*control)(struct net_domain *domain, int32 option, void *value, - size_t *_length); - status_t (*send_data)(struct net_route *route, struct net_buffer *buffer); - status_t (*send_datagram)(struct net_protocol *protocol, - struct net_domain *domain, struct net_buffer *buffer); + status_t (*control)(net_domain* domain, int32 option, void* value, + size_t* _length); + status_t (*send_data)(net_route* route, net_buffer* buffer); + status_t (*send_datagram)(struct net_protocol* protocol, + net_domain* domain, net_buffer* buffer); - bool (*is_local_address)(struct net_domain *domain, - const struct sockaddr *address, net_interface **_interface, - uint32 *_matchedType); - bool (*is_local_link_address)(struct net_domain *domain, bool unconfigured, - const struct sockaddr *address, net_interface **_interface); + bool (*is_local_address)(net_domain* domain, + const struct sockaddr* address, + net_interface_address** _interfaceAddress, + uint32* _matchedType); + bool (*is_local_link_address)(net_domain* domain, + bool unconfigured, const struct sockaddr* address, + net_interface_address** _interfaceAddress); - net_interface *(*get_interface)(struct net_domain *domain, uint32 index); - net_interface *(*get_interface_with_address)(struct net_domain *domain, - const struct sockaddr *address); + net_interface* (*get_interface)(net_domain* domain, uint32 index); + net_interface* (*get_interface_with_address)( + const struct sockaddr* address); + void (*put_interface)(net_interface* interface); + + net_interface_address* (*get_interface_address)( + const struct sockaddr* address); + bool (*get_next_interface_address)(net_interface* interface, + net_interface_address** _address); + void (*put_interface_address)(net_interface_address* address); + + status_t (*join_multicast)(net_interface* interface, + net_domain* domain, const struct sockaddr* address); + status_t (*leave_multicast)(net_interface* interface, + net_domain* domain, const struct sockaddr* address); // routes - status_t (*add_route)(struct net_domain *domain, - const struct net_route *route); - status_t (*remove_route)(struct net_domain *domain, - const struct net_route *route); - struct net_route *(*get_route)(struct net_domain *domain, - const struct sockaddr *address); - status_t (*get_buffer_route)(struct net_domain *domain, - struct net_buffer *buffer, struct net_route **_route); - void (*put_route)(struct net_domain *domain, struct net_route *route); + status_t (*add_route)(net_domain* domain, const net_route* route); + status_t (*remove_route)(net_domain* domain, const net_route* route); + net_route* (*get_route)(net_domain* domain, + const struct sockaddr* address); + status_t (*get_buffer_route)(net_domain* domain, + struct net_buffer* buffer, net_route** _route); + void (*put_route)(net_domain* domain, net_route* route); - status_t (*register_route_info)(struct net_domain *domain, - struct net_route_info *info); - status_t (*unregister_route_info)(struct net_domain *domain, - struct net_route_info *info); - status_t (*update_route_info)(struct net_domain *domain, - struct net_route_info *info); + status_t (*register_route_info)(net_domain* domain, + net_route_info* info); + status_t (*unregister_route_info)(net_domain* domain, + net_route_info* info); + status_t (*update_route_info)(net_domain* domain, + net_route_info* info); }; #define NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS 0x01 @@ -104,47 +118,58 @@ struct net_address_module_info { module_info info; uint32 flags; - status_t (*copy_address)(const sockaddr *from, sockaddr **to, - bool replaceWithZeros, const sockaddr *mask); + status_t (*copy_address)(const struct sockaddr* from, + struct sockaddr** to, bool replaceWithZeros, + const struct sockaddr* mask); - status_t (*mask_address)(const sockaddr *address, const sockaddr *mask, - sockaddr *result); + status_t (*mask_address)(const struct sockaddr* address, + const struct sockaddr* mask, struct sockaddr* result); - bool (*equal_addresses)(const sockaddr *a, const sockaddr *b); - bool (*equal_ports)(const sockaddr *a, const sockaddr *b); - bool (*equal_addresses_and_ports)(const sockaddr *a, const sockaddr *b); - bool (*equal_masked_addresses)(const sockaddr *a, const sockaddr *b, - const sockaddr *mask); - bool (*is_empty_address)(const sockaddr *address, bool checkPort); - bool (*is_same_family)(const sockaddr *address); + bool (*equal_addresses)(const struct sockaddr* a, + const struct sockaddr* b); + bool (*equal_ports)(const struct sockaddr* a, + const struct sockaddr* b); + bool (*equal_addresses_and_ports)(const struct sockaddr* a, + const struct sockaddr* b); + bool (*equal_masked_addresses)(const struct sockaddr* a, + const struct sockaddr* b, const struct sockaddr* mask); + bool (*is_empty_address)(const struct sockaddr* address, + bool checkPort); + bool (*is_same_family)(const struct sockaddr* address); - int32 (*first_mask_bit)(const sockaddr *mask); + int32 (*first_mask_bit)(const struct sockaddr* mask); - bool (*check_mask)(const sockaddr *address); + bool (*check_mask)(const struct sockaddr* address); - status_t (*print_address)(const sockaddr *address, char **buffer, - bool printPort); - status_t (*print_address_buffer)(const sockaddr *address, char *buffer, - size_t bufferSize, bool printPort); + status_t (*print_address)(const struct sockaddr* address, + char** buffer, bool printPort); + status_t (*print_address_buffer)(const struct sockaddr* address, + char* buffer, size_t bufferSize, bool printPort); - uint16 (*get_port)(const sockaddr *address); - status_t (*set_port)(sockaddr *address, uint16 port); + uint16 (*get_port)(const struct sockaddr* address); + status_t (*set_port)(struct sockaddr* address, uint16 port); - status_t (*set_to)(sockaddr *address, const sockaddr *from); - status_t (*set_to_empty_address)(sockaddr *address); - status_t (*set_to_defaults)(sockaddr *defaultMask, - sockaddr *defaultBroadcast, sockaddr *address, - sockaddr *netmask); + status_t (*set_to)(struct sockaddr* address, + const struct sockaddr* from); + status_t (*set_to_empty_address)(struct sockaddr* address); + status_t (*set_to_defaults)(struct sockaddr* defaultMask, + struct sockaddr* defaultBroadcast, + const struct sockaddr* address, + const struct sockaddr* netmask); - status_t (*update_to)(sockaddr *address, const sockaddr *from); + status_t (*update_to)(struct sockaddr* address, + const struct sockaddr* from); - uint32 (*hash_address_pair)(const sockaddr *ourAddress, - const sockaddr *peerAddress); + uint32 (*hash_address)(const struct sockaddr* address, + bool includePort); + uint32 (*hash_address_pair)(const struct sockaddr* ourAddress, + const struct sockaddr* peerAddress); - status_t (*checksum_address)(struct Checksum *checksum, - const sockaddr *address); + status_t (*checksum_address)(struct Checksum* checksum, + const struct sockaddr* address); - void (*get_loopback_address)(sockaddr *result); + void (*get_loopback_address)(struct sockaddr* result); }; + #endif // NET_DATALINK_H diff --git a/headers/private/net/net_datalink_protocol.h b/headers/private/net/net_datalink_protocol.h index edaa94b4d4..7df4d98593 100644 --- a/headers/private/net/net_datalink_protocol.h +++ b/headers/private/net/net_datalink_protocol.h @@ -1,5 +1,5 @@ /* - * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef NET_DATALINK_PROTOCOL_H @@ -10,31 +10,37 @@ typedef struct net_datalink_protocol { - struct net_datalink_protocol *next; - struct net_datalink_protocol_module_info *module; - struct net_interface *interface; + struct net_datalink_protocol* next; + struct net_datalink_protocol_module_info* module; + struct net_interface* interface; + struct net_domain* domain; } net_datalink_protocol; struct net_datalink_protocol_module_info { module_info info; - status_t (*init_protocol)(struct net_interface *interface, - net_datalink_protocol **_protocol); - status_t (*uninit_protocol)(net_datalink_protocol *self); + status_t (*init_protocol)(net_interface* interface, net_domain* domain, + net_datalink_protocol** _protocol); + status_t (*uninit_protocol)(net_datalink_protocol* self); - status_t (*send_data)(net_datalink_protocol *self, - net_buffer *buffer); + status_t (*send_data)(net_datalink_protocol* self, net_buffer* buffer); - status_t (*interface_up)(net_datalink_protocol *self); - void (*interface_down)(net_datalink_protocol *self); + status_t (*interface_up)(net_datalink_protocol* self); + void (*interface_down)(net_datalink_protocol* self); - status_t (*control)(net_datalink_protocol *self, - int32 op, void *argument, size_t length); + status_t (*change_address)(net_datalink_protocol* self, + net_interface_address* address, int32 option, + const struct sockaddr* oldAddress, + const struct sockaddr* newAddress); - status_t (*join_multicast)(net_datalink_protocol *self, - const sockaddr *address); - status_t (*leave_multicast)(net_datalink_protocol *self, - const sockaddr *address); + status_t (*control)(net_datalink_protocol* self, int32 option, + void* argument, size_t length); + + status_t (*join_multicast)(net_datalink_protocol* self, + const struct sockaddr* address); + status_t (*leave_multicast)(net_datalink_protocol* self, + const struct sockaddr* address); }; + #endif // NET_DATALINK_PROTOCOL_H diff --git a/src/add-ons/kernel/network/datalink_protocols/Jamfile b/src/add-ons/kernel/network/datalink_protocols/Jamfile index 177fc9cc71..4b212c11e2 100644 --- a/src/add-ons/kernel/network/datalink_protocols/Jamfile +++ b/src/add-ons/kernel/network/datalink_protocols/Jamfile @@ -1,7 +1,6 @@ SubDir HAIKU_TOP src add-ons kernel network datalink_protocols ; -SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols arp ; -SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ethernet_frame ; -SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ipv4_datagram ; -SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ipv6_datagram ; -SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols loopback_frame ; +HaikuSubInclude arp ; +HaikuSubInclude ethernet_frame ; +HaikuSubInclude ipv6_datagram ; +HaikuSubInclude loopback_frame ; 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 6c3ad9fdd8..1e38cb61c7 100644 --- a/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp +++ b/src/add-ons/kernel/network/datalink_protocols/arp/arp.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -7,6 +7,7 @@ * Hugo Santos, hugosantos@gmail.com */ + //! Ethernet Address Resolution Protocol, see RFC 826. @@ -110,6 +111,7 @@ struct arp_entry { struct arp_protocol : net_datalink_protocol { sockaddr_dl hardware_address; + in_addr_t local_address; }; @@ -117,9 +119,10 @@ static const net_buffer* kDeletedBuffer = (net_buffer*)~0; static void arp_timer(struct net_timer *timer, void *data); -net_buffer_module_info *gBufferModule; -static net_stack_module_info *sStackModule; -static hash_table *sCache; +net_buffer_module_info* gBufferModule; +static net_stack_module_info* sStackModule; +static net_datalink_module_info* sDatalinkModule; +static hash_table* sCache; static mutex sCacheLock; static bool sIgnoreReplies; @@ -283,7 +286,7 @@ void arp_entry::MarkValid() { TRACE(("ARP entry %p Marked as VALID, have %li packets queued.\n", this, - queue.Size())); + queue.Count())); flags = (flags & ~ARP_FLAG_REJECT) | ARP_FLAG_VALID; @@ -316,9 +319,6 @@ arp_entry::ScheduleRemoval() static void ipv4_to_ether_multicast(sockaddr_dl *destination, const sockaddr_in *source) { - // TODO: this is ethernet specific, and doesn't belong here - // (should be moved to the ethernet_frame module) - // RFC 1112 - Host extensions for IP multicasting // // ``An IP host group address is mapped to an Ethernet multicast @@ -352,7 +352,7 @@ ipv4_to_ether_multicast(sockaddr_dl *destination, const sockaddr_in *source) This function does not lock the cache - you have to do it yourself before calling it. */ -status_t +static status_t arp_update_entry(in_addr_t protocolAddress, sockaddr_dl *hardwareAddress, uint32 flags, arp_entry **_entry = NULL) { @@ -405,22 +405,73 @@ arp_update_entry(in_addr_t protocolAddress, sockaddr_dl *hardwareAddress, } -/*! 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) +static void +arp_remove_local_entry(arp_protocol* protocol, const sockaddr* local, + bool updateLocalAddress) { - ASSERT_LOCKED_MUTEX(&sCacheLock); + in_addr_t inetAddress = ((sockaddr_in*)local)->sin_addr.s_addr; - net_interface *interface = protocol->interface; + MutexLocker locker(sCacheLock); + + arp_entry* entry = arp_entry::Lookup(inetAddress); + if (entry != NULL) { + hash_remove(sCache, entry); + entry->flags |= ARP_FLAG_REMOVED; + } + + if (updateLocalAddress && protocol->local_address == inetAddress) { + // find new local sender address + protocol->local_address = 0; + + net_interface_address* address = NULL; + while (sDatalinkModule->get_next_interface_address(protocol->interface, + &address)) { + if (address->local == NULL || address->local->sa_family != AF_INET) + continue; + + protocol->local_address + = ((sockaddr_in*)address->local)->sin_addr.s_addr; + } + } + + locker.Unlock(); + delete entry; +} + + +/*! Removes all entries belonging to the local interface of the \a procotol + given. +*/ +static void +arp_remove_local(arp_protocol* protocol) +{ + net_interface_address* address = NULL; + while (sDatalinkModule->get_next_interface_address(protocol->interface, + &address)) { + if (address->local == NULL || address->local->sa_family != AF_INET) + continue; + + arp_remove_local_entry(protocol, address->local, false); + } +} + + +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 (interface->address == NULL) { + + if (local == NULL) { // interface has not yet been set inetAddress = INADDR_ANY; } else - inetAddress = ((sockaddr_in *)interface->address)->sin_addr.s_addr; + inetAddress = ((sockaddr_in*)local)->sin_addr.s_addr; + + if (protocol->local_address == 0) + protocol->local_address = inetAddress; sockaddr_dl address; address.sdl_len = sizeof(sockaddr_dl); @@ -435,7 +486,7 @@ arp_update_local(arp_protocol *protocol) memcpy(&protocol->hardware_address, &address, sizeof(sockaddr_dl)); // cache the address in our protocol - arp_entry *entry; + arp_entry* entry; status_t status = arp_update_entry(inetAddress, &address, ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry); if (status == B_OK) @@ -445,6 +496,37 @@ arp_update_local(arp_protocol *protocol) } +/*! Creates permanent local entries for all addresses of the interface belonging + to this protocol. + Returns an error if no entry could be added. +*/ +static status_t +arp_update_local(arp_protocol* protocol) +{ + protocol->local_address = 0; + // TODO: test if this actually works - maybe we should use + // INADDR_BROADCAST instead + + ssize_t count = 0; + + net_interface_address* address = NULL; + while (sDatalinkModule->get_next_interface_address(protocol->interface, + &address)) { + if (address->local == NULL || address->local->sa_family != AF_INET) + continue; + + if (arp_set_local_entry(protocol, address->local) == B_OK) { + count++; + } + } + + if (count == 0) + return arp_set_local_entry(protocol, NULL); + + return B_OK; +} + + static status_t handle_arp_request(net_buffer *buffer, arp_header &header) { @@ -518,15 +600,19 @@ arp_receive(void *cookie, net_device *device, net_buffer *buffer) #ifdef TRACE_ARP dprintf(" hw sender: %02x:%02x:%02x:%02x:%02x:%02x\n", - header.hardware_sender[0], header.hardware_sender[1], header.hardware_sender[2], - header.hardware_sender[3], header.hardware_sender[4], header.hardware_sender[5]); - dprintf(" proto sender: %ld.%ld.%ld.%ld\n", header.protocol_sender >> 24, (header.protocol_sender >> 16) & 0xff, - (header.protocol_sender >> 8) & 0xff, header.protocol_sender & 0xff); + header.hardware_sender[0], header.hardware_sender[1], + header.hardware_sender[2], header.hardware_sender[3], + header.hardware_sender[4], header.hardware_sender[5]); + unsigned int addr = ntohl(header.protocol_sender); + dprintf(" proto sender: %d.%d.%d.%d\n", addr >> 24, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff); dprintf(" hw target: %02x:%02x:%02x:%02x:%02x:%02x\n", - header.hardware_target[0], header.hardware_target[1], header.hardware_target[2], - header.hardware_target[3], header.hardware_target[4], header.hardware_target[5]); - dprintf(" proto target: %ld.%ld.%ld.%ld\n", header.protocol_target >> 24, (header.protocol_target >> 16) & 0xff, - (header.protocol_target >> 8) & 0xff, header.protocol_target & 0xff); + header.hardware_target[0], header.hardware_target[1], + header.hardware_target[2], header.hardware_target[3], + header.hardware_target[4], header.hardware_target[5]); + addr = ntohl(header.protocol_target); + dprintf(" proto target: %d.%d.%d.%d\n", addr >> 24, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff); #endif if (ntohs(header.protocol_type) != ETHER_TYPE_IP @@ -588,21 +674,23 @@ arp_timer(struct net_timer *timer, void *data) case ARP_STATE_REMOVE_FAILED: case ARP_STATE_STALE: + { // the entry has aged so much that we're going to remove it TRACE((" remove ARP entry %p!\n", entry)); - mutex_lock(&sCacheLock); + MutexLocker locker(sCacheLock); if ((entry->flags & ARP_FLAG_REMOVED) != 0) { - // The entry has already been removed, and is about to be deleted - mutex_unlock(&sCacheLock); + // The entry has already been removed, and is about to be + // deleted break; } hash_remove(sCache, entry); - mutex_unlock(&sCacheLock); + locker.Unlock(); delete entry; break; + } default: { @@ -649,8 +737,7 @@ arp_timer(struct net_timer *timer, void *data) You need to have the sCacheLock held when calling this function. */ static status_t -arp_start_resolve(net_datalink_protocol *protocol, in_addr_t address, - arp_entry **_entry) +arp_start_resolve(arp_protocol* protocol, in_addr_t address, arp_entry** _entry) { ASSERT_LOCKED_MUTEX(&sCacheLock); @@ -686,16 +773,8 @@ arp_start_resolve(net_datalink_protocol *protocol, in_addr_t address, header.opcode = htons(ARP_OPCODE_REQUEST); memcpy(header.hardware_sender, device->address.data, ETHER_ADDRESS_LENGTH); - if (protocol->interface->address != NULL) { - header.protocol_sender - = ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr; - } else { - header.protocol_sender = 0; - // TODO: test if this actually works - maybe we should use - // INADDR_BROADCAST instead - } - memset(header.hardware_target, 0, ETHER_ADDRESS_LENGTH); + header.protocol_sender = protocol->local_address; header.protocol_target = address; // prepare source and target addresses @@ -867,21 +946,25 @@ arp_uninit() status_t -arp_init_protocol(struct net_interface *interface, - net_datalink_protocol **_protocol) +arp_init_protocol(net_interface* interface, net_domain* domain, + net_datalink_protocol** _protocol) { // We currently only support a single family and type! - if (interface->domain->family != AF_INET - || interface->device->type != IFT_ETHER) + if (interface->device->type != IFT_ETHER + || domain->family != AF_INET) return B_BAD_TYPE; status_t status = sStackModule->register_device_handler(interface->device, ETHER_FRAME_TYPE | ETHER_TYPE_ARP, &arp_receive, NULL); - - if (status < B_OK) + if (status != B_OK) return status; - arp_protocol *protocol = new (std::nothrow) arp_protocol; + status = sStackModule->register_domain_device_handler( + interface->device, ETHER_FRAME_TYPE | ETHER_TYPE_IP, domain); + if (status != B_OK) + return status; + + arp_protocol* protocol = new(std::nothrow) arp_protocol; if (protocol == NULL) return B_NO_MEMORY; @@ -896,6 +979,8 @@ arp_uninit_protocol(net_datalink_protocol *protocol) { sStackModule->unregister_device_handler(protocol->interface->device, ETHER_FRAME_TYPE | ETHER_TYPE_ARP); + sStackModule->unregister_device_handler(protocol->interface->device, + ETHER_FRAME_TYPE | ETHER_TYPE_IP); delete protocol; return B_OK; @@ -914,7 +999,7 @@ arp_send_data(net_datalink_protocol *_protocol, net_buffer *buffer) memcpy(buffer->source, &protocol->hardware_address, protocol->hardware_address.sdl_len); - if (buffer->flags & MSG_MCAST) { + if ((buffer->flags & MSG_MCAST) != 0) { sockaddr_dl multicastDestination; ipv4_to_ether_multicast(&multicastDestination, (sockaddr_in *)buffer->destination); @@ -926,14 +1011,16 @@ arp_send_data(net_datalink_protocol *_protocol, net_buffer *buffer) ((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) + ((struct sockaddr_in*)buffer->destination)->sin_addr.s_addr, + &entry); + if (status != B_OK) return status; } - if (entry->flags & ARP_FLAG_REJECT) + if ((entry->flags & ARP_FLAG_REJECT) != 0) return EHOSTUNREACH; - else if (!(entry->flags & ARP_FLAG_VALID)) { + + if ((entry->flags & ARP_FLAG_VALID) == 0) { // entry is still being resolved. TRACE(("ARP Queuing packet %p, entry still being resolved.\n", buffer)); @@ -951,20 +1038,17 @@ arp_send_data(net_datalink_protocol *_protocol, net_buffer *buffer) status_t -arp_up(net_datalink_protocol *_protocol) +arp_up(net_datalink_protocol* _protocol) { - arp_protocol *protocol = (arp_protocol *)_protocol; + arp_protocol* protocol = (arp_protocol*)_protocol; status_t status = protocol->next->module->interface_up(protocol->next); - if (status < B_OK) + if (status != B_OK) return status; // cache this device's address for later use - mutex_lock(&sCacheLock); status = arp_update_local(protocol); - mutex_unlock(&sCacheLock); - - if (status < B_OK) { + if (status != B_OK) { protocol->next->module->interface_down(protocol->next); return status; } @@ -976,70 +1060,55 @@ arp_up(net_datalink_protocol *_protocol) void arp_down(net_datalink_protocol *protocol) { - // remove local ARP entry from the cache - - if (protocol->interface->address != NULL) { - MutexLocker locker(sCacheLock); - - arp_entry *entry = arp_entry::Lookup( - ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr); - if (entry != NULL) { - hash_remove(sCache, entry); - entry->flags |= ARP_FLAG_REMOVED; - locker.Unlock(); - - delete entry; - } - } + // remove local ARP entries from the cache + arp_remove_local((arp_protocol*)protocol); protocol->next->module->interface_down(protocol->next); } +status_t +arp_change_address(net_datalink_protocol* _protocol, + net_interface_address* address, int32 option, + const struct sockaddr* oldAddress, const struct sockaddr* newAddress) +{ + arp_protocol* protocol = (arp_protocol*)_protocol; + + switch (option) { + case SIOCSIFADDR: + case SIOCAIFADDR: + case SIOCDIFADDR: + // Those are the options we handle + if ((protocol->interface->flags & IFF_UP) != 0) { + // Update ARP entry for the local address + + if (newAddress != NULL && newAddress->sa_family == AF_INET) { + status_t status = arp_set_local_entry(protocol, newAddress); + if (status != B_OK) + return status; + } + + if (oldAddress != NULL && oldAddress->sa_family == AF_INET) + arp_remove_local_entry(protocol, oldAddress, true); + } + break; + + default: + break; + } + + return protocol->next->module->change_address(protocol->next, address, + option, oldAddress, newAddress); +} + + status_t arp_control(net_datalink_protocol *_protocol, int32 op, void *argument, size_t length) { - arp_protocol *protocol = (arp_protocol *)_protocol; - - if (op == SIOCSIFADDR && (protocol->interface->flags & IFF_UP) != 0) { - // The interface may get a new address, so we need to update our - // local entries. - in_addr_t oldAddress = 0; - if (protocol->interface->address != NULL) { - oldAddress - = ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr; - } - - status_t status = protocol->next->module->control(protocol->next, - SIOCSIFADDR, argument, length); - if (status < B_OK) - return status; - - MutexLocker locker(sCacheLock); - - arp_update_local(protocol); - - if (oldAddress == ((sockaddr_in *) - protocol->interface->address)->sin_addr.s_addr) - return B_OK; - - // remove previous address from cache - - arp_entry *entry = arp_entry::Lookup(oldAddress); - if (entry != NULL) { - hash_remove(sCache, entry); - entry->flags |= ARP_FLAG_REMOVED; - locker.Unlock(); - - delete entry; - } - - return B_OK; - } - - return protocol->next->module->control(protocol->next, - op, argument, length); + arp_protocol* protocol = (arp_protocol*)_protocol; + return protocol->next->module->control(protocol->next, op, argument, + length); } @@ -1097,6 +1166,7 @@ static net_datalink_protocol_module_info sARPModule = { arp_send_data, arp_up, arp_down, + arp_change_address, arp_control, arp_join_multicast, arp_leave_multicast, @@ -1104,12 +1174,13 @@ static net_datalink_protocol_module_info sARPModule = { module_dependency module_dependencies[] = { - {NET_STACK_MODULE_NAME, (module_info **)&sStackModule}, - {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, + {NET_STACK_MODULE_NAME, (module_info**)&sStackModule}, + {NET_DATALINK_MODULE_NAME, (module_info**)&sDatalinkModule}, + {NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule}, {} }; -module_info *modules[] = { - (module_info *)&sARPModule, +module_info* modules[] = { + (module_info*)&sARPModule, NULL }; 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 52c15da78b..25e13f0132 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 @@ -1,5 +1,5 @@ /* - * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -30,23 +30,23 @@ struct ethernet_frame_protocol : net_datalink_protocol { static const uint8 kBroadcastAddress[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -struct net_buffer_module_info *gBufferModule; +struct net_buffer_module_info* gBufferModule; int32 -ethernet_deframe(net_device *device, net_buffer *buffer) +ethernet_deframe(net_device* device, net_buffer* buffer) { //dprintf("asked to deframe buffer for device %s\n", device->name); NetBufferHeaderRemover bufferHeader(buffer); - if (bufferHeader.Status() < B_OK) + if (bufferHeader.Status() != B_OK) return bufferHeader.Status(); - ether_header &header = bufferHeader.Data(); + ether_header& header = bufferHeader.Data(); uint16 type = ntohs(header.type); - struct sockaddr_dl &source = *(struct sockaddr_dl *)buffer->source; - struct sockaddr_dl &destination = *(struct sockaddr_dl *)buffer->destination; + struct sockaddr_dl& source = *(struct sockaddr_dl*)buffer->source; + struct sockaddr_dl& destination = *(struct sockaddr_dl*)buffer->destination; source.sdl_len = sizeof(sockaddr_dl); source.sdl_family = AF_LINK; @@ -68,7 +68,7 @@ ethernet_deframe(net_device *device, net_buffer *buffer) // mark buffer if it was a broadcast/multicast packet if (!memcmp(header.destination, kBroadcastAddress, ETHER_ADDRESS_LENGTH)) buffer->flags |= MSG_BCAST; - else if (header.destination[0] & 0x01) + else if ((header.destination[0] & 0x01) != 0) buffer->flags |= MSG_MCAST; return ETHER_FRAME_TYPE | type; @@ -79,20 +79,24 @@ ethernet_deframe(net_device *device, net_buffer *buffer) status_t -ethernet_frame_init(struct net_interface *interface, net_datalink_protocol **_protocol) +ethernet_frame_init(struct net_interface* interface, net_domain* domain, + net_datalink_protocol** _protocol) { - net_stack_module_info *stack; - status_t status = get_module(NET_STACK_MODULE_NAME, (module_info **)&stack); + net_stack_module_info* stack; + status_t status = get_module(NET_STACK_MODULE_NAME, (module_info**)&stack); if (status < B_OK) return status; - status = stack->register_device_deframer(interface->device, ðernet_deframe); + status = stack->register_device_deframer(interface->device, + ðernet_deframe); + put_module(NET_STACK_MODULE_NAME); - if (status < B_OK) + if (status != B_OK) return status; - ethernet_frame_protocol *protocol = new (std::nothrow) ethernet_frame_protocol; + ethernet_frame_protocol* protocol + = new(std::nothrow) ethernet_frame_protocol; if (protocol == NULL) return B_NO_MEMORY; @@ -102,10 +106,10 @@ ethernet_frame_init(struct net_interface *interface, net_datalink_protocol **_pr status_t -ethernet_frame_uninit(net_datalink_protocol *protocol) +ethernet_frame_uninit(net_datalink_protocol* protocol) { - net_stack_module_info *stack; - if (get_module(NET_STACK_MODULE_NAME, (module_info **)&stack) == B_OK) { + net_stack_module_info* stack; + if (get_module(NET_STACK_MODULE_NAME, (module_info**)&stack) == B_OK) { stack->unregister_device_deframer(protocol->interface->device); put_module(NET_STACK_MODULE_NAME); } @@ -116,24 +120,23 @@ ethernet_frame_uninit(net_datalink_protocol *protocol) status_t -ethernet_frame_send_data(net_datalink_protocol *protocol, - net_buffer *buffer) +ethernet_frame_send_data(net_datalink_protocol* protocol, net_buffer* buffer) { - struct sockaddr_dl &source = *(struct sockaddr_dl *)buffer->source; - struct sockaddr_dl &destination = *(struct sockaddr_dl *)buffer->destination; + struct sockaddr_dl& source = *(struct sockaddr_dl*)buffer->source; + struct sockaddr_dl& destination = *(struct sockaddr_dl*)buffer->destination; if (source.sdl_family != AF_LINK || source.sdl_type != IFT_ETHER) return B_ERROR; NetBufferPrepend bufferHeader(buffer); - if (bufferHeader.Status() < B_OK) + if (bufferHeader.Status() != B_OK) return bufferHeader.Status(); ether_header &header = bufferHeader.Data(); header.type = htons(source.sdl_e_type); memcpy(header.source, source.sdl_data, ETHER_ADDRESS_LENGTH); - if (buffer->flags & MSG_BCAST) + if ((buffer->flags & MSG_BCAST) != 0) memcpy(header.destination, kBroadcastAddress, ETHER_ADDRESS_LENGTH); else memcpy(header.destination, destination.sdl_data, ETHER_ADDRESS_LENGTH); @@ -146,40 +149,49 @@ ethernet_frame_send_data(net_datalink_protocol *protocol, status_t -ethernet_frame_up(net_datalink_protocol *_protocol) +ethernet_frame_up(net_datalink_protocol* protocol) { - ethernet_frame_protocol *protocol = (ethernet_frame_protocol *)_protocol; - return protocol->next->module->interface_up(protocol->next); } void -ethernet_frame_down(net_datalink_protocol *protocol) +ethernet_frame_down(net_datalink_protocol* protocol) { return protocol->next->module->interface_down(protocol->next); } status_t -ethernet_frame_control(net_datalink_protocol *protocol, - int32 op, void *argument, size_t length) +ethernet_frame_change_address(net_datalink_protocol* protocol, + net_interface_address* address, int32 option, + const struct sockaddr* oldAddress, const struct sockaddr* newAddress) { - return protocol->next->module->control(protocol->next, op, argument, length); + return protocol->next->module->change_address(protocol->next, address, + option, oldAddress, newAddress); +} + + +status_t +ethernet_frame_control(net_datalink_protocol* protocol, int32 option, + void* argument, size_t length) +{ + return protocol->next->module->control(protocol->next, option, argument, + length); } static status_t -ethernet_frame_join_multicast(net_datalink_protocol *protocol, - const sockaddr *address) +ethernet_frame_join_multicast(net_datalink_protocol* protocol, + const sockaddr* address) { return protocol->next->module->join_multicast(protocol->next, address); } static status_t -ethernet_frame_leave_multicast(net_datalink_protocol *protocol, - const sockaddr *address) +ethernet_frame_leave_multicast(net_datalink_protocol* protocol, + const sockaddr* address) { return protocol->next->module->leave_multicast(protocol->next, address); } @@ -190,7 +202,8 @@ ethernet_frame_std_ops(int32 op, ...) { switch (op) { case B_MODULE_INIT: - return get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule); + return get_module(NET_BUFFER_MODULE_NAME, + (module_info**)&gBufferModule); case B_MODULE_UNINIT: put_module(NET_BUFFER_MODULE_NAME); return B_OK; @@ -212,12 +225,13 @@ static net_datalink_protocol_module_info sEthernetFrameModule = { ethernet_frame_send_data, ethernet_frame_up, ethernet_frame_down, + ethernet_frame_change_address, ethernet_frame_control, ethernet_frame_join_multicast, ethernet_frame_leave_multicast, }; -module_info *modules[] = { - (module_info *)&sEthernetFrameModule, +module_info* modules[] = { + (module_info*)&sEthernetFrameModule, NULL }; diff --git a/src/add-ons/kernel/network/datalink_protocols/ipv4_datagram/Jamfile b/src/add-ons/kernel/network/datalink_protocols/ipv4_datagram/Jamfile deleted file mode 100644 index 19b73758c5..0000000000 --- a/src/add-ons/kernel/network/datalink_protocols/ipv4_datagram/Jamfile +++ /dev/null @@ -1,25 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel network datalink_protocols ipv4_datagram ; - -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UseHeaders [ FStandardOSHeaders ] : true ; - # Needed for and maybe other stuff. - UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; - # We need the public network headers also when not compiling for Haiku. - # Unfortunately we get more than we want, namely all POSIX headers. -} - -UsePrivateHeaders kernel net ; - -KernelAddon ipv4_datagram : - ipv4_datagram.cpp -; - -# Installation -HaikuInstall install-networking : /boot/home/config/add-ons/kernel/haiku_network/datalink_protocols - : ipv4_datagram ; - -Package haiku-networkingkit-cvs : - haiku : - boot home config add-ons kernel haiku_network datalink_protocols ; diff --git a/src/add-ons/kernel/network/datalink_protocols/ipv4_datagram/ipv4_datagram.cpp b/src/add-ons/kernel/network/datalink_protocols/ipv4_datagram/ipv4_datagram.cpp deleted file mode 100644 index b39d8074a6..0000000000 --- a/src/add-ons/kernel/network/datalink_protocols/ipv4_datagram/ipv4_datagram.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2007, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Hugo Santos, hugosantos@gmail.com - */ - - -#include -#include -#include -#include - -#include - -#include // for ETHER_TYPE_IP -#include - -#include - - -static net_stack_module_info *sStackModule; -// TODO ETHER_FRAME_TYPE doesn't belong there, we need Layer 2 -// independence. -static const int32 kIPv4FrameType = ETHER_FRAME_TYPE | ETHER_TYPE_IP; - - -static status_t -ipv4_datalink_init(net_interface *interface, net_datalink_protocol **_protocol) -{ - dprintf("ipv4_datalink_init(%s)\n", interface->name); - - if (interface->domain->family != AF_INET) - return B_BAD_TYPE; - - // While the loopback doesn't get a header to mux protocols, - // we let it do all of the registration work. - if (interface->device->type == IFT_LOOP) - return B_BAD_TYPE; - - net_datalink_protocol *protocol = new (std::nothrow) net_datalink_protocol; - if (protocol == NULL) - return B_NO_MEMORY; - - // We register ETHER_TYPE_IP as most datalink protocols use it - // to identify IP datagrams. In the future we may limit this. - - status_t status = sStackModule->register_domain_device_handler( - interface->device, kIPv4FrameType, interface->domain); - if (status < B_OK) - delete protocol; - else - *_protocol = protocol; - - return status; -} - - -static status_t -ipv4_datalink_uninit(net_datalink_protocol *protocol) -{ - sStackModule->unregister_device_handler(protocol->interface->device, - kIPv4FrameType); - delete protocol; - return B_OK; -} - - -static status_t -ipv4_datalink_send_data(net_datalink_protocol *protocol, net_buffer *buffer) -{ - return protocol->next->module->send_data(protocol->next, buffer); -} - - -static status_t -ipv4_datalink_up(net_datalink_protocol *protocol) -{ - return protocol->next->module->interface_up(protocol->next); -} - - -static void -ipv4_datalink_down(net_datalink_protocol *protocol) -{ - // TODO Clear routes here instead? - protocol->next->module->interface_down(protocol->next); -} - - -static status_t -ipv4_datalink_control(net_datalink_protocol *protocol, int32 op, - void *argument, size_t length) -{ - return protocol->next->module->control(protocol->next, op, argument, length); -} - - -static status_t -ipv4_datalink_join_multicast(net_datalink_protocol *protocol, - const sockaddr *address) -{ - return protocol->next->module->join_multicast(protocol->next, address); -} - - -static status_t -ipv4_datalink_leave_multicast(net_datalink_protocol *protocol, - const sockaddr *address) -{ - return protocol->next->module->leave_multicast(protocol->next, address); -} - - -static status_t -ipv4_datalink_std_ops(int32 op, ...) -{ - switch (op) { - case B_MODULE_INIT: - return get_module(NET_STACK_MODULE_NAME, (module_info **)&sStackModule); - - case B_MODULE_UNINIT: - return put_module(NET_STACK_MODULE_NAME); - } - - return B_ERROR; -} - - -net_datalink_protocol_module_info gIPv4DataLinkModule = { - { - "network/datalink_protocols/ipv4_datagram/v1", - 0, - ipv4_datalink_std_ops - }, - ipv4_datalink_init, - ipv4_datalink_uninit, - ipv4_datalink_send_data, - ipv4_datalink_up, - ipv4_datalink_down, - ipv4_datalink_control, - ipv4_datalink_join_multicast, - ipv4_datalink_leave_multicast, -}; - -module_info *modules[] = { - (module_info *)&gIPv4DataLinkModule, - NULL -}; diff --git a/src/add-ons/kernel/network/datalink_protocols/ipv6_datagram/ipv6_datagram.cpp b/src/add-ons/kernel/network/datalink_protocols/ipv6_datagram/ipv6_datagram.cpp index 0d53047605..ee15c2d0cd 100644 --- a/src/add-ons/kernel/network/datalink_protocols/ipv6_datagram/ipv6_datagram.cpp +++ b/src/add-ons/kernel/network/datalink_protocols/ipv6_datagram/ipv6_datagram.cpp @@ -1040,6 +1040,66 @@ ipv6_datalink_down(net_datalink_protocol* protocol) } +status_t +ipv6_datalink_change_address(net_datalink_protocol* protocol, + net_interface_address* address, int32 option, + const struct sockaddr* oldAddress, const struct sockaddr* newAddress) +{ +#if 0 + switch (option) { + case SIOCSIFADDR: + case SIOCAIFADDR: + case SIOCDIFADDR: + // Those are the options we handle + if ((protocol->interface->flags & IFF_UP) != 0) { + // Update ARP entry for the local address + + if (newAddress != NULL && newAddress->sa_family == AF_INET6) { + status_t status = arp_set_local_entry(protocol, newAddress); + if (status != B_OK) + return status; + + // add IPv6 remove multicast route (ff00::/8) + sockaddr_in6 address; + memset(&address, 0, sizeof(sockaddr_in6)); + address.sin6_family = AF_INET6; + address.sin6_len = sizeof(sockaddr_in6); + address.sin6_addr.s6_addr[0] = 0xff; + + route.destination = (sockaddr*)&address; + route.mask = (sockaddr*)&address; + route.flags = 0; + add_route(interface->domain, &route); + } + + if (oldAddress != NULL && oldAddress->sa_family == AF_INET6) { + arp_remove_local_entry(protocol, oldAddress, true); + + // remove IPv6 remove multicast route (ff00::/8) + sockaddr_in6 address; + memset(&address, 0, sizeof(sockaddr_in6)); + address.sin6_family = AF_INET6; + address.sin6_len = sizeof(sockaddr_in6); + address.sin6_addr.s6_addr[0] = 0xff; + + route.destination = (sockaddr*)&address; + route.mask = (sockaddr*)&address; + route.flags = 0; + remove_route(interface->domain, &route); + } + } + break; + + default: + break; + } +#endif + + return protocol->next->module->change_address(protocol->next, address, + option, oldAddress, newAddress); +} + + static status_t ipv6_datalink_control(net_datalink_protocol* protocol, int32 op, void* argument, size_t length) @@ -1105,6 +1165,7 @@ net_datalink_protocol_module_info gIPv6DataLinkModule = { ipv6_datalink_send_data, ipv6_datalink_up, ipv6_datalink_down, + ipv6_datalink_change_address, ipv6_datalink_control, ipv6_datalink_join_multicast, ipv6_datalink_leave_multicast, 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 2f23a47fde..4f5522b54f 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 @@ -1,5 +1,5 @@ /* - * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -28,11 +28,11 @@ struct loopback_frame_protocol : net_datalink_protocol { }; -struct net_buffer_module_info *gBufferModule; +struct net_buffer_module_info* gBufferModule; int32 -loopback_deframe(net_device *device, net_buffer *buffer) +loopback_deframe(net_device* device, net_buffer* buffer) { // there is not that much to do... return 0; @@ -43,32 +43,34 @@ loopback_deframe(net_device *device, net_buffer *buffer) status_t -loopback_frame_init(struct net_interface *interface, net_datalink_protocol **_protocol) +loopback_frame_init(struct net_interface*interface, net_domain* domain, + net_datalink_protocol** _protocol) { // We currently only support a single family and type! if (interface->device->type != IFT_LOOP) return B_BAD_TYPE; - loopback_frame_protocol *protocol; + loopback_frame_protocol* protocol; - net_stack_module_info *stack; - status_t status = get_module(NET_STACK_MODULE_NAME, (module_info **)&stack); - if (status < B_OK) + net_stack_module_info* stack; + status_t status = get_module(NET_STACK_MODULE_NAME, (module_info**)&stack); + if (status != B_OK) return status; - status = stack->register_device_deframer(interface->device, &loopback_deframe); - if (status < B_OK) + status = stack->register_device_deframer(interface->device, + &loopback_deframe); + if (status != B_OK) goto err1; // We also register the domain as a handler for our packets - status = stack->register_domain_device_handler(interface->device, - 0, interface->domain); - if (status < B_OK) + status = stack->register_domain_device_handler(interface->device, 0, + domain); + if (status != B_OK) goto err2; put_module(NET_STACK_MODULE_NAME); - protocol = new (std::nothrow) loopback_frame_protocol; + protocol = new(std::nothrow) loopback_frame_protocol; if (protocol == NULL) return B_NO_MEMORY; @@ -84,10 +86,10 @@ err1: status_t -loopback_frame_uninit(net_datalink_protocol *protocol) +loopback_frame_uninit(net_datalink_protocol* protocol) { - net_stack_module_info *stack; - if (get_module(NET_STACK_MODULE_NAME, (module_info **)&stack) == B_OK) { + net_stack_module_info* stack; + if (get_module(NET_STACK_MODULE_NAME, (module_info**)&stack) == B_OK) { stack->unregister_device_deframer(protocol->interface->device); stack->unregister_device_handler(protocol->interface->device, 0); put_module(NET_STACK_MODULE_NAME); @@ -99,48 +101,56 @@ loopback_frame_uninit(net_datalink_protocol *protocol) status_t -loopback_frame_send_data(net_datalink_protocol *protocol, - net_buffer *buffer) +loopback_frame_send_data(net_datalink_protocol* protocol, net_buffer* buffer) { return protocol->next->module->send_data(protocol->next, buffer); } status_t -loopback_frame_up(net_datalink_protocol *_protocol) +loopback_frame_up(net_datalink_protocol* protocol) { - loopback_frame_protocol *protocol = (loopback_frame_protocol *)_protocol; - return protocol->next->module->interface_up(protocol->next); } void -loopback_frame_down(net_datalink_protocol *protocol) +loopback_frame_down(net_datalink_protocol* protocol) { return protocol->next->module->interface_down(protocol->next); } status_t -loopback_frame_control(net_datalink_protocol *protocol, - int32 op, void *argument, size_t length) +loopback_frame_change_address(net_datalink_protocol* protocol, + net_interface_address* address, int32 option, + const struct sockaddr* oldAddress, const struct sockaddr* newAddress) { - return protocol->next->module->control(protocol->next, op, argument, length); + return protocol->next->module->change_address(protocol->next, address, + option, oldAddress, newAddress); +} + + +status_t +loopback_frame_control(net_datalink_protocol* protocol, int32 option, + void* argument, size_t length) +{ + return protocol->next->module->control(protocol->next, option, argument, + length); } static status_t -loopback_frame_join_multicast(net_datalink_protocol *protocol, - const sockaddr *address) +loopback_frame_join_multicast(net_datalink_protocol* protocol, + const sockaddr* address) { return protocol->next->module->join_multicast(protocol->next, address); } static status_t -loopback_frame_leave_multicast(net_datalink_protocol *protocol, - const sockaddr *address) +loopback_frame_leave_multicast(net_datalink_protocol* protocol, + const sockaddr* address) { return protocol->next->module->leave_multicast(protocol->next, address); } @@ -151,7 +161,8 @@ loopback_frame_std_ops(int32 op, ...) { switch (op) { case B_MODULE_INIT: - return get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule); + return get_module(NET_BUFFER_MODULE_NAME, + (module_info**)&gBufferModule); case B_MODULE_UNINIT: put_module(NET_BUFFER_MODULE_NAME); return B_OK; @@ -173,12 +184,13 @@ static net_datalink_protocol_module_info sLoopbackFrameModule = { loopback_frame_send_data, loopback_frame_up, loopback_frame_down, + loopback_frame_change_address, loopback_frame_control, loopback_frame_join_multicast, loopback_frame_leave_multicast, }; -module_info *modules[] = { - (module_info *)&sLoopbackFrameModule, +module_info* modules[] = { + (module_info*)&sLoopbackFrameModule, NULL }; diff --git a/src/add-ons/kernel/network/protocols/icmp/icmp.cpp b/src/add-ons/kernel/network/protocols/icmp/icmp.cpp index c312de8a37..181a2fd5c3 100644 --- a/src/add-ons/kernel/network/protocols/icmp/icmp.cpp +++ b/src/add-ons/kernel/network/protocols/icmp/icmp.cpp @@ -86,8 +86,8 @@ static net_domain* get_domain(struct net_buffer* buffer) { net_domain* domain; - if (buffer->interface != NULL) - domain = buffer->interface->domain; + if (buffer->interface_address != NULL) + domain = buffer->interface_address->domain; else domain = sStackModule->get_domain(buffer->source->sa_family); @@ -288,13 +288,8 @@ icmp_receive_data(net_buffer* buffer) { TRACE("ICMP received some data, buffer length %lu\n", buffer->size); - net_domain* domain; - if (buffer->interface != NULL) - domain = buffer->interface->domain; - else - domain = sStackModule->get_domain(buffer->source->sa_family); - - if (domain == NULL || domain->module == NULL) + net_domain* domain = get_domain(buffer); + if (domain == NULL) return B_ERROR; NetBufferHeaderReader bufferHeader(buffer); @@ -322,11 +317,11 @@ icmp_receive_data(net_buffer* buffer) if (domain == NULL) break; - if (buffer->interface != NULL) { + if (buffer->interface_address != NULL) { // We only reply to echo requests of our local interface; we // don't reply to broadcast requests if (!domain->address_module->equal_addresses( - buffer->interface->address, buffer->destination)) + buffer->interface_address->local, buffer->destination)) break; } diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp index 0bc0501377..bae91415af 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp @@ -141,7 +141,7 @@ struct ipv4_protocol : net_protocol { uint8 time_to_live; uint8 multicast_time_to_live; uint32 flags; - struct sockaddr* interface_address; // for IP_MULTICAST_IF + struct sockaddr* multicast_address; // for IP_MULTICAST_IF IPv4MulticastFilter multicast_filter; }; @@ -673,12 +673,14 @@ deliver_multicast(net_protocol_module_info* module, net_buffer* buffer, if (module->deliver_data == NULL) return false; + // TODO: fix multicast! + return false; MutexLocker _(sMulticastGroupsLock); sockaddr_in* multicastAddr = (sockaddr_in*)buffer->destination; MulticastState::ValueIterator it = sMulticastState->Lookup(std::make_pair( - &multicastAddr->sin_addr, buffer->interface->index)); + &multicastAddr->sin_addr, buffer->interface_address->interface->index)); size_t count = 0; @@ -687,7 +689,7 @@ deliver_multicast(net_protocol_module_info* module, net_buffer* buffer, ipv4_protocol* ipProtocol = state->Parent()->Socket(); if (deliverToRaw && (ipProtocol->raw == NULL - || ipProtocol->socket->protocol != buffer->protocol)) + || ipProtocol->socket->protocol != buffer->protocol)) continue; if (state->FilterAccepts(buffer)) { @@ -819,11 +821,8 @@ IPv4Multicast::JoinGroup(IPv4GroupInterface* state) MutexLocker _(sMulticastGroupsLock); sockaddr_in groupAddr; - net_interface* interface = state->Interface(); - - status_t status = interface->first_info->join_multicast( - interface->first_protocol, - fill_sockaddr_in(&groupAddr, state->Address().s_addr)); + status_t status = sDatalinkModule->join_multicast(state->Interface(), + sDomain, fill_sockaddr_in(&groupAddr, state->Address().s_addr)); if (status != B_OK) return status; @@ -840,10 +839,7 @@ IPv4Multicast::LeaveGroup(IPv4GroupInterface* state) sMulticastState->Remove(state); sockaddr_in groupAddr; - net_interface* interface = state->Interface(); - - return interface->first_protocol->module->join_multicast( - interface->first_protocol, + return sDatalinkModule->leave_multicast(state->Interface(), sDomain, fill_sockaddr_in(&groupAddr, state->Address().s_addr)); } @@ -876,7 +872,7 @@ ipv4_delta_membership(ipv4_protocol* protocol, int option, net_interface* interface, const in_addr* groupAddr, const in_addr* sourceAddr) { - IPv4MulticastFilter &filter = protocol->multicast_filter; + IPv4MulticastFilter& filter = protocol->multicast_filter; IPv4GroupInterface* state = NULL; status_t status = B_OK; @@ -935,13 +931,14 @@ generic_to_ipv4(int option) static net_interface* get_multicast_interface(ipv4_protocol* protocol, const in_addr* address) { + // TODO: this is broken and leaks references sockaddr_in groupAddr; net_route* route = sDatalinkModule->get_route(sDomain, fill_sockaddr_in(&groupAddr, address ? address->s_addr : INADDR_ANY)); if (route == NULL) return NULL; - return route->interface; + return route->interface_address->interface; } @@ -955,7 +952,7 @@ ipv4_delta_membership(ipv4_protocol* protocol, int option, interface = get_multicast_interface(protocol, groupAddr); } else { sockaddr_in address; - interface = sDatalinkModule->get_interface_with_address(sDomain, + interface = sDatalinkModule->get_interface_with_address( fill_sockaddr_in(&address, interfaceAddr->s_addr)); } @@ -972,14 +969,13 @@ ipv4_generic_delta_membership(ipv4_protocol* protocol, int option, uint32 index, const sockaddr_storage* _groupAddr, const sockaddr_storage* _sourceAddr) { - if (_groupAddr->ss_family != AF_INET) - return B_BAD_VALUE; - - if (_sourceAddr && _sourceAddr->ss_family != AF_INET) + if (_groupAddr->ss_family != AF_INET + || _sourceAddr != NULL && _sourceAddr->ss_family != AF_INET) return B_BAD_VALUE; const in_addr* groupAddr = &((const sockaddr_in*)_groupAddr)->sin_addr; + // TODO: this is broken and leaks references net_interface* interface; if (index == 0) interface = get_multicast_interface(protocol, groupAddr); @@ -990,7 +986,7 @@ ipv4_generic_delta_membership(ipv4_protocol* protocol, int option, return ENODEV; const in_addr* sourceAddr = NULL; - if (_sourceAddr) + if (_sourceAddr != NULL) sourceAddr = &((const sockaddr_in*)_sourceAddr)->sin_addr; return ipv4_delta_membership(protocol, generic_to_ipv4(option), interface, @@ -1013,7 +1009,7 @@ ipv4_init_protocol(net_socket* socket) protocol->time_to_live = kDefaultTTL; protocol->multicast_time_to_live = kDefaultMulticastTTL; protocol->flags = 0; - protocol->interface_address = NULL; + protocol->multicast_address = NULL; return protocol; } @@ -1024,7 +1020,7 @@ ipv4_uninit_protocol(net_protocol* _protocol) ipv4_protocol* protocol = (ipv4_protocol*)_protocol; delete protocol->raw; - delete protocol->interface_address; + delete protocol->multicast_address; delete protocol; return B_OK; } @@ -1217,21 +1213,23 @@ ipv4_setsockopt(net_protocol* _protocol, int level, int option, // Using INADDR_ANY to remove the previous setting. if (address->sin_addr.s_addr == htonl(INADDR_ANY)) { delete address; - delete protocol->interface_address; - protocol->interface_address = NULL; + delete protocol->multicast_address; + protocol->multicast_address = NULL; return B_OK; } struct net_interface* interface - = sDatalinkModule->get_interface_with_address(sDomain, - (struct sockaddr*)address); + = sDatalinkModule->get_interface_with_address( + (sockaddr*)address); if (interface == NULL) { delete address; return EADDRNOTAVAIL; } - delete protocol->interface_address; - protocol->interface_address = (struct sockaddr*)address; + delete protocol->multicast_address; + protocol->multicast_address = (struct sockaddr*)address; + + sDatalinkModule->put_interface(interface); return B_OK; } if (option == IP_MULTICAST_TTL) { @@ -1346,16 +1344,18 @@ ipv4_send_routed_data(net_protocol* _protocol, struct net_route* route, return B_BAD_VALUE; ipv4_protocol* protocol = (ipv4_protocol*)_protocol; - net_interface* interface = route->interface; + net_interface_address* interfaceAddress = route->interface_address; + net_interface* interface = interfaceAddress->interface; TRACE_SK(protocol, "SendRoutedData(%p, %p [%ld bytes])", route, buffer, buffer->size); sockaddr_in& source = *(sockaddr_in*)buffer->source; sockaddr_in& destination = *(sockaddr_in*)buffer->destination; - sockaddr_in& broadcastAddress = *(sockaddr_in*)interface->destination; + sockaddr_in* broadcastAddress = (sockaddr_in*)interfaceAddress->destination; - bool headerIncluded = false, checksumNeeded = true; + bool checksumNeeded = true; + bool headerIncluded = false; if (protocol != NULL) headerIncluded = (protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0; @@ -1366,8 +1366,8 @@ ipv4_send_routed_data(net_protocol* _protocol, struct net_route* route, if ((interface->device->flags & IFF_BROADCAST) != 0 && (destination.sin_addr.s_addr == INADDR_BROADCAST - || destination.sin_addr.s_addr - == broadcastAddress.sin_addr.s_addr)) { + || (broadcastAddress != NULL && destination.sin_addr.s_addr + == broadcastAddress->sin_addr.s_addr))) { if (protocol && !(protocol->socket->options & SO_BROADCAST)) return B_BAD_VALUE; buffer->flags |= MSG_BCAST; @@ -1466,18 +1466,21 @@ ipv4_send_data(net_protocol* _protocol, net_buffer* buffer) } // handle IP_MULTICAST_IF - if (IN_MULTICAST(ntohl(((sockaddr_in*)buffer->destination)-> - sin_addr.s_addr)) && protocol->interface_address != NULL) { - net_interface* interface - = sDatalinkModule->get_interface_with_address(sDomain, - protocol->interface_address); - if (interface == NULL || (interface->flags & IFF_UP) == 0) + if (IN_MULTICAST(ntohl( + ((sockaddr_in*)buffer->destination)->sin_addr.s_addr)) + && protocol->multicast_address != NULL) { + net_interface_address* address = sDatalinkModule->get_interface_address( + protocol->multicast_address); + if (address == NULL || (address->interface->flags & IFF_UP) == 0) { + sDatalinkModule->put_interface_address(address); return EADDRNOTAVAIL; + } - buffer->interface = interface; + sDatalinkModule->put_interface_address(buffer->interface_address); + buffer->interface_address = address; + // the buffer takes over ownership of the address - net_route* route = sDatalinkModule->get_route(sDomain, - interface->address); + net_route* route = sDatalinkModule->get_route(sDomain, address->local); if (route == NULL) return ENETUNREACH; @@ -1540,7 +1543,7 @@ ipv4_get_mtu(net_protocol* protocol, const struct sockaddr* address) if (route->mtu != 0) mtu = route->mtu; else - mtu = route->interface->mtu; + mtu = route->interface_address->interface->mtu; sDatalinkModule->put_route(sDomain, route); return mtu - sizeof(ipv4_header); @@ -1588,9 +1591,9 @@ ipv4_receive_data(net_buffer* buffer) // test if the packet is really for us if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination, - &buffer->interface, &matchedAddressType) + &buffer->interface_address, &matchedAddressType) && !sDatalinkModule->is_local_link_address(sDomain, true, - buffer->destination, &buffer->interface)) { + buffer->destination, &buffer->interface_address)) { TRACE(" ipv4_receive_data(): packet was not for us %x -> %x", ntohl(header.source), ntohl(header.destination)); diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp b/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp index 59fc13862a..6e42089140 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -107,6 +107,7 @@ ipv4_is_empty_address(const sockaddr *address, bool checkPort) && (!checkPort || ((sockaddr_in *)address)->sin_port == 0); } + /*! Checks if the given \a address is an IPv4 address. \return false if \a address is NULL, or with family different from AF_INET true if it has AF_INET address family @@ -120,6 +121,7 @@ ipv4_is_same_family(const sockaddr *address) return address->sa_family == AF_INET; } + /*! Compares the IP-addresses of the two given address structures \a a and \a b. \return true if IP-addresses of \a a and \a b are equal, false if not */ @@ -407,12 +409,12 @@ ipv4_set_to_empty_address(sockaddr *address) static status_t ipv4_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast, - sockaddr *_address, sockaddr *_mask) + const sockaddr *_address, const sockaddr *_mask) { sockaddr_in *defaultMask = (sockaddr_in *)_defaultMask; sockaddr_in *defaultBroadcast = (sockaddr_in *)_defaultBroadcast; - sockaddr_in *address = (sockaddr_in *)_address; - sockaddr_in *mask = (sockaddr_in *)_mask; + const sockaddr_in *address = (const sockaddr_in *)_address; + const sockaddr_in *mask = (const sockaddr_in *)_mask; if (address == NULL || (defaultMask == NULL && defaultBroadcast == NULL)) return B_BAD_VALUE; @@ -453,6 +455,23 @@ ipv4_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast, } +/*! Computes a hash value of the given \a address. + \return uint32 representing the hash value +*/ +static uint32 +ipv4_hash_address(const struct sockaddr* _address, bool includePort) +{ + const sockaddr_in* address = (const sockaddr_in*)_address; + if (address == NULL || address->sin_len == 0) + return 0; + + if (includePort) + return address->sin_port ^ address->sin_addr.s_addr; + + return address->sin_addr.s_addr; +} + + /*! Computes a hash-value of the given addresses \a ourAddress and \a peerAddress. \return uint32 representing the hash-value @@ -526,6 +545,7 @@ net_address_module_info gIPv4AddressModule = { ipv4_set_to_empty_address, ipv4_set_to_defaults, ipv4_update_to, + ipv4_hash_address, ipv4_hash_address_pair, ipv4_checksum_address, ipv4_get_loopback_address diff --git a/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp b/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp index 2c4b56dd32..8da85ec6eb 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2007, Haiku, Inc. All Rights Reserved. + * Copyright 2007-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -14,19 +14,27 @@ #include -static inline bool -operator==(const in_addr &a1, const in_addr &a2) -{ - return a1.s_addr == a2.s_addr; -} using std::nothrow; +static inline bool +operator==(const in_addr& a, const in_addr& b) +{ + return a.s_addr == b.s_addr; +} + + +// #pragma mark - + + template MulticastGroupInterface::MulticastGroupInterface(Filter *parent, const AddressType &address, net_interface *interface) - : fParent(parent), fMulticastAddress(address), fInterface(interface) + : + fParent(parent), + fMulticastAddress(address), + fInterface(interface) { } diff --git a/src/add-ons/kernel/network/protocols/ipv6/ipv6_address.cpp b/src/add-ons/kernel/network/protocols/ipv6/ipv6_address.cpp index 108bc1076f..3fce6e50b6 100644 --- a/src/add-ons/kernel/network/protocols/ipv6/ipv6_address.cpp +++ b/src/add-ons/kernel/network/protocols/ipv6/ipv6_address.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -478,6 +478,25 @@ ipv6_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast, } +/*! Computes a hash value of the given \a address. + \return uint32 representing the hash value +*/ +static uint32 +ipv6_hash_address(const struct sockaddr* _address, bool includePort) +{ + const sockaddr_in6* address = (const sockaddr_in6*)_address; + if (address == NULL || address->sin6_len == 0) + return 0; + + // TODO: also use sin6_flowinfo and sin6_scope_id? + uint32 port = includePort ? address->sin6_port : 0; + + uint32 result = jenkins_hashword((const uint32*)&address->sin6_addr, + sizeof(in6_addr) / sizeof(uint32), 0); + return jenkins_hashword(&port, 1, result); +} + + /*! Computes a hash-value of the given addresses \a ourAddress and \a peerAddress. \return uint32 representing the hash-value @@ -485,26 +504,8 @@ ipv6_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast, static uint32 ipv6_hash_address_pair(const sockaddr *ourAddress, const sockaddr *peerAddress) { - uint32 result = 0; - if (ourAddress) { - const sockaddr_in6 *our = (const sockaddr_in6 *)ourAddress; - uint32 port = our->sin6_port; - - result = jenkins_hashword((const uint32*)&our->sin6_addr, - sizeof(in6_addr) / sizeof(uint32), result); - result = jenkins_hashword(&port, 1, result); - } - if (peerAddress) { - const sockaddr_in6 *peer = (const sockaddr_in6 *)peerAddress; - uint32 port = peer->sin6_port; - - result = jenkins_hashword((const uint32*)&peer->sin6_addr, - sizeof(in6_addr) / sizeof(uint32), result); - result = jenkins_hashword(&port, 1, result); - } - - // TODO: also use sin6_flowinfo and sin6_scope_id? - return result; + uint32 result = ipv6_hash_address(peerAddress, true); + return jenkins_hashword(&result, 1, ipv6_hash_address(ourAddress, true)); } @@ -563,6 +564,7 @@ net_address_module_info gIPv6AddressModule = { ipv6_set_to_empty_address, ipv6_set_to_defaults, ipv6_update_to, + ipv6_hash_address, ipv6_hash_address_pair, ipv6_checksum_address, ipv6_get_loopback_address diff --git a/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.cpp b/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.cpp index 4d1521c24d..4527fa5c0d 100644 --- a/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.cpp +++ b/src/add-ons/kernel/network/protocols/l2cap/l2cap_address.cpp @@ -1,11 +1,12 @@ /* - * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com */ + #include #include @@ -20,15 +21,13 @@ #include #include -#define L2CAP_CHECKSUM(address) (address.b[0]+\ - address.b[1]+\ - address.b[2]+\ - address.b[3]+\ - address.b[4]+\ - address.b[5]) -/*! - Routing utility function: copies address \a from into a new address +#define L2CAP_CHECKSUM(address) \ + (address.b[0] + address.b[1] + address.b[2] + address.b[3] \ + + address.b[4] + address.b[5]) + + +/*! Routing utility function: copies address \a from into a new address that is put into \a to. If \a replaceWithZeros is set \a from will be replaced by an empty address. @@ -67,8 +66,7 @@ l2cap_copy_address(const sockaddr *from, sockaddr **to, } -/*! - Routing utility function: applies \a mask to given \a address and puts +/*! Routing utility function: applies \a mask to given \a address and puts the resulting address into \a result. \return B_OK if the mask has been applied \return B_BAD_VALUE if \a address or \a mask is NULL @@ -84,8 +82,7 @@ l2cap_mask_address(const sockaddr *address, const sockaddr *mask, } -/*! - Checks if the given \a address is the empty address. By default, the port +/*! Checks if the given \a address is the empty address. By default, the port is checked, too, but you can avoid that by passing \a checkPort = false. \return true if \a address is NULL, uninitialized or the empty address, false if not @@ -103,8 +100,8 @@ l2cap_is_empty_address(const sockaddr *address, bool checkPort) /*! Checks if the given \a address is L2CAP address. - \return false if \a address is NULL, or with family different from AF_BLUETOOTH - true if it has AF_BLUETOOTH address family + \return false if \a address is NULL, or with family different from + AF_BLUETOOTH true if it has AF_BLUETOOTH address family */ static bool l2cap_is_same_family(const sockaddr *address) @@ -115,8 +112,8 @@ l2cap_is_same_family(const sockaddr *address) return address->sa_family == AF_BLUETOOTH; } -/*! - Compares the IP-addresses of the two given address structures \a a and \a b. + +/*! Compares the IP-addresses of the two given address structures \a a and \a b. \return true if IP-addresses of \a a and \a b are equal, false if not */ static bool @@ -134,8 +131,7 @@ l2cap_equal_addresses(const sockaddr *a, const sockaddr *b) } -/*! - Compares the ports of the two given address structures \a a and \a b. +/*! Compares the ports of the two given address structures \a a and \a b. \return true if ports of \a a and \a b are equal, false if not */ static bool @@ -147,10 +143,10 @@ l2cap_equal_ports(const sockaddr *a, const sockaddr *b) } -/*! - Compares the IP-addresses and ports of the two given address structures +/*! Compares the IP-addresses and ports of the two given address structures \a a and \a b. - \return true if IP-addresses and ports of \a a and \a b are equal, false if not + \return true if IP-addresses and ports of \a a and \a b are equal, false if + not. */ static bool l2cap_equal_addresses_and_ports(const sockaddr *a, const sockaddr *b) @@ -168,8 +164,7 @@ l2cap_equal_addresses_and_ports(const sockaddr *a, const sockaddr *b) } -/*! - Applies the given \a mask two \a a and \a b and then checks whether +/*! Applies the given \a mask two \a a and \a b and then checks whether the masked addresses match. \return true if \a a matches \a b after masking both, false if not */ @@ -184,8 +179,7 @@ l2cap_equal_masked_addresses(const sockaddr *a, const sockaddr *b, } -/*! - Routing utility function: determines the least significant bit that is set +/*! Routing utility function: determines the least significant bit that is set in the given \a mask. \return the number of the first bit that is set (0-32, where 32 means that there's no bit set in the mask). @@ -200,8 +194,7 @@ l2cap_first_mask_bit(const sockaddr *_mask) } -/*! - Routing utility function: checks the given \a mask for correctness (which +/*! Routing utility function: checks the given \a mask for correctness (which means that (starting with LSB) consists zero or more unset bits, followed by bits that are all set). \return true if \a mask is ok, false if not @@ -214,8 +207,7 @@ l2cap_check_mask(const sockaddr *_mask) } -/*! - Creates a buffer for the given \a address and prints the address into +/*! Creates a buffer for the given \a address and prints the address into it (hexadecimal representation in host byte order or ''). If \a printPort is set, the port is printed, too. \return B_OK if the address could be printed, \a buffer will point to @@ -270,8 +262,7 @@ l2cap_print_address(const sockaddr *_address, char **_buffer, bool printPort) } -/*! - Determines the port of the given \a address. +/*! Determines the port of the given \a address. \return uint16 representing the port-nr */ static uint16 @@ -284,8 +275,7 @@ l2cap_get_port(const sockaddr *address) } -/*! - Sets the port of the given \a address to \a port. +/*! Sets the port of the given \a address to \a port. \return B_OK if the port has been set \return B_BAD_VALUE if \a address is NULL */ @@ -300,8 +290,7 @@ l2cap_set_port(sockaddr *address, uint16 port) } -/*! - Sets \a address to \a from. +/*! Sets \a address to \a from. \return B_OK if \a from has been copied into \a address \return B_BAD_VALUE if either \a address or \a from is NULL \return B_MISMATCHED_VALUES if from is not of family AF_BLUETOOTH @@ -346,8 +335,7 @@ l2cap_update_to(sockaddr *_address, const sockaddr *_from) } -/*! - Sets \a address to the empty address (0.0.0.0). +/*! Sets \a address to the empty address. \return B_OK if \a address has been set \return B_BAD_VALUE if \a address is NULL */ @@ -366,14 +354,28 @@ l2cap_set_to_empty_address(sockaddr *address) static status_t l2cap_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast, - sockaddr *_address, sockaddr *_mask) + const sockaddr *_address, const sockaddr *_mask) { - - return B_OK; + // TODO: not implemented + return B_ERROR; } -/*! - Computes a hash-value of the given addresses \a ourAddress + +/*! Computes a hash value of the given \a address. + \return uint32 representing the hash value +*/ +static uint32 +l2cap_hash_address(const struct sockaddr* _address, bool includePort) +{ + const sockaddr_l2cap* address = (const sockaddr_l2cap*)_address; + if (address == NULL || address->l2cap_len == 0) + return 0; + + return address->l2cap_psm ^ L2CAP_CHECKSUM(address->l2cap_bdaddr); +} + + +/*! Computes a hash-value of the given addresses \a ourAddress and \a peerAddress. \return uint32 representing the hash-value */ @@ -389,8 +391,7 @@ l2cap_hash_address_pair(const sockaddr *ourAddress, const sockaddr *peerAddress) } -/*! - Adds the given \a address to the IP-checksum \a checksum. +/*! Adds the given \a address to the IP-checksum \a checksum. \return B_OK if \a address has been added to the checksum \return B_BAD_VALUE if either \a address or \a checksum is NULL */ @@ -432,6 +433,7 @@ net_address_module_info gL2cap4AddressModule = { l2cap_set_to_empty_address, l2cap_set_to_defaults, l2cap_update_to, + l2cap_hash_address, l2cap_hash_address_pair, l2cap_checksum_address, NULL // get_loopback_address diff --git a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp index bb827ec3f3..481d4555d7 100644 --- a/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/TCPEndpoint.cpp @@ -2127,7 +2127,7 @@ TCPEndpoint::_PrepareSendPath(const sockaddr* peer) // make sure connection does not already exist status_t status = fManager->SetConnection(this, *LocalAddress(), peer, - fRoute->interface->address); + fRoute->interface_address->local); if (status < B_OK) return status; diff --git a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp index e48301bf1f..e36cc9e0ed 100644 --- a/src/add-ons/kernel/network/protocols/tcp/tcp.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/tcp.cpp @@ -660,10 +660,11 @@ tcp_receive_data(net_buffer* buffer) { TRACE(("TCP: Received buffer %p\n", buffer)); - if (buffer->interface == NULL || buffer->interface->domain == NULL) + if (buffer->interface_address == NULL + || buffer->interface_address->domain == NULL) return B_ERROR; - net_domain* domain = buffer->interface->domain; + net_domain* domain = buffer->interface_address->domain; net_address_module_info* addressModule = domain->address_module; NetBufferHeaderReader bufferHeader(buffer); diff --git a/src/add-ons/kernel/network/protocols/udp/udp.cpp b/src/add-ons/kernel/network/protocols/udp/udp.cpp index 56f125289e..3f2782067c 100644 --- a/src/add-ons/kernel/network/protocols/udp/udp.cpp +++ b/src/add-ons/kernel/network/protocols/udp/udp.cpp @@ -367,7 +367,7 @@ UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint, = gDatalinkModule->get_route(fDomain, address); if (routeToDestination) { status = endpoint->LocalAddress().SetTo( - routeToDestination->interface->address); + routeToDestination->interface_address->local); gDatalinkModule->put_route(fDomain, routeToDestination); if (status < B_OK) return status; @@ -516,8 +516,8 @@ UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer) sockaddr *peerAddr = buffer->source; sockaddr *broadcastAddr = buffer->destination; sockaddr *mask = NULL; - if (buffer->interface) - mask = (sockaddr *)buffer->interface->mask; + if (buffer->interface_address != NULL) + mask = (sockaddr *)buffer->interface_address->mask; TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer); @@ -731,7 +731,7 @@ UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer) std::min(buffer->size, sizeof(udp_header))) != B_OK) return B_BAD_VALUE; - net_domain* domain = buffer->interface->domain; + net_domain* domain = buffer->interface_address->domain; net_address_module_info* addressModule = domain->address_module; SocketAddress source(addressModule, buffer->source); @@ -760,13 +760,14 @@ UdpEndpointManager::Deframe(net_buffer *buffer) udp_header &header = bufferHeader.Data(); - if (buffer->interface == NULL || buffer->interface->domain == NULL) { + if (buffer->interface_address == NULL + || buffer->interface_address->domain == NULL) { TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain " - "specified (interface %p).", buffer->interface); + "specified (interface address %p).", buffer->interface_address); return B_BAD_VALUE; } - net_domain *domain = buffer->interface->domain; + net_domain *domain = buffer->interface_address->domain; net_address_module_info *addressModule = domain->address_module; SocketAddress source(addressModule, buffer->source); @@ -869,11 +870,11 @@ UdpEndpointManager::_GetDomain(net_domain *domain, bool create) UdpDomainSupport* UdpEndpointManager::_GetDomain(net_buffer* buffer) { - if (buffer->interface == NULL) + if (buffer->interface_address == NULL) return NULL; MutexLocker _(fLock); - return _GetDomain(buffer->interface->domain, false); + return _GetDomain(buffer->interface_address->domain, false); // TODO: we don't want to hold to the manager's lock during the // whole RX path, we may not hold an endpoint's lock with the // manager lock held. @@ -1313,38 +1314,42 @@ init_udp() if (status != B_OK) goto err1; - status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_IP, + status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, + IPPROTO_IP, "network/protocols/udp/v1", "network/protocols/ipv4/v1", NULL); if (status < B_OK) goto err1; - status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, IPPROTO_IP, + status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, + IPPROTO_IP, "network/protocols/udp/v1", "network/protocols/ipv6/v1", NULL); if (status < B_OK) goto err1; - status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP, + status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, + IPPROTO_UDP, "network/protocols/udp/v1", "network/protocols/ipv4/v1", NULL); if (status < B_OK) goto err1; - status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, + status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, + IPPROTO_UDP, "network/protocols/udp/v1", "network/protocols/ipv6/v1", NULL); if (status < B_OK) goto err1; - status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP, - "network/protocols/udp/v1"); + status = gStackModule->register_domain_receiving_protocol(AF_INET, + IPPROTO_UDP, "network/protocols/udp/v1"); if (status < B_OK) goto err1; - status = gStackModule->register_domain_receiving_protocol(AF_INET6, IPPROTO_UDP, - "network/protocols/udp/v1"); + status = gStackModule->register_domain_receiving_protocol(AF_INET6, + IPPROTO_UDP, "network/protocols/udp/v1"); if (status < B_OK) goto err1; diff --git a/src/add-ons/kernel/network/protocols/unix/UnixAddress.cpp b/src/add-ons/kernel/network/protocols/unix/UnixAddress.cpp index 0f580e5f4f..6ec09e2d25 100644 --- a/src/add-ons/kernel/network/protocols/unix/UnixAddress.cpp +++ b/src/add-ons/kernel/network/protocols/unix/UnixAddress.cpp @@ -217,7 +217,7 @@ unix_mask_address(const sockaddr *address, const sockaddr *mask, static status_t unix_set_to_defaults(sockaddr *defaultMask, sockaddr *defaultBroadcast, - sockaddr *address, sockaddr *netmask) + const sockaddr *address, const sockaddr *netmask) { if (address == NULL) return B_BAD_VALUE; @@ -246,8 +246,9 @@ unix_update_to(sockaddr *address, const sockaddr *from) static uint32 -hash_address(const sockaddr_un* address) +unix_hash_address(const sockaddr* _address, bool includePort) { + sockaddr_un* address = (sockaddr_un*)_address; if (address == NULL) return 0; @@ -264,8 +265,8 @@ hash_address(const sockaddr_un* address) static uint32 unix_hash_address_pair(const sockaddr *ourAddress, const sockaddr *peerAddress) { - return hash_address((sockaddr_un*)ourAddress) * 17 - + hash_address((sockaddr_un*)peerAddress); + return unix_hash_address(ourAddress, false) * 17 + + unix_hash_address(peerAddress, false); } @@ -309,6 +310,7 @@ net_address_module_info gAddressModule = { unix_set_to_empty_address, unix_set_to_defaults, unix_update_to, + unix_hash_address, unix_hash_address_pair, unix_checksum_address, NULL // get_loopback_address diff --git a/src/add-ons/kernel/network/stack/Jamfile b/src/add-ons/kernel/network/stack/Jamfile index ed7355c0fc..97d8e71199 100644 --- a/src/add-ons/kernel/network/stack/Jamfile +++ b/src/add-ons/kernel/network/stack/Jamfile @@ -17,6 +17,7 @@ UsePrivateHeaders net shared ; KernelAddon stack : ancillary_data.cpp datalink.cpp + device_interfaces.cpp domains.cpp interfaces.cpp net_buffer.cpp diff --git a/src/add-ons/kernel/network/stack/datalink.cpp b/src/add-ons/kernel/network/stack/datalink.cpp index 532d897d95..6ea774556f 100644 --- a/src/add-ons/kernel/network/stack/datalink.cpp +++ b/src/add-ons/kernel/network/stack/datalink.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -9,30 +9,35 @@ #include "datalink.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "device_interfaces.h" #include "domains.h" #include "interfaces.h" #include "routes.h" #include "stack_private.h" #include "utility.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -// TODO: this is only needed for IPv6 multicast route code; -// remove it when the code will be refactored -#include +//#define TRACE_DATALINK +#ifdef TRACE_DATALINK +# define TRACE(x...) dprintf(STACK_DEBUG_PREFIX x) +#else +# define TRACE(x...) ; +#endif struct datalink_protocol : net_protocol { @@ -45,190 +50,86 @@ struct interface_protocol : net_datalink_protocol { }; -/*! A service thread for each device interface. It just reads as many packets - as availabe, deframes them, and puts them into the receive queue of the - device interface. -*/ -static status_t -device_reader_thread(void* _interface) -{ - net_device_interface* interface = (net_device_interface*)_interface; - net_device* device = interface->device; - status_t status = B_OK; - - RecursiveLocker locker(interface->receive_lock); - - while ((device->flags & IFF_UP) != 0) { - locker.Unlock(); - - net_buffer* buffer; - status = device->module->receive_data(device, &buffer); - - locker.Lock(); - - if (status == B_OK) { - // feed device monitors - DeviceMonitorList::Iterator iterator = - interface->monitor_funcs.GetIterator(); - while (net_device_monitor* monitor = iterator.Next()) { - monitor->receive(monitor, buffer); - } - - buffer->interface = NULL; - buffer->type = interface->deframe_func(interface->device, buffer); - if (buffer->type < 0) { - gNetBufferModule.free(buffer); - continue; - } - - fifo_enqueue_buffer(&interface->receive_queue, buffer); - } else { - // In case of error, give the other threads some - // time to run since this is a high priority time thread. - snooze(10000); - } - } - - return status; -} - - -static struct sockaddr** -interface_address(net_interface* interface, int32 option) +#ifdef TRACE_DATALINK + + +static const char* +option_to_string(int32 option) { +# define CODE(x) case x: return #x; switch (option) { - case SIOCSIFADDR: - case SIOCGIFADDR: - return &interface->address; + CODE(SIOCADDRT) /* add route */ + CODE(SIOCDELRT) /* delete route */ + CODE(SIOCSIFADDR) /* set interface address */ + CODE(SIOCGIFADDR) /* get interface address */ + CODE(SIOCSIFDSTADDR) /* set point-to-point address */ + CODE(SIOCGIFDSTADDR) /* get point-to-point address */ + CODE(SIOCSIFFLAGS) /* set interface flags */ + CODE(SIOCGIFFLAGS) /* get interface flags */ + CODE(SIOCGIFBRDADDR) /* get broadcast address */ + CODE(SIOCSIFBRDADDR) /* set broadcast address */ + CODE(SIOCGIFCOUNT) /* count interfaces */ + CODE(SIOCGIFCONF) /* get interface list */ + CODE(SIOCGIFINDEX) /* interface name -> index */ + CODE(SIOCGIFNAME) /* interface index -> name */ + CODE(SIOCGIFNETMASK) /* get net address mask */ + CODE(SIOCSIFNETMASK) /* set net address mask */ + CODE(SIOCGIFMETRIC) /* get interface metric */ + CODE(SIOCSIFMETRIC) /* set interface metric */ + CODE(SIOCDIFADDR) /* delete interface address */ + CODE(SIOCAIFADDR) /* configure interface alias */ + CODE(SIOCADDMULTI) /* add multicast address */ + CODE(SIOCDELMULTI) /* delete multicast address */ + CODE(SIOCGIFMTU) /* get interface MTU */ + CODE(SIOCSIFMTU) /* set interface MTU */ + CODE(SIOCSIFMEDIA) /* set net media */ + CODE(SIOCGIFMEDIA) /* get net media */ - case SIOCSIFNETMASK: - case SIOCGIFNETMASK: - return &interface->mask; + CODE(SIOCGRTSIZE) /* get route table size */ + CODE(SIOCGRTTABLE) /* get route table */ + CODE(SIOCGETRT) /* get route information for destination */ - case SIOCSIFBRDADDR: - case SIOCSIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCGIFDSTADDR: - return &interface->destination; + CODE(SIOCGIFSTATS) /* get interface stats */ + CODE(SIOCGIFTYPE) /* get interface type */ + + CODE(SIOCSPACKETCAP) /* Start capturing packets on an interface */ + CODE(SIOCCPACKETCAP) /* Stop capturing packets on an interface */ + + CODE(SIOCSHIWAT) /* set high watermark */ + CODE(SIOCGHIWAT) /* get high watermark */ + CODE(SIOCSLOWAT) /* set low watermark */ + CODE(SIOCGLOWAT) /* get low watermark */ + CODE(SIOCATMARK) /* at out-of-band mark? */ + CODE(SIOCSPGRP) /* set process group */ + CODE(SIOCGPGRP) /* get process group */ + + CODE(SIOCGPRIVATE_0) /* device private 0 */ + CODE(SIOCGPRIVATE_1) /* device private 1 */ + CODE(SIOCSDRVSPEC) /* set driver-specific parameters */ + CODE(SIOCGDRVSPEC) /* get driver-specific parameters */ + + CODE(SIOCSIFGENERIC) /* generic IF set op */ + CODE(SIOCGIFGENERIC) /* generic IF get op */ default: - return NULL; + static char buffer[24]; + snprintf(buffer, sizeof(buffer), "%" B_PRId32, option); + return buffer; } +# undef CODE } -/*! Removes the default routes as set by add_default_routes() again. */ -static void -remove_default_routes(net_interface_private* interface, int32 option) -{ - net_route route; - route.destination = interface->address; - route.gateway = NULL; - route.interface = interface; - - if (interface->mask != NULL - && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) { - route.mask = interface->mask; - route.flags = 0; - remove_route(interface->domain, &route); - } - - if (option == SIOCSIFADDR) { - route.mask = NULL; - route.flags = RTF_LOCAL | RTF_HOST; - remove_route(interface->domain, &route); - } - - // for IPv6 remove multicast route (ff00::/8) - // TODO: move this code - if (interface->address->sa_family == AF_INET6) { - sockaddr_in6 address; - memset(&address, 0, sizeof(sockaddr_in6)); - address.sin6_family = AF_INET6; - address.sin6_len = sizeof(sockaddr_in6); - address.sin6_addr.s6_addr[0] = 0xff; - - route.destination = (sockaddr*)&address; - route.mask = (sockaddr*)&address; - route.flags = 0; - remove_route(interface->domain, &route); - } -} - - -/*! Adds the default routes that every interface needs, ie. the local host - route, and one for the subnet (if set). -*/ -static void -add_default_routes(net_interface_private* interface, int32 option) -{ - net_route route; - route.destination = interface->address; - route.gateway = NULL; - route.interface = interface; - - if (interface->mask != NULL - && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) { - route.mask = interface->mask; - route.flags = 0; - add_route(interface->domain, &route); - } - - if (option == SIOCSIFADDR) { - route.mask = NULL; - route.flags = RTF_LOCAL | RTF_HOST; - add_route(interface->domain, &route); - } - - // for IPv6 add multicast route (ff00::/8) - // TODO: move this code - if (interface->address->sa_family == AF_INET6) { - sockaddr_in6 address; - memset(&address, 0, sizeof(sockaddr_in6)); - address.sin6_family = AF_INET6; - address.sin6_len = sizeof(sockaddr_in6); - address.sin6_addr.s6_addr[0] = 0xff; - - route.destination = (sockaddr*)&address; - route.mask = (sockaddr*)&address; - route.flags = 0; - add_route(interface->domain, &route); - } -} - - -static sockaddr* -reallocate_address(sockaddr** _address, uint32 size) -{ - sockaddr* address = *_address; - - size = max_c(size, sizeof(struct sockaddr)); - if (address != NULL && address->sa_len >= size) - return address; - - address = (sockaddr*)malloc(size); - if (address == NULL) - return NULL; - - free(*_address); - *_address = address; - - return address; -} - - -static void -free_address(sockaddr** _address) -{ - free(*_address); - *_address = NULL; -} +#endif // TRACE_DATALINK static status_t -datalink_control_interface(net_domain_private* domain, int32 option, - void* value, size_t* _length, size_t expected, bool getByName) +get_interface_name_or_index(net_domain* domain, int32 option, void* value, + size_t* _length) { + ASSERT(option == SIOCGIFINDEX || option == SIOCGIFNAME); + + size_t expected = option == SIOCGIFINDEX ? IF_NAMESIZE : sizeof(ifreq); if (*_length < expected) return B_BAD_VALUE; @@ -238,34 +139,21 @@ datalink_control_interface(net_domain_private* domain, int32 option, if (user_memcpy(&request, value, expected) < B_OK) return B_BAD_ADDRESS; - RecursiveLocker _(domain->lock); net_interface* interface = NULL; - - if (getByName) - interface = find_interface(domain, request.ifr_name); + if (option == SIOCGIFINDEX) + interface = get_interface(domain, request.ifr_name); else - interface = find_interface(domain, request.ifr_index); + interface = get_interface(domain, request.ifr_index); - status_t status = interface == NULL ? ENODEV : B_OK; + if (interface == NULL) + return B_BAD_VALUE; - switch (option) { - case SIOCGIFINDEX: - if (interface) - request.ifr_index = interface->index; - else - request.ifr_index = 0; - break; + if (option == SIOCGIFINDEX) + request.ifr_index = interface->index; + else + strlcpy(request.ifr_name, interface->name, IF_NAMESIZE); - case SIOCGIFNAME: - if (interface) - strlcpy(request.ifr_name, interface->name, IF_NAMESIZE); - else - status = B_BAD_VALUE; // TODO: should be ENXIO? - break; - } - - if (status < B_OK) - return status; + *_length = sizeof(ifreq); return user_memcpy(value, &request, sizeof(ifreq)); } @@ -278,6 +166,9 @@ status_t datalink_control(net_domain* _domain, int32 option, void* value, size_t* _length) { + TRACE("%s(domain %p, option %s, value %p, length %zu)\n", __FUNCTION__, + _domain, option_to_string(option), value, *_length); + net_domain_private* domain = (net_domain_private*)_domain; if (domain == NULL || domain->family == AF_LINK) { // the AF_LINK family is already handled completely in the link protocol @@ -286,37 +177,72 @@ datalink_control(net_domain* _domain, int32 option, void* value, switch (option) { case SIOCGIFINDEX: - return datalink_control_interface(domain, option, value, _length, - IF_NAMESIZE, true); case SIOCGIFNAME: - return datalink_control_interface(domain, option, value, _length, - sizeof(ifreq), false); - - case SIOCDIFADDR: - case SIOCSIFFLAGS: - { - struct ifreq request; - if (user_memcpy(&request, value, sizeof(struct ifreq)) < B_OK) - return B_BAD_ADDRESS; - - return domain_interface_control(domain, option, &request); - } + return get_interface_name_or_index(domain, option, value, _length); case SIOCAIFADDR: { // add new interface address + if (*_length < sizeof(struct ifaliasreq)) + return B_BAD_VALUE; + + struct ifaliasreq request; + if (user_memcpy(&request, value, sizeof(struct ifaliasreq)) < B_OK) + return B_BAD_ADDRESS; + + Interface* interface = get_interface(domain, request.ifra_name); + if (interface != NULL) { + // A new alias is added to this interface + status_t status = add_interface_address(interface, domain, + request); + notify_interface_changed(interface); + return status; + } + + // A new interface needs to be added + net_device_interface* deviceInterface + = get_device_interface(request.ifra_name); + if (deviceInterface == NULL) + return ENODEV; + + status_t status = add_interface(request.ifra_name, domain, request, + deviceInterface); + + put_device_interface(deviceInterface); + return status; + } + + case SIOCDIFADDR: + { + // remove interface (address) struct ifreq request; if (user_memcpy(&request, value, sizeof(struct ifreq)) < B_OK) return B_BAD_ADDRESS; - return add_interface_to_domain(domain, request); - } + Interface* interface = get_interface(domain, request.ifr_name); + if (interface == NULL) + return B_BAD_VALUE; + status_t status; + + if (request.ifr_addr.sa_family != AF_UNSPEC + || request.ifr_addr.sa_len != 0) { + // TODO: remove interface if this was the last address? + status = interface->Control(domain, SIOCDIFADDR, request, + (ifreq*)value, *_length); + } else + status = remove_interface(interface); + + interface->ReleaseReference(); + + return status; + } + case SIOCGIFCOUNT: { // count number of interfaces struct ifconf config; - config.ifc_value = count_domain_interfaces(); + config.ifc_value = count_interfaces(); return user_memcpy(value, &config, sizeof(struct ifconf)); } @@ -328,11 +254,13 @@ datalink_control(net_domain* _domain, int32 option, void* value, if (user_memcpy(&config, value, sizeof(struct ifconf)) < B_OK) return B_BAD_ADDRESS; - status_t result = list_domain_interfaces(config.ifc_buf, - (size_t*)&config.ifc_len); - if (result != B_OK) - return result; + size_t size = config.ifc_len; + status_t status + = list_interfaces(domain->family, config.ifc_buf, &size); + if (status != B_OK) + return status; + config.ifc_len = (int)size; return user_memcpy(value, &config, sizeof(struct ifconf)); } @@ -358,21 +286,23 @@ datalink_control(net_domain* _domain, int32 option, void* value, default: { + if (*_length < sizeof(struct ifreq)) + return B_BAD_VALUE; + // try to pass the request to an existing interface struct ifreq request; if (user_memcpy(&request, value, sizeof(struct ifreq)) < B_OK) return B_BAD_ADDRESS; - RecursiveLocker _(domain->lock); - - net_interface* interface = find_interface(domain, - request.ifr_name); + Interface* interface = get_interface(domain, request.ifr_name); if (interface == NULL) return B_BAD_VALUE; - // pass the request into the datalink protocol stack - return interface->first_info->control( - interface->first_protocol, option, value, *_length); + status_t status = interface->Control(domain, option, request, + (ifreq*)value, *_length); + + interface->ReleaseReference(); + return status; } } return B_BAD_VALUE; @@ -382,26 +312,35 @@ datalink_control(net_domain* _domain, int32 option, void* value, status_t datalink_send_data(struct net_route* route, net_buffer* buffer) { - net_interface_private* interface = - (net_interface_private*)route->interface; + TRACE("%s(route %p, buffer %p)\n", __FUNCTION__, route, buffer); + + net_interface_address* address = route->interface_address; + Interface* interface = (Interface*)address->interface; //dprintf("send buffer (%ld bytes) to interface %s (route flags %lx)\n", // buffer->size, interface->name, route->flags); - if (route->flags & RTF_REJECT) + if ((route->flags & RTF_REJECT) != 0) { + TRACE(" rejected route\n"); return ENETUNREACH; - - if (route->flags & RTF_LOCAL) { - // we set the interface here so the buffer is delivered directly - // to the domain in interfaces.cpp:device_consumer_thread() - buffer->interface = interface; - // this one goes back to the domain directly - return fifo_enqueue_buffer( - &interface->device_interface->receive_queue, buffer); } - if (route->flags & RTF_GATEWAY) { - // this route involves a gateway, we need to use the gateway address + if ((route->flags & RTF_LOCAL) != 0) { + TRACE(" local route\n"); + + // We set the interface address here, so the buffer is delivered + // directly to the domain in interfaces.cpp:device_consumer_thread() + buffer->interface_address = address; + + // this one goes back to the domain directly + return fifo_enqueue_buffer( + &interface->DeviceInterface()->receive_queue, buffer); + } + + if ((route->flags & RTF_GATEWAY) != 0) { + TRACE(" gateway route\n"); + + // This route involves a gateway, we need to use the gateway address // instead of the destination address: if (route->gateway == NULL) return B_MISMATCHED_VALUES; @@ -409,7 +348,9 @@ datalink_send_data(struct net_route* route, net_buffer* buffer) } // this goes out to the datalink protocols - return interface->first_info->send_data(interface->first_protocol, buffer); + domain_datalink* datalink + = interface->DomainDatalink(address->domain->family); + return datalink->first_info->send_data(datalink->first_protocol, buffer); } @@ -417,11 +358,14 @@ status_t datalink_send_datagram(net_protocol* protocol, net_domain* domain, net_buffer* buffer) { + TRACE("%s(%p, domain %p, buffer %p)\n", __FUNCTION__, protocol, domain, + buffer); + if (protocol == NULL && domain == NULL) return B_BAD_VALUE; - net_protocol_module_info* module = protocol ? protocol->module - : domain->module; + net_protocol_module_info* module = protocol != NULL + ? protocol->module : domain->module; if (domain == NULL) domain = protocol->module->get_domain(protocol); @@ -434,7 +378,10 @@ datalink_send_datagram(net_protocol* protocol, net_domain* domain, &route); } else status = get_buffer_route(domain, buffer, &route); - if (status < B_OK) + + TRACE(" route status: %s\n", strerror(status)); + + if (status != B_OK) return status; status = module->send_routed_data(protocol, route, buffer); @@ -450,132 +397,173 @@ datalink_send_datagram(net_protocol* protocol, net_domain* domain, \param _matchedType will be set to either zero or MSG_BCAST if non-NULL. */ bool -datalink_is_local_address(net_domain* _domain, const struct sockaddr* address, - net_interface** _interface, uint32* _matchedType) +datalink_is_local_address(net_domain* domain, const struct sockaddr* address, + net_interface_address** _interfaceAddress, uint32* _matchedType) { - net_domain_private* domain = (net_domain_private*)_domain; - if (domain == NULL || address == NULL) + TRACE("%s(domain %p, address %s)\n", __FUNCTION__, domain, + AddressString(domain, address).Data()); + + if (domain == NULL || address == NULL + || domain->family != address->sa_family) return false; - RecursiveLocker locker(domain->lock); - - net_interface* interface = NULL; uint32 matchedType = 0; - while (true) { - interface = (net_interface*)list_get_next_item( - &domain->interfaces, interface); - if (interface == NULL) - break; - if (interface->address == NULL) - continue; - - // check for matching unicast address first - if (domain->address_module->equal_addresses(interface->address, address)) - break; - - // check for matching broadcast address if interface supports - // broadcasting (IFF_BROADCAST is a link-level flag, so it is - // a property of the device) - if ((interface->device->flags & IFF_BROADCAST) != 0 - && domain->address_module->equal_addresses(interface->destination, - address)) { + InterfaceAddress* interfaceAddress = get_interface_address(address); + if (interfaceAddress == NULL) { + // Check for matching broadcast address + if ((domain->address_module->flags + & NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0) { + interfaceAddress + = get_interface_address_for_destination(domain, address); matchedType = MSG_BCAST; - break; + } + if (interfaceAddress == NULL) { + TRACE(" no\n"); + return false; } } - if (interface == NULL) - return false; + TRACE(" it is, interface address %p\n", interfaceAddress); + + if (_interfaceAddress != NULL) + *_interfaceAddress = interfaceAddress; + else + interfaceAddress->ReleaseReference(); - if (_interface != NULL) - *_interface = interface; if (_matchedType != NULL) *_matchedType = matchedType; + return true; } /*! Tests if \a address is a local link address in the domain. - \param unconfigured only unconfigured interfaces are taken into account. - \param _interface will be set to the interface belonging to that address - if non-NULL. + \param unconfiguredOnly only unconfigured interfaces are taken into account. + \param _interfaceAddress will be set to the first address of the interface + and domain belonging to that address if non-NULL. */ bool -datalink_is_local_link_address(net_domain* _domain, bool unconfigured, - const struct sockaddr* address, net_interface** _interface) +datalink_is_local_link_address(net_domain* domain, bool unconfiguredOnly, + const struct sockaddr* address, net_interface_address** _interfaceAddress) { - net_domain_private* domain = (net_domain_private*)_domain; if (domain == NULL || address == NULL || address->sa_family != AF_LINK) return false; - RecursiveLocker locker(domain->lock); + InterfaceAddress* interfaceAddress = get_interface_address_for_link(domain, + address, unconfiguredOnly); + if (interfaceAddress == NULL) + return false; - sockaddr_dl& linkAddress = *(sockaddr_dl*)address; - net_interface* interface = NULL; + if (_interfaceAddress != NULL) + *_interfaceAddress = interfaceAddress; + else + interfaceAddress->ReleaseReference(); - while (true) { - interface = (net_interface*)list_get_next_item( - &domain->interfaces, interface); - if (interface == NULL) - break; - - if (unconfigured && interface->address != NULL - && (interface->flags & IFF_CONFIGURING) == 0) - continue; - - if (linkAddress.sdl_alen == interface->device->address.length - && memcmp(LLADDR(&linkAddress), interface->device->address.data, - linkAddress.sdl_alen) == 0) { - // link address matches - if (_interface != NULL) - *_interface = interface; - return true; - } - } - - return false; -} - - -net_interface* -datalink_get_interface_with_address(net_domain* _domain, - const sockaddr* address) -{ - net_domain_private* domain = (net_domain_private*)_domain; - if (domain == NULL) - return NULL; - - RecursiveLocker _(domain->lock); - - net_interface* interface = NULL; - - while (true) { - interface = (net_interface*)list_get_next_item( - &domain->interfaces, interface); - if (interface == NULL) - break; - - if (address == NULL) - return interface; - - if (domain->address_module->equal_addresses(interface->address, - address)) - return interface; - } - - return NULL; + return true; } net_interface* datalink_get_interface(net_domain* domain, uint32 index) { - if (index == 0) - return datalink_get_interface_with_address(domain, NULL); + return get_interface(domain, index); +} - return find_interface(domain, index); + +net_interface* +datalink_get_interface_with_address(const sockaddr* address) +{ + InterfaceAddress* interfaceAddress = get_interface_address(address); + if (interfaceAddress == NULL) + return NULL; + + Interface* interface = static_cast(interfaceAddress->interface); + + interface->AcquireReference(); + interfaceAddress->ReleaseReference(); + + return interface; +} + + +static void +datalink_put_interface(net_interface* interface) +{ + if (interface == NULL) + return; + + ((Interface*)interface)->ReleaseReference(); +} + + +net_interface_address* +datalink_get_interface_address(const struct sockaddr* address) +{ + return get_interface_address(address); +} + + +/*! Returns a reference to the next address of the given interface in + \a _address. When you call this function the first time, \a _address must + point to a NULL address. Upon the next call, the reference to the previous + address is taken over again. + + If you do not traverse the list to the end, you'll have to manually release + the reference to the address where you stopped. + + \param interface The interface whose address list should be iterated over. + \param _address A pointer to the location where the next address should + be stored. + + \return \c true if an address reference was returned, \c false if not. +*/ +bool +datalink_get_next_interface_address(net_interface* _interface, + net_interface_address** _address) +{ + Interface* interface = (Interface*)_interface; + + InterfaceAddress* address = (InterfaceAddress*)*_address; + bool gotOne = interface->GetNextAddress(&address); + *_address = address; + + return gotOne; +} + + +void +datalink_put_interface_address(net_interface_address* address) +{ + if (address == NULL) + return; + + ((InterfaceAddress*)address)->ReleaseReference(); +} + + +status_t +datalink_join_multicast(net_interface* _interface, net_domain* domain, + const struct sockaddr* address) +{ + Interface* interface = (Interface*)_interface; + domain_datalink* datalink = interface->DomainDatalink(domain->family); + + return datalink->first_info->join_multicast(datalink->first_protocol, + address); +} + + +status_t +datalink_leave_multicast(net_interface* _interface, net_domain* domain, + const struct sockaddr* address) +{ + Interface* interface = (Interface*)_interface; + domain_datalink* datalink = interface->DomainDatalink(domain->family); + + return datalink->first_info->leave_multicast(datalink->first_protocol, + address); } @@ -597,15 +585,16 @@ datalink_std_ops(int32 op, ...) status_t -interface_protocol_init(struct net_interface* _interface, +interface_protocol_init(net_interface* interface, net_domain* domain, net_datalink_protocol** _protocol) { - net_interface_private* interface = (net_interface_private*)_interface; - - interface_protocol* protocol = new (std::nothrow) interface_protocol; + interface_protocol* protocol = new(std::nothrow) interface_protocol; if (protocol == NULL) return B_NO_MEMORY; + TRACE("%s(%p, interface %p - %s, domain %p)\n", __FUNCTION__, protocol, + interface, interface->name, domain); + protocol->device_module = interface->device->module; protocol->device = interface->device; @@ -617,6 +606,8 @@ interface_protocol_init(struct net_interface* _interface, status_t interface_protocol_uninit(net_datalink_protocol* protocol) { + TRACE("%s(%p)\n", __FUNCTION__, protocol); + delete protocol; return B_OK; } @@ -626,9 +617,10 @@ status_t interface_protocol_send_data(net_datalink_protocol* _protocol, net_buffer* buffer) { + TRACE("%s(%p, buffer %p)\n", __FUNCTION__, _protocol, buffer); + interface_protocol* protocol = (interface_protocol*)_protocol; - net_interface_private* interface - = (net_interface_private*)protocol->interface; + Interface* interface = (Interface*)protocol->interface; // TODO: Need to think about this locking. We can't obtain the // RX Lock here (nor would it make sense) as the ARP @@ -637,7 +629,7 @@ interface_protocol_send_data(net_datalink_protocol* _protocol, // protocol). DeviceMonitorList::Iterator iterator = - interface->device_interface->monitor_funcs.GetIterator(); + interface->DeviceInterface()->monitor_funcs.GetIterator(); while (iterator.HasNext()) { net_device_monitor* monitor = iterator.Next(); monitor->receive(monitor, buffer); @@ -648,42 +640,9 @@ interface_protocol_send_data(net_datalink_protocol* _protocol, status_t -interface_protocol_up(net_datalink_protocol* _protocol) +interface_protocol_up(net_datalink_protocol* protocol) { - interface_protocol* protocol = (interface_protocol*)_protocol; - net_device_interface* deviceInterface = - ((net_interface_private*)protocol->interface)->device_interface; - net_device* device = protocol->device; - - // This function is called with the RX lock held. - - if (deviceInterface->up_count != 0) { - deviceInterface->up_count++; - return B_OK; - } - - status_t status = protocol->device_module->up(device); - if (status < B_OK) - return status; - - if (device->module->receive_data != NULL) { - // give the thread a nice name - char name[B_OS_NAME_LENGTH]; - snprintf(name, sizeof(name), "%s reader", device->name); - - deviceInterface->reader_thread = - spawn_kernel_thread(device_reader_thread, name, - B_REAL_TIME_DISPLAY_PRIORITY - 10, deviceInterface); - if (deviceInterface->reader_thread < B_OK) - return deviceInterface->reader_thread; - } - - device->flags |= IFF_UP; - - if (device->module->receive_data != NULL) - resume_thread(deviceInterface->reader_thread); - - deviceInterface->up_count = 1; + TRACE("%s(%p)\n", __FUNCTION__, protocol); return B_OK; } @@ -691,17 +650,18 @@ interface_protocol_up(net_datalink_protocol* _protocol) void interface_protocol_down(net_datalink_protocol* _protocol) { - interface_protocol* protocol = (interface_protocol*)_protocol; - net_device_interface* deviceInterface = - ((net_interface_private*)protocol->interface)->device_interface; + TRACE("%s(%p)\n", __FUNCTION__, _protocol); + + interface_protocol* protocol = (interface_protocol*)_protocol; + Interface* interface = (Interface*)protocol->interface; + net_device_interface* deviceInterface = interface->DeviceInterface(); - // This function is called with the RX lock held. if (deviceInterface->up_count == 0) return; deviceInterface->up_count--; - domain_interface_went_down(protocol->interface); + interface_went_down(interface); if (deviceInterface->up_count > 0) return; @@ -711,92 +671,74 @@ interface_protocol_down(net_datalink_protocol* _protocol) status_t -interface_protocol_control(net_datalink_protocol* _protocol, int32 option, - void* argument, size_t length) +interface_protocol_change_address(net_datalink_protocol* protocol, + net_interface_address* interfaceAddress, int32 option, + const struct sockaddr* oldAddress, const struct sockaddr* newAddress) { - interface_protocol* protocol = (interface_protocol*)_protocol; - net_interface_private* interface - = (net_interface_private*)protocol->interface; + TRACE("%s(%p, interface address %p, option %s, old %p, new %p)\n", + __FUNCTION__, protocol, interfaceAddress, option_to_string(option), + oldAddress, newAddress); switch (option) { case SIOCSIFADDR: case SIOCSIFNETMASK: case SIOCSIFBRDADDR: case SIOCSIFDSTADDR: - { - // set logical interface address - struct ifreq request; - if (user_memcpy(&request, argument, sizeof(struct ifreq)) < B_OK) - return B_BAD_ADDRESS; + case SIOCDIFADDR: + return update_interface_address((InterfaceAddress*)interfaceAddress, + option, oldAddress, newAddress); + } - sockaddr** _address = interface_address(interface, option); - if (_address == NULL) - return B_BAD_VALUE; + return B_OK; +} - // allocate new address if needed - sockaddr* address = reallocate_address(_address, - request.ifr_addr.sa_len); - // copy new address over - if (address != NULL) { - remove_default_routes(interface, option); - memcpy(address, &request.ifr_addr, request.ifr_addr.sa_len); +status_t +interface_protocol_control(net_datalink_protocol* _protocol, int32 option, + void* argument, size_t length) +{ + TRACE("%s(%p, option %s, argument %p, length %zu)\n", __FUNCTION__, + _protocol, option_to_string(option), argument, length); - if (option == SIOCSIFADDR || option == SIOCSIFNETMASK) { - // reset netmask and broadcast addresses to defaults - sockaddr* netmask = NULL; - sockaddr* oldNetmask = NULL; - if (option == SIOCSIFADDR) { - netmask = reallocate_address(&interface->mask, - request.ifr_addr.sa_len); - } else - oldNetmask = address; - - // reset the broadcast address if the address family has such - sockaddr* broadcast; - if ((interface->domain->address_module->flags - & NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0) { - broadcast = reallocate_address(&interface->destination, - request.ifr_addr.sa_len); - } else { - broadcast = NULL; - free_address(&interface->destination); - } - - interface->domain->address_module->set_to_defaults( - netmask, broadcast, interface->address, oldNetmask); - } - - add_default_routes(interface, option); - notify_interface_changed(interface); - } - - return address != NULL ? B_OK : B_NO_MEMORY; - } + interface_protocol* protocol = (interface_protocol*)_protocol; + Interface* interface = (Interface*)protocol->interface; + switch (option) { case SIOCGIFADDR: case SIOCGIFNETMASK: case SIOCGIFBRDADDR: case SIOCGIFDSTADDR: { - // get logical interface address - sockaddr** _address = interface_address(interface, option); - if (_address == NULL) + if (length < sizeof(ifreq)) return B_BAD_VALUE; - struct ifreq request; + ifreq request; + if (user_memcpy(&request, argument, sizeof(struct ifreq)) != B_OK) + return B_BAD_ADDRESS; - sockaddr* address = *_address; - if (address != NULL) - memcpy(&request.ifr_addr, address, address->sa_len); - else { - request.ifr_addr.sa_len = 2; - request.ifr_addr.sa_family = AF_UNSPEC; + InterfaceAddress* interfaceAddress + = get_interface_address(&request.ifr_addr); + if (interfaceAddress == NULL) { + interfaceAddress + = interface->FirstForFamily(protocol->domain->family); + if (interfaceAddress == NULL) + return B_BAD_VALUE; } - // copy address over + size_t maxLength = length - offsetof(ifreq, ifr_addr); + + sockaddr* address = *interfaceAddress->AddressFor(option); + if (address != NULL) { + // Copy address over + return user_memcpy(&((struct ifreq*)argument)->ifr_addr, + address, min_c(address->sa_len, maxLength)); + } + + // Fill in empty address + request.ifr_addr.sa_len = 2; + request.ifr_addr.sa_family = AF_UNSPEC; return user_memcpy(&((struct ifreq*)argument)->ifr_addr, - &request.ifr_addr, request.ifr_addr.sa_len); + &request.ifr_addr, min_c(2, maxLength)); } case SIOCGIFFLAGS: @@ -809,25 +751,11 @@ interface_protocol_control(net_datalink_protocol* _protocol, int32 option, &request.ifr_flags, sizeof(request.ifr_flags)); } - case SIOCGIFPARAM: - { - // get interface parameter - struct ifreq request; - strlcpy(request.ifr_parameter.base_name, interface->base_name, IF_NAMESIZE); - strlcpy(request.ifr_parameter.device, - interface->device_interface->device->name, IF_NAMESIZE); - request.ifr_parameter.sub_type = 0; - // TODO: for now, we ignore the sub type... - - return user_memcpy(&((struct ifreq*)argument)->ifr_parameter, - &request.ifr_parameter, sizeof(request.ifr_parameter)); - } - case SIOCGIFSTATS: { // get stats return user_memcpy(&((struct ifreq*)argument)->ifr_stats, - &interface->device_interface->device->stats, + &interface->DeviceInterface()->device->stats, sizeof(struct ifreq_stats)); } @@ -874,7 +802,7 @@ interface_protocol_control(net_datalink_protocol* _protocol, int32 option, if (user_memcpy(&request, argument, sizeof(struct ifreq)) < B_OK) return B_BAD_ADDRESS; - return interface->device_interface->device->module->set_media( + return interface->DeviceInterface()->device->module->set_media( interface->device, request.ifr_media); } case SIOCGIFMEDIA: @@ -911,7 +839,8 @@ interface_protocol_control(net_datalink_protocol* _protocol, int32 option, case SIOCADDRT: case SIOCDELRT: // interface related route options - return control_routes(interface, option, argument, length); + return control_routes(interface, protocol->domain, option, argument, + length); } return protocol->device_module->control(protocol->device, @@ -950,10 +879,20 @@ net_datalink_module_info gNetDatalinkModule = { datalink_control, datalink_send_data, datalink_send_datagram, + datalink_is_local_address, datalink_is_local_link_address, + datalink_get_interface, datalink_get_interface_with_address, + datalink_put_interface, + + datalink_get_interface_address, + datalink_get_next_interface_address, + datalink_put_interface_address, + + datalink_join_multicast, + datalink_leave_multicast, add_route, remove_route, @@ -976,6 +915,7 @@ net_datalink_protocol_module_info gDatalinkInterfaceProtocolModule = { interface_protocol_send_data, interface_protocol_up, interface_protocol_down, + interface_protocol_change_address, interface_protocol_control, interface_protocol_join_multicast, interface_protocol_leave_multicast, diff --git a/src/add-ons/kernel/network/stack/device_interfaces.cpp b/src/add-ons/kernel/network/stack/device_interfaces.cpp new file mode 100644 index 0000000000..bb728dfa6e --- /dev/null +++ b/src/add-ons/kernel/network/stack/device_interfaces.cpp @@ -0,0 +1,797 @@ +/* + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "device_interfaces.h" +#include "domains.h" +#include "interfaces.h" +#include "stack_private.h" +#include "utility.h" + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + + +//#define TRACE_DEVICE_INTERFACES +#ifdef TRACE_DEVICE_INTERFACES +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +static mutex sLock; +static DeviceInterfaceList sInterfaces; +static uint32 sDeviceIndex; + + +/*! A service thread for each device interface. It just reads as many packets + as availabe, deframes them, and puts them into the receive queue of the + device interface. +*/ +static status_t +device_reader_thread(void* _interface) +{ + net_device_interface* interface = (net_device_interface*)_interface; + net_device* device = interface->device; + status_t status = B_OK; + + RecursiveLocker locker(interface->receive_lock); + + while ((device->flags & IFF_UP) != 0) { + locker.Unlock(); + + net_buffer* buffer; + status = device->module->receive_data(device, &buffer); + + locker.Lock(); + + if (status == B_OK) { + // feed device monitors + DeviceMonitorList::Iterator iterator = + interface->monitor_funcs.GetIterator(); + while (net_device_monitor* monitor = iterator.Next()) { + monitor->receive(monitor, buffer); + } + + buffer->interface_address = NULL; + buffer->type = interface->deframe_func(interface->device, buffer); + if (buffer->type < 0) { + gNetBufferModule.free(buffer); + continue; + } + + fifo_enqueue_buffer(&interface->receive_queue, buffer); + } else { + // In case of error, give the other threads some + // time to run since this is a high priority time thread. + snooze(10000); + } + } + + return status; +} + + +static status_t +device_consumer_thread(void* _interface) +{ + net_device_interface* interface = (net_device_interface*)_interface; + net_device* device = interface->device; + net_buffer* buffer; + + while (true) { + ssize_t status = fifo_dequeue_buffer(&interface->receive_queue, 0, + B_INFINITE_TIMEOUT, &buffer); + if (status != B_OK) { + if (status == B_INTERRUPTED) + continue; + break; + } + + if (buffer->interface_address != NULL) { + // if the interface is already specified, this buffer was + // delivered locally. + if (buffer->interface_address->domain->module->receive_data(buffer) + == B_OK) + buffer = NULL; + } else { + // find handler for this packet + DeviceHandlerList::Iterator iterator = + interface->receive_funcs.GetIterator(); + while (buffer && iterator.HasNext()) { + net_device_handler* handler = iterator.Next(); + + // if the handler returns B_OK, it consumed the buffer + if (handler->type == buffer->type + && handler->func(handler->cookie, device, buffer) == B_OK) + buffer = NULL; + } + } + + if (buffer != NULL) + gNetBufferModule.free(buffer); + } + + return B_OK; +} + + +/*! The domain's device receive handler - this will inject the net_buffers into + the protocol layer (the domain's registered receive handler). +*/ +static status_t +domain_receive_adapter(void* cookie, net_device* device, net_buffer* buffer) +{ + net_domain_private* domain = (net_domain_private*)cookie; + + return domain->module->receive_data(buffer); +} + + +static net_device_interface* +find_device_interface(const char* name) +{ + DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); + + while (net_device_interface* interface = iterator.Next()) { + if (!strcmp(interface->device->name, name)) + return interface; + } + + return NULL; +} + + +static net_device_interface* +allocate_device_interface(net_device* device, net_device_module_info* module) +{ + net_device_interface* interface = new(std::nothrow) net_device_interface; + if (interface == NULL) + return NULL; + + recursive_lock_init(&interface->receive_lock, "interface receive lock"); + + char name[128]; + snprintf(name, sizeof(name), "%s receive queue", device->name); + + if (init_fifo(&interface->receive_queue, name, 16 * 1024 * 1024) < B_OK) + goto error1; + + interface->device = device; + interface->up_count = 0; + interface->ref_count = 1; + interface->deframe_func = NULL; + interface->deframe_ref_count = 0; + + snprintf(name, sizeof(name), "%s consumer", device->name); + + interface->reader_thread = -1; + interface->consumer_thread = spawn_kernel_thread(device_consumer_thread, + name, B_DISPLAY_PRIORITY, interface); + if (interface->consumer_thread < B_OK) + goto error2; + resume_thread(interface->consumer_thread); + + // TODO: proper interface index allocation + device->index = ++sDeviceIndex; + device->module = module; + + sInterfaces.Add(interface); + return interface; + +error2: + uninit_fifo(&interface->receive_queue); +error1: + recursive_lock_destroy(&interface->receive_lock); + delete interface; + + return NULL; +} + + +static void +notify_device_monitors(net_device_interface* interface, int32 event) +{ + RecursiveLocker _(interface->receive_lock); + + DeviceMonitorList::Iterator iterator + = interface->monitor_funcs.GetIterator(); + while (net_device_monitor* monitor = iterator.Next()) { + // it's safe for the "current" item to remove itself. + monitor->event(monitor, event); + } +} + + +#if ENABLE_DEBUGGER_COMMANDS + + +static int +dump_device_interface(int argc, char** argv) +{ + if (argc != 2) { + kprintf("usage: %s [address]\n", argv[0]); + return 0; + } + + net_device_interface* interface + = (net_device_interface*)parse_expression(argv[1]); + + kprintf("device: %p\n", interface->device); + kprintf("reader_thread: %ld\n", interface->reader_thread); + kprintf("up_count: %" B_PRIu32 "\n", interface->up_count); + kprintf("ref_count: %" B_PRId32 "\n", interface->ref_count); + kprintf("deframe_func: %p\n", interface->deframe_func); + kprintf("deframe_ref_count: %" B_PRId32 "\n", interface->ref_count); + kprintf("monitor_funcs:\n"); + kprintf("receive_funcs:\n"); + kprintf("consumer_thread: %ld\n", interface->consumer_thread); + kprintf("receive_lock: %p\n", &interface->receive_lock); + kprintf("receive_queue: %p\n", &interface->receive_queue); + + DeviceMonitorList::Iterator monitorIterator + = interface->monitor_funcs.GetIterator(); + while (monitorIterator.HasNext()) + kprintf(" %p\n", monitorIterator.Next()); + + DeviceHandlerList::Iterator handlerIterator + = interface->receive_funcs.GetIterator(); + while (handlerIterator.HasNext()) + kprintf(" %p\n", handlerIterator.Next()); + + return 0; +} + + +static int +dump_device_interfaces(int argc, char** argv) +{ + DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); + while (net_device_interface* interface = iterator.Next()) { + kprintf(" %p %s\n", interface, interface->device->name); + } + + return 0; +} + + +#endif // ENABLE_DEBUGGER_COMMANDS + + +// #pragma mark - device interfaces + + +net_device_interface* +acquire_device_interface(net_device_interface* interface) +{ + if (interface == NULL || atomic_add(&interface->ref_count, 1) == 0) + return NULL; + + return interface; +} + + +void +get_device_interface_address(net_device_interface* interface, sockaddr* _address) +{ + sockaddr_dl &address = *(sockaddr_dl*)_address; + + address.sdl_family = AF_LINK; + address.sdl_index = interface->device->index; + address.sdl_type = interface->device->type; + address.sdl_nlen = strlen(interface->device->name); + address.sdl_slen = 0; + memcpy(address.sdl_data, interface->device->name, address.sdl_nlen); + + address.sdl_alen = interface->device->address.length; + memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen); + + address.sdl_len = sizeof(sockaddr_dl) - sizeof(address.sdl_data) + + address.sdl_nlen + address.sdl_alen; +} + + +uint32 +count_device_interfaces() +{ + MutexLocker locker(sLock); + + DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); + uint32 count = 0; + + while (iterator.HasNext()) { + iterator.Next(); + count++; + } + + return count; +} + + +/*! Dumps a list of all interfaces into the supplied userland buffer. + If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is + returned. +*/ +status_t +list_device_interfaces(void* _buffer, size_t* bufferSize) +{ + MutexLocker locker(sLock); + + DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); + UserBuffer buffer(_buffer, *bufferSize); + + while (net_device_interface* interface = iterator.Next()) { + ifreq request; + strlcpy(request.ifr_name, interface->device->name, IF_NAMESIZE); + get_device_interface_address(interface, &request.ifr_addr); + + if (buffer.Copy(&request, IF_NAMESIZE + request.ifr_addr.sa_len) == NULL) + return buffer.Status(); + } + + *bufferSize = buffer.ConsumedAmount(); + return B_OK; +} + + +/*! Releases the reference for the interface. When all references are + released, the interface is removed. +*/ +void +put_device_interface(struct net_device_interface* interface) +{ + if (atomic_add(&interface->ref_count, -1) != 1) + return; + + { + MutexLocker locker(sLock); + sInterfaces.Remove(interface); + } + + uninit_fifo(&interface->receive_queue); + status_t status; + wait_for_thread(interface->consumer_thread, &status); + + net_device* device = interface->device; + const char* moduleName = device->module->info.name; + + device->module->uninit_device(device); + put_module(moduleName); + + recursive_lock_destroy(&interface->receive_lock); + delete interface; +} + + +/*! Finds an interface by the specified index and acquires a reference to it. +*/ +struct net_device_interface* +get_device_interface(uint32 index) +{ + MutexLocker locker(sLock); + + // TODO: maintain an array of all device interfaces instead + DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); + while (net_device_interface* interface = iterator.Next()) { + if (interface->device->index == index) { + if (atomic_add(&interface->ref_count, 1) != 0) + return interface; + } + } + + return NULL; +} + + +/*! Finds an interface by the specified name and grabs a reference to it. + If the interface does not yet exist, a new one is created. +*/ +struct net_device_interface* +get_device_interface(const char* name, bool create) +{ + MutexLocker locker(sLock); + + net_device_interface* interface = find_device_interface(name); + if (interface != NULL) { + if (atomic_add(&interface->ref_count, 1) != 0) + return interface; + + // try to recreate interface - it just got removed + } + + if (!create) + return NULL; + + void* cookie = open_module_list("network/devices"); + if (cookie == NULL) + return NULL; + + while (true) { + char moduleName[B_FILE_NAME_LENGTH]; + size_t length = sizeof(moduleName); + if (read_next_module_name(cookie, moduleName, &length) != B_OK) + break; + + TRACE(("get_device_interface: ask \"%s\" for %s\n", moduleName, name)); + + net_device_module_info* module; + if (get_module(moduleName, (module_info**)&module) == B_OK) { + net_device* device; + status_t status = module->init_device(name, &device); + if (status == B_OK) { + interface = allocate_device_interface(device, module); + if (interface != NULL) + return interface; + + module->uninit_device(device); + } + put_module(moduleName); + } + } + + return NULL; +} + + +status_t +up_device_interface(net_device_interface* interface) +{ + net_device* device = interface->device; + + RecursiveLocker locker(interface->receive_lock); + + if (interface->up_count != 0) { + interface->up_count++; + return B_OK; + } + + status_t status = device->module->up(device); + if (status != B_OK) + return status; + + if (device->module->receive_data != NULL) { + // give the thread a nice name + char name[B_OS_NAME_LENGTH]; + snprintf(name, sizeof(name), "%s reader", device->name); + + interface->reader_thread = spawn_kernel_thread(device_reader_thread, + name, B_REAL_TIME_DISPLAY_PRIORITY - 10, interface); + if (interface->reader_thread < B_OK) + return interface->reader_thread; + } + + device->flags |= IFF_UP; + + if (device->module->receive_data != NULL) + resume_thread(interface->reader_thread); + + interface->up_count = 1; + return B_OK; +} + + +void +down_device_interface(net_device_interface* interface) +{ + // Receive lock must be held when calling down_device_interface. + // Known callers are `interface_protocol_down' which gets + // here via one of the following paths: + // + // - domain_interface_control() [rx lock held, domain lock held] + // interface_set_down() + // interface_protocol_down() + // + // - domain_interface_control() [rx lock held, domain lock held] + // remove_interface_from_domain() + // delete_interface() + // interface_set_down() + + net_device* device = interface->device; + + device->flags &= ~IFF_UP; + device->module->down(device); + + notify_device_monitors(interface, B_DEVICE_GOING_DOWN); + + if (device->module->receive_data != NULL) { + thread_id readerThread = interface->reader_thread; + + // make sure the reader thread is gone before shutting down the interface + status_t status; + wait_for_thread(readerThread, &status); + } +} + + +// #pragma mark - devices stack API + + +/*! Unregisters a previously registered deframer function. */ +status_t +unregister_device_deframer(net_device* device) +{ + MutexLocker locker(sLock); + + // find device interface for this device + net_device_interface* interface = find_device_interface(device->name); + if (interface == NULL) + return ENODEV; + + RecursiveLocker _(interface->receive_lock); + + if (--interface->deframe_ref_count == 0) + interface->deframe_func = NULL; + + return B_OK; +} + + +/*! Registers the deframer function for the specified \a device. + Note, however, that right now, you can only register one single + deframer function per device. + + If the need arises, we might want to lift that limitation at a + later time (which would require a slight API change, though). +*/ +status_t +register_device_deframer(net_device* device, net_deframe_func deframeFunc) +{ + MutexLocker locker(sLock); + + // find device interface for this device + net_device_interface* interface = find_device_interface(device->name); + if (interface == NULL) + return ENODEV; + + RecursiveLocker _(interface->receive_lock); + + if (interface->deframe_func != NULL + && interface->deframe_func != deframeFunc) + return B_ERROR; + + interface->deframe_func = deframeFunc; + interface->deframe_ref_count++; + return B_OK; +} + + +/*! Registers a domain to receive net_buffers from the specified \a device. */ +status_t +register_domain_device_handler(struct net_device* device, int32 type, + struct net_domain* _domain) +{ + net_domain_private* domain = (net_domain_private*)_domain; + if (domain->module == NULL || domain->module->receive_data == NULL) + return B_BAD_VALUE; + + return register_device_handler(device, type, &domain_receive_adapter, + domain); +} + + +/*! Registers a receiving function callback for the specified \a device. */ +status_t +register_device_handler(struct net_device* device, int32 type, + net_receive_func receiveFunc, void* cookie) +{ + MutexLocker locker(sLock); + + // find device interface for this device + net_device_interface* interface = find_device_interface(device->name); + if (interface == NULL) + return ENODEV; + + RecursiveLocker _(interface->receive_lock); + + // see if such a handler already for this device + + DeviceHandlerList::Iterator iterator + = interface->receive_funcs.GetIterator(); + while (net_device_handler* handler = iterator.Next()) { + if (handler->type == type) + return B_ERROR; + } + + // Add new handler + + net_device_handler* handler = new(std::nothrow) net_device_handler; + if (handler == NULL) + return B_NO_MEMORY; + + handler->func = receiveFunc; + handler->type = type; + handler->cookie = cookie; + interface->receive_funcs.Add(handler); + return B_OK; +} + + +/*! Unregisters a previously registered device handler. */ +status_t +unregister_device_handler(struct net_device* device, int32 type) +{ + MutexLocker locker(sLock); + + // find device interface for this device + net_device_interface* interface = find_device_interface(device->name); + if (interface == NULL) + return ENODEV; + + RecursiveLocker _(interface->receive_lock); + + // search for the handler + + DeviceHandlerList::Iterator iterator + = interface->receive_funcs.GetIterator(); + while (net_device_handler* handler = iterator.Next()) { + if (handler->type == type) { + // found it + iterator.Remove(); + delete handler; + return B_OK; + } + } + + return B_BAD_VALUE; +} + + +/*! Registers a device monitor for the specified device. */ +status_t +register_device_monitor(net_device* device, net_device_monitor* monitor) +{ + if (monitor->receive == NULL || monitor->event == NULL) + return B_BAD_VALUE; + + MutexLocker locker(sLock); + + // find device interface for this device + net_device_interface* interface = find_device_interface(device->name); + if (interface == NULL) + return ENODEV; + + RecursiveLocker _(interface->receive_lock); + interface->monitor_funcs.Add(monitor); + return B_OK; +} + + +/*! Unregisters a previously registered device monitor. */ +status_t +unregister_device_monitor(net_device* device, net_device_monitor* monitor) +{ + MutexLocker locker(sLock); + + // find device interface for this device + net_device_interface* interface = find_device_interface(device->name); + if (interface == NULL) + return ENODEV; + + RecursiveLocker _(interface->receive_lock); + + // search for the monitor + + DeviceMonitorList::Iterator iterator = interface->monitor_funcs.GetIterator(); + while (iterator.HasNext()) { + if (iterator.Next() == monitor) { + iterator.Remove(); + return B_OK; + } + } + + return B_BAD_VALUE; +} + + +/*! This function is called by device modules in case their link + state changed, ie. if an ethernet cable was plugged in or + removed. +*/ +status_t +device_link_changed(net_device* device) +{ + notify_link_changed(device); + return B_OK; +} + + +/*! This function is called by device modules once their device got + physically removed, ie. a USB networking card is unplugged. +*/ +status_t +device_removed(net_device* device) +{ + MutexLocker locker(sLock); + + // hold a reference to the device interface being removed + // so our put_() will (eventually) do the final cleanup + net_device_interface* interface = get_device_interface(device->name, false); + if (interface == NULL) + return ENODEV; + + // Propagate the loss of the device throughout the stack. + // This is very complex, refer to remove_interface() for + // further details. + + // TODO! + //domain_removed_device_interface(interface); + + notify_device_monitors(interface, B_DEVICE_BEING_REMOVED); + + // By now all of the monitors must have removed themselves. If they + // didn't, they'll probably wait forever to be callback'ed again. + interface->monitor_funcs.RemoveAll(); + + // All of the readers should be gone as well since we are out of + // interfaces and put_domain_datalink_protocols() is called for + // each delete_interface(). + + put_device_interface(interface); + + return B_OK; +} + + +status_t +device_enqueue_buffer(net_device* device, net_buffer* buffer) +{ + net_device_interface* interface = get_device_interface(device->index); + if (interface == NULL) + return ENODEV; + + status_t status = fifo_enqueue_buffer(&interface->receive_queue, buffer); + + put_device_interface(interface); + return status; +} + + +// #pragma mark - + + +status_t +init_device_interfaces() +{ + mutex_init(&sLock, "net device interfaces"); + + new (&sInterfaces) DeviceInterfaceList; + // static C++ objects are not initialized in the module startup + +#if ENABLE_DEBUGGER_COMMANDS + add_debugger_command("net_device_interface", &dump_device_interface, + "Dump the given network device interface"); + add_debugger_command("net_device_interfaces", &dump_device_interfaces, + "Dump network device interfaces"); +#endif + return B_OK; +} + + +status_t +uninit_device_interfaces() +{ +#if ENABLE_DEBUGGER_COMMANDS + remove_debugger_command("net_device_interface", &dump_device_interface); + remove_debugger_command("net_device_interfaces", &dump_device_interfaces); +#endif + + mutex_destroy(&sLock); + return B_OK; +} + diff --git a/src/add-ons/kernel/network/stack/device_interfaces.h b/src/add-ons/kernel/network/stack/device_interfaces.h new file mode 100644 index 0000000000..46b9890423 --- /dev/null +++ b/src/add-ons/kernel/network/stack/device_interfaces.h @@ -0,0 +1,84 @@ +/* + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef DEVICE_INTERFACES_H +#define DEVICE_INTERFACES_H + + +#include +#include + +#include + + +struct net_device_handler : DoublyLinkedListLinkImpl { + net_receive_func func; + int32 type; + void* cookie; +}; + +typedef DoublyLinkedList DeviceHandlerList; + +typedef DoublyLinkedList > DeviceMonitorList; + +struct net_device_interface : DoublyLinkedListLinkImpl { + struct net_device* device; + thread_id reader_thread; + uint32 up_count; + // a device can be brought up by more than one interface + int32 ref_count; + + net_deframe_func deframe_func; + int32 deframe_ref_count; + + DeviceMonitorList monitor_funcs; + DeviceHandlerList receive_funcs; + + recursive_lock receive_lock; + + thread_id consumer_thread; + net_fifo receive_queue; +}; + +typedef DoublyLinkedList DeviceInterfaceList; + + +// device interfaces +net_device_interface* acquire_device_interface(net_device_interface* interface); +void get_device_interface_address(net_device_interface* interface, + sockaddr* address); +uint32 count_device_interfaces(); +status_t list_device_interfaces(void* buffer, size_t* _bufferSize); +void put_device_interface(struct net_device_interface* interface); +struct net_device_interface* get_device_interface(uint32 index); +struct net_device_interface* get_device_interface(const char* name, + bool create = true); +status_t up_device_interface(net_device_interface* interface); +void down_device_interface(net_device_interface* interface); + +// devices +status_t unregister_device_deframer(net_device* device); +status_t register_device_deframer(net_device* device, net_deframe_func deframeFunc); +status_t register_domain_device_handler(struct net_device* device, int32 type, + struct net_domain* domain); +status_t register_device_handler(struct net_device* device, int32 type, + net_receive_func receiveFunc, void* cookie); +status_t unregister_device_handler(struct net_device* device, int32 type); +status_t register_device_monitor(struct net_device* device, + struct net_device_monitor* monitor); +status_t unregister_device_monitor(struct net_device* device, + struct net_device_monitor* monitor); +status_t device_link_changed(net_device* device); +status_t device_removed(net_device* device); +status_t device_enqueue_buffer(net_device* device, net_buffer* buffer); + +status_t init_device_interfaces(); +status_t uninit_device_interfaces(); + + +#endif // DEVICE_INTERFACES_H diff --git a/src/add-ons/kernel/network/stack/domains.cpp b/src/add-ons/kernel/network/stack/domains.cpp index 16dc3f5ba0..03fac2e268 100644 --- a/src/add-ons/kernel/network/stack/domains.cpp +++ b/src/add-ons/kernel/network/stack/domains.cpp @@ -47,6 +47,8 @@ static DomainList sDomains; static net_domain_private* lookup_domain(int family) { + ASSERT_LOCKED_MUTEX(&sDomainLock); + DomainList::Iterator iterator = sDomains.GetIterator(); while (net_domain_private* domain = iterator.Next()) { if (domain->family == family) @@ -68,19 +70,6 @@ dump_domains(int argc, char** argv) kprintf("domain: %p, %s, %d\n", domain, domain->name, domain->family); kprintf(" module: %p\n", domain->module); kprintf(" address_module: %p\n", domain->address_module); - - if (!list_is_empty(&domain->interfaces)) - kprintf(" interfaces:\n"); - - net_interface* interface = NULL; - while (true) { - interface = (net_interface*)list_get_next_item(&domain->interfaces, - interface); - if (interface == NULL) - break; - - kprintf(" %p\n", interface); - } if (!domain->routes.IsEmpty()) kprintf(" routes:\n"); @@ -119,230 +108,6 @@ get_domain(int family) } -uint32 -count_domain_interfaces() -{ - MutexLocker locker(sDomainLock); - - uint32 count = 0; - - DomainList::Iterator iterator = sDomains.GetIterator(); - while (net_domain_private* domain = iterator.Next()) { - net_interface* interface = NULL; - while (true) { - interface = (net_interface*)list_get_next_item(&domain->interfaces, - interface); - if (interface == NULL) - break; - - count++; - } - } - - return count; -} - - -/*! Dumps a list of all interfaces into the supplied userland buffer. - If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is - returned. -*/ -status_t -list_domain_interfaces(void* _buffer, size_t* bufferSize) -{ - MutexLocker locker(sDomainLock); - - UserBuffer buffer(_buffer, *bufferSize); - - DomainList::Iterator iterator = sDomains.GetIterator(); - while (net_domain_private* domain = iterator.Next()) { - RecursiveLocker locker(domain->lock); - - net_interface* interface = NULL; - while (true) { - interface = (net_interface*)list_get_next_item(&domain->interfaces, - interface); - if (interface == NULL) - break; - - ifreq request; - strlcpy(request.ifr_name, interface->name, IF_NAMESIZE); - if (interface->address != NULL) { - memcpy(&request.ifr_addr, interface->address, - interface->address->sa_len); - } else { - // empty address - request.ifr_addr.sa_len = 2; - request.ifr_addr.sa_family = AF_UNSPEC; - } - - if (buffer.Copy(&request, IF_NAMESIZE - + request.ifr_addr.sa_len) == NULL) - return buffer.Status(); - } - } - - *bufferSize = buffer.ConsumedAmount(); - return B_OK; -} - - -status_t -add_interface_to_domain(net_domain* _domain, - struct ifreq& request) -{ - net_domain_private* domain = (net_domain_private*)_domain; - - const char* deviceName = request.ifr_parameter.device[0] - ? request.ifr_parameter.device : request.ifr_name; - const char* baseName = request.ifr_parameter.base_name[0] - ? request.ifr_parameter.base_name : request.ifr_name; - - net_device_interface* deviceInterface = get_device_interface(deviceName); - if (deviceInterface == NULL) - return ENODEV; - - RecursiveLocker locker(domain->lock); - - net_interface_private* interface = NULL; - status_t status; - - if (find_interface(domain, request.ifr_name) == NULL) { - // We must not hold the domain's link when creating the interface: - // this will call get_module() which might want to access a network - // device when booting from network. - locker.Unlock(); - status = create_interface(domain, request.ifr_name, - baseName, deviceInterface, &interface); - locker.Lock(); - - if (find_interface(domain, request.ifr_name) != NULL) { - delete_interface(interface); - status = B_NAME_IN_USE; - } - } else - status = B_NAME_IN_USE; - - put_device_interface(deviceInterface); - - if (status == B_OK) { - list_add_item(&domain->interfaces, interface); - notify_interface_added(interface); - } - - return status; -} - - -/*! Removes the interface from its domain, and deletes it. - You need to hold the domain's lock when calling this function. -*/ -status_t -remove_interface_from_domain(net_interface* interface) -{ - net_domain_private* domain = (net_domain_private*)interface->domain; - - invalidate_routes(domain, interface); - - list_remove_item(&domain->interfaces, interface); - notify_interface_removed(interface); - delete_interface((net_interface_private*)interface); - return B_OK; -} - - -status_t -domain_interface_control(net_domain_private* domain, int32 option, - ifreq* request) -{ - const char* name = request->ifr_name; - status_t status = B_OK; - - net_device_interface* device = get_device_interface(name, false); - if (device == NULL) - return ENODEV; - - RecursiveLocker _(domain->lock); - - net_interface* interface = find_interface(domain, name); - if (interface != NULL) { - switch (option) { - case SIOCDIFADDR: - remove_interface_from_domain(interface); - break; - - case SIOCSIFFLAGS: - { - uint32 oldFlags = interface->flags; - uint32 requestFlags = request->ifr_flags; - request->ifr_flags &= ~(IFF_UP | IFF_LINK | IFF_BROADCAST); - - if ((requestFlags & IFF_UP) != (interface->flags & IFF_UP)) { - if ((requestFlags & IFF_UP) != 0) { - status = interface->first_info->interface_up( - interface->first_protocol); - if (status == B_OK) - interface->flags |= IFF_UP; - } else { - interface_set_down(interface); - } - } - - if (status == B_OK) { - // TODO: why shouldn't we able to delete IFF_BROADCAST? - interface->flags &= IFF_UP | IFF_LINK | IFF_BROADCAST; - interface->flags |= request->ifr_flags; - } - - if (oldFlags != interface->flags) { - notify_interface_changed(interface, oldFlags, - interface->flags); - } - break; - } - } - } - - // If the SIOCDIFADDR call above removed the last interface associated with - // the device interface, this will effectively remove the interface - put_device_interface(device); - - return status; -} - - -/*! You need to hold the domain lock when calling this function. */ -void -domain_interface_went_down(net_interface* interface) -{ - ASSERT_LOCKED_RECURSIVE(&((net_domain_private*)interface->domain)->lock); - - TRACE(("domain_interface_went_down(%i, %s)\n", - interface->domain->family, interface->name)); - - invalidate_routes(interface->domain, interface); -} - - -void -domain_removed_device_interface(net_device_interface* deviceInterface) -{ - MutexLocker locker(sDomainLock); - - DomainList::Iterator iterator = sDomains.GetIterator(); - while (net_domain_private* domain = iterator.Next()) { - RecursiveLocker locker(domain->lock); - - net_interface_private* interface = find_interface(domain, - deviceInterface->device->name); - if (interface == NULL) - continue; - - remove_interface_from_domain(interface); - } -} - - status_t register_domain(int family, const char* name, struct net_protocol_module_info* module, @@ -367,8 +132,6 @@ register_domain(int family, const char* name, domain->module = module; domain->address_module = addressModule; - list_init(&domain->interfaces); - sDomains.Add(domain); *_domain = domain; @@ -387,16 +150,6 @@ unregister_domain(net_domain* _domain) sDomains.Remove(domain); - net_interface_private* interface = NULL; - while (true) { - interface = (net_interface_private*)list_remove_head_item( - &domain->interfaces); - if (interface == NULL) - break; - - delete_interface(interface); - } - recursive_lock_destroy(&domain->lock); delete domain; return B_OK; diff --git a/src/add-ons/kernel/network/stack/domains.h b/src/add-ons/kernel/network/stack/domains.h index 6da5ca147d..538326f13c 100644 --- a/src/add-ons/kernel/network/stack/domains.h +++ b/src/add-ons/kernel/network/stack/domains.h @@ -28,23 +28,14 @@ struct net_domain_private : net_domain, }; -status_t init_domains(); -status_t uninit_domains(); - -uint32 count_domain_interfaces(); -status_t list_domain_interfaces(void* buffer, size_t* _bufferSize); -status_t add_interface_to_domain(net_domain* domain, struct ifreq& request); -status_t remove_interface_from_domain(net_interface* interface); -void domain_interface_went_down(net_interface* interface); -void domain_removed_device_interface(net_device_interface* interface); -status_t domain_interface_control(net_domain_private* domain, int32 option, - struct ifreq* request); - net_domain* get_domain(int family); status_t register_domain(int family, const char* name, struct net_protocol_module_info* module, struct net_address_module_info* addressModule, net_domain* *_domain); status_t unregister_domain(net_domain* domain); +status_t init_domains(); +status_t uninit_domains(); + #endif // DOMAINS_H diff --git a/src/add-ons/kernel/network/stack/interfaces.cpp b/src/add-ons/kernel/network/stack/interfaces.cpp index da217c44ae..1800a1c0f6 100644 --- a/src/add-ons/kernel/network/stack/interfaces.cpp +++ b/src/add-ons/kernel/network/stack/interfaces.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -7,179 +7,83 @@ */ -#include "domains.h" #include "interfaces.h" -#include "stack_private.h" -#include "utility.h" - -#include - -#include -#include - -#include #include #include #include #include #include +#include + +#include + +#include +#include +#include + +#include "device_interfaces.h" +#include "domains.h" +#include "stack_private.h" +#include "utility.h" -#define TRACE_INTERFACES +//#define TRACE_INTERFACES #ifdef TRACE_INTERFACES -# define TRACE(x) dprintf x +# define TRACE(x...) dprintf(STACK_DEBUG_PREFIX x) #else -# define TRACE(x) ; +# define TRACE(x...) ; #endif -#define ENABLE_DEBUGGER_COMMANDS 1 + +struct AddressHashDefinition { + typedef const sockaddr* KeyType; + typedef InterfaceAddress ValueType; + + AddressHashDefinition() + { + } + + size_t HashKey(const KeyType& key) const + { + net_domain* domain = get_domain(key->sa_family); + if (domain == NULL) + return 0; + + return domain->address_module->hash_address(key, false); + } + + size_t Hash(InterfaceAddress* address) const + { + return address->domain->address_module->hash_address(address->local, false); + } + + bool Compare(const KeyType& key, InterfaceAddress* address) const + { + if (address->local == NULL) + return key->sa_family == AF_UNSPEC; + + if (address->local->sa_family != key->sa_family) + return false; + + return address->domain->address_module->equal_addresses(key, + address->local); + } + + InterfaceAddress*& GetLink(InterfaceAddress* address) const + { + return address->HashTableLink(); + } +}; + +typedef BOpenHashTable AddressTable; -static mutex sInterfaceLock; -static DeviceInterfaceList sInterfaces; +static mutex sLock; +static InterfaceList sInterfaces; +static mutex sHashLock; +static AddressTable sAddressTable; static uint32 sInterfaceIndex; -static uint32 sDeviceIndex; - - -static status_t -device_consumer_thread(void* _interface) -{ - net_device_interface* interface = (net_device_interface*)_interface; - net_device* device = interface->device; - net_buffer* buffer; - - while (true) { - ssize_t status = fifo_dequeue_buffer(&interface->receive_queue, 0, - B_INFINITE_TIMEOUT, &buffer); - if (status == B_INTERRUPTED) - continue; - else if (status < B_OK) - break; - - if (buffer->interface != NULL) { - // if the interface is already specified, this buffer was - // delivered locally. - if (buffer->interface->domain->module->receive_data(buffer) == B_OK) - buffer = NULL; - } else { - // find handler for this packet - DeviceHandlerList::Iterator iterator = - interface->receive_funcs.GetIterator(); - while (buffer && iterator.HasNext()) { - net_device_handler* handler = iterator.Next(); - - // if the handler returns B_OK, it consumed the buffer - if (handler->type == buffer->type - && handler->func(handler->cookie, device, buffer) == B_OK) - buffer = NULL; - } - } - - if (buffer != NULL) - gNetBufferModule.free(buffer); - } - - return B_OK; -} - - -static net_device_interface* -find_device_interface(const char* name) -{ - DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); - - while (net_device_interface* interface = iterator.Next()) { - if (!strcmp(interface->device->name, name)) - return interface; - } - - return NULL; -} - - -/*! The domain's device receive handler - this will inject the net_buffers into - the protocol layer (the domain's registered receive handler). -*/ -static status_t -domain_receive_adapter(void* cookie, net_device* device, net_buffer* buffer) -{ - net_domain_private* domain = (net_domain_private*)cookie; - - buffer->interface = find_interface(domain, device->index); - return domain->module->receive_data(buffer); -} - - -static net_device_interface* -allocate_device_interface(net_device* device, net_device_module_info* module) -{ - net_device_interface* interface = new(std::nothrow) net_device_interface; - if (interface == NULL) - return NULL; - - recursive_lock_init(&interface->receive_lock, "interface receive lock"); - - char name[128]; - snprintf(name, sizeof(name), "%s receive queue", device->name); - - if (init_fifo(&interface->receive_queue, name, 16 * 1024 * 1024) < B_OK) - goto error1; - - interface->device = device; - interface->up_count = 0; - interface->ref_count = 1; - interface->deframe_func = NULL; - interface->deframe_ref_count = 0; - - snprintf(name, sizeof(name), "%s consumer", device->name); - - interface->reader_thread = -1; - interface->consumer_thread = spawn_kernel_thread(device_consumer_thread, - name, B_DISPLAY_PRIORITY, interface); - if (interface->consumer_thread < B_OK) - goto error2; - resume_thread(interface->consumer_thread); - - // TODO: proper interface index allocation - device->index = ++sDeviceIndex; - device->module = module; - - sInterfaces.Add(interface); - return interface; - -error2: - uninit_fifo(&interface->receive_queue); -error1: - recursive_lock_destroy(&interface->receive_lock); - delete interface; - - return NULL; -} - - -static net_device_interface* -acquire_device_interface(net_device_interface* interface) -{ - if (interface == NULL || atomic_add(&interface->ref_count, 1) == 0) - return NULL; - - return interface; -} - - -static void -notify_device_monitors(net_device_interface* interface, int32 event) -{ - RecursiveLocker _(interface->receive_lock); - - DeviceMonitorList::Iterator iterator - = interface->monitor_funcs.GetIterator(); - while (net_device_monitor* monitor = iterator.Next()) { - // it's safe for the "current" item to remove itself. - monitor->event(monitor, event); - } -} #if ENABLE_DEBUGGER_COMMANDS @@ -193,73 +97,57 @@ dump_interface(int argc, char** argv) return 0; } - net_interface_private* interface - = (net_interface_private*)parse_expression(argv[1]); - - kprintf("name: %s\n", interface->name); - kprintf("base_name: %s\n", interface->name); - kprintf("domain: %p\n", interface->domain); - kprintf("device: %p\n", interface->device); - kprintf("device_interface: %p\n", interface->device_interface); - kprintf("direct_route: %p\n", &interface->direct_route); - kprintf("first_protocol: %p\n", interface->first_protocol); - kprintf("first_info: %p\n", interface->first_info); - kprintf("address: %p\n", interface->address); - kprintf("destination: %p\n", interface->destination); - kprintf("mask: %p\n", interface->mask); - kprintf("index: %" B_PRIu32 "\n", interface->index); - kprintf("flags: %#" B_PRIx32 "\n", interface->flags); - kprintf("type: %u\n", interface->type); - kprintf("mtu: %" B_PRIu32 "\n", interface->mtu); - kprintf("metric: %" B_PRIu32 "\n", interface->metric); + Interface* interface = (Interface*)parse_expression(argv[1]); + interface->Dump(); return 0; } static int -dump_device_interface(int argc, char** argv) +dump_interfaces(int argc, char** argv) +{ + InterfaceList::Iterator iterator = sInterfaces.GetIterator(); + while (Interface* interface = iterator.Next()) { + kprintf("%p %s\n", interface, interface->name); + } + return 0; +} + + +static int +dump_local(int argc, char** argv) +{ + AddressTable::Iterator iterator = sAddressTable.GetIterator(); + size_t i = 0; + while (InterfaceAddress* address = iterator.Next()) { + address->Dump(++i); + dprintf(" hash: %lu\n", + address->domain->address_module->hash_address(address->local, + false)); + } + return 0; +} + + +static int +dump_route(int argc, char** argv) { if (argc != 2) { kprintf("usage: %s [address]\n", argv[0]); return 0; } - net_device_interface* interface - = (net_device_interface*)parse_expression(argv[1]); + net_route* route = (net_route*)parse_expression(argv[1]); + kprintf("destination: %p\n", route->destination); + kprintf("mask: %p\n", route->mask); + kprintf("gateway: %p\n", route->gateway); + kprintf("flags: %" B_PRIx32 "\n", route->flags); + kprintf("mtu: %" B_PRIu32 "\n", route->mtu); + kprintf("interface address: %p\n", route->interface_address); - kprintf("device: %p\n", interface->device); - kprintf("reader_thread: %ld\n", interface->reader_thread); - kprintf("up_count: %" B_PRIu32 "\n", interface->up_count); - kprintf("ref_count: %" B_PRId32 "\n", interface->ref_count); - kprintf("deframe_func: %p\n", interface->deframe_func); - kprintf("deframe_ref_count: %" B_PRId32 "\n", interface->ref_count); - kprintf("monitor_funcs:\n"); - kprintf("receive_funcs:\n"); - kprintf("consumer_thread: %ld\n", interface->consumer_thread); - kprintf("receive_lock: %p\n", &interface->receive_lock); - kprintf("receive_queue: %p\n", &interface->receive_queue); - - DeviceMonitorList::Iterator monitorIterator - = interface->monitor_funcs.GetIterator(); - while (monitorIterator.HasNext()) - kprintf(" %p\n", monitorIterator.Next()); - - DeviceHandlerList::Iterator handlerIterator - = interface->receive_funcs.GetIterator(); - while (handlerIterator.HasNext()) - kprintf(" %p\n", handlerIterator.Next()); - - return 0; -} - - -static int -dump_device_interfaces(int argc, char** argv) -{ - DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); - while (net_device_interface* interface = iterator.Next()) { - kprintf(" %p\n", interface); + if (route->interface_address != NULL) { + ((InterfaceAddress*)route->interface_address)->Dump(); } return 0; @@ -269,23 +157,649 @@ dump_device_interfaces(int argc, char** argv) #endif // ENABLE_DEBUGGER_COMMANDS -// #pragma mark - interfaces - - -/*! Searches for a specific interface in a domain by name. - You need to have the domain's lock hold when calling this function. -*/ -struct net_interface_private* -find_interface(struct net_domain* domain, const char* name) +InterfaceAddress::InterfaceAddress() { - net_interface_private* interface = NULL; + _Init(NULL, NULL); +} - while (true) { - interface = (net_interface_private*)list_get_next_item( - &domain->interfaces, interface); - if (interface == NULL) + +InterfaceAddress::InterfaceAddress(net_interface* netInterface, + net_domain* netDomain) +{ + _Init(netInterface, netDomain); +} + + +InterfaceAddress::~InterfaceAddress() +{ +} + + +status_t +InterfaceAddress::SetTo(const ifaliasreq& request) +{ + status_t status = SetLocal((const sockaddr*)&request.ifra_addr); + if (status == B_OK) + status = SetDestination((const sockaddr*)&request.ifra_broadaddr); + if (status == B_OK) + status = SetMask((const sockaddr*)&request.ifra_mask); + + return status; +} + + +status_t +InterfaceAddress::SetLocal(const sockaddr* to) +{ + return Set(&local, to); +} + + +status_t +InterfaceAddress::SetDestination(const sockaddr* to) +{ + return Set(&destination, to); +} + + +status_t +InterfaceAddress::SetMask(const sockaddr* to) +{ + return Set(&mask, to); +} + + +sockaddr** +InterfaceAddress::AddressFor(int32 option) +{ + switch (option) { + case SIOCSIFADDR: + case SIOCGIFADDR: + return &local; + + case SIOCSIFNETMASK: + case SIOCGIFNETMASK: + return &mask; + + case SIOCSIFBRDADDR: + case SIOCSIFDSTADDR: + case SIOCGIFBRDADDR: + case SIOCGIFDSTADDR: + return &destination; + + default: + return NULL; + } +} + + +#if ENABLE_DEBUGGER_COMMANDS + + +void +InterfaceAddress::Dump(size_t index, bool hideInterface) +{ + if (index) + kprintf("%2zu. ", index); + else + kprintf(" "); + + if (!hideInterface) { + kprintf("interface: %p (%s)\n ", interface, + interface != NULL ? interface->name : "-"); + } + + kprintf("domain: %p (family %u)\n", domain, + domain != NULL ? domain->family : AF_UNSPEC); + + char buffer[64]; + if (local != NULL && domain != NULL) { + domain->address_module->print_address_buffer(local, buffer, + sizeof(buffer), false); + } else + strcpy(buffer, "-"); + kprintf(" local: %s\n", buffer); + + if (mask != NULL && domain != NULL) { + domain->address_module->print_address_buffer(mask, buffer, + sizeof(buffer), false); + } else + strcpy(buffer, "-"); + kprintf(" mask: %s\n", buffer); + + if (destination != NULL && domain != NULL) { + domain->address_module->print_address_buffer(destination, buffer, + sizeof(buffer), false); + } else + strcpy(buffer, "-"); + kprintf(" destination: %s\n", buffer); +} + + +#endif // ENABLE_DEBUGGER_COMMANDS + + +/*static*/ status_t +InterfaceAddress::Set(sockaddr** _address, const sockaddr* to) +{ + sockaddr* address = *_address; + + if (to == NULL || to->sa_family == AF_UNSPEC) { + // Clear address + free(address); + *_address = NULL; + return B_OK; + } + + // Set address + + size_t size = max_c(to->sa_len, sizeof(sockaddr)); + if (size > sizeof(sockaddr_storage)) + size = sizeof(sockaddr_storage); + + address = Prepare(_address, size); + if (address == NULL) + return B_NO_MEMORY; + + memcpy(address, to, size); + address->sa_len = size; + + return B_OK; +} + + +/*static*/ sockaddr* +InterfaceAddress::Prepare(sockaddr** _address, size_t size) +{ + size = max_c(size, sizeof(sockaddr)); + if (size > sizeof(sockaddr_storage)) + size = sizeof(sockaddr_storage); + + sockaddr* address = *_address; + + if (address == NULL || size > address->sa_len) { + address = (sockaddr*)realloc(address, size); + if (address == NULL) + return NULL; + } + + address->sa_len = size; + + *_address = address; + return address; +} + + +void +InterfaceAddress::_Init(net_interface* netInterface, net_domain* netDomain) +{ + interface = netInterface; + domain = netDomain; + local = NULL; + destination = NULL; + mask = NULL; +} + + +// #pragma mark - + + +Interface::Interface(const char* interfaceName, + net_device_interface* deviceInterface) +{ + TRACE("Interface %p: new \"%s\", device interface %p\n", this, + interfaceName, deviceInterface); + + strlcpy(name, interfaceName, IF_NAMESIZE); + device = deviceInterface->device; + + index = ++sInterfaceIndex; + flags = 0; + type = 0; + mtu = deviceInterface->device->mtu; + metric = 0; + + fDeviceInterface = acquire_device_interface(deviceInterface); + + recursive_lock_init(&fLock, name); + + // Grab a reference to the networking stack, to make sure it won't be + // unloaded as long as an interface exists + module_info* module; + get_module(gNetStackInterfaceModule.info.name, &module); +} + + +Interface::~Interface() +{ + recursive_lock_destroy(&fLock); + + // Release reference of the stack - at this point, our stack may be unloaded + // if no other interfaces or sockets are left + put_module(gNetStackInterfaceModule.info.name); +} + + +/*! Returns a reference to the first InterfaceAddress that is from the same + as the specified \a family. +*/ +InterfaceAddress* +Interface::FirstForFamily(int family) +{ + RecursiveLocker locker(fLock); + + InterfaceAddress* address = _FirstForFamily(family); + if (address != NULL) { + address->AcquireReference(); + return address; + } + + return NULL; +} + + +/*! Returns a reference to the first unconfigured address of this interface + for the specified \a family. +*/ +InterfaceAddress* +Interface::FirstUnconfiguredForFamily(int family) +{ + RecursiveLocker locker(fLock); + + AddressList::Iterator iterator = fAddresses.GetIterator(); + while (InterfaceAddress* address = iterator.Next()) { + if (address->domain->family == family + && (address->local == NULL + // TODO: this has to be solved differently!! + || (flags & IFF_CONFIGURING) != 0)) { + address->AcquireReference(); + return address; + } + } + + return NULL; +} + + +/*! Returns a reference to the InterfaceAddress that has the specified + \a destination address. +*/ +InterfaceAddress* +Interface::AddressForDestination(net_domain* domain, + const sockaddr* destination) +{ + RecursiveLocker locker(fLock); + + if ((device->flags & IFF_BROADCAST) == 0) { + // The device does not support broadcasting + return NULL; + } + + AddressList::Iterator iterator = fAddresses.GetIterator(); + while (InterfaceAddress* address = iterator.Next()) { + if (address->domain == domain + && address->destination != NULL + && domain->address_module->equal_addresses(address->destination, + destination)) { + address->AcquireReference(); + return address; + } + } + + return NULL; +} + + +status_t +Interface::AddAddress(InterfaceAddress* address) +{ + net_domain* domain = address->domain; + if (domain == NULL) + return B_BAD_VALUE; + + RecursiveLocker locker(fLock); + fAddresses.Add(address); + locker.Unlock(); + + MutexLocker hashLocker(sHashLock); + sAddressTable.Insert(address); + return B_OK; +} + + +void +Interface::RemoveAddress(InterfaceAddress* address) +{ + net_domain* domain = address->domain; + if (domain == NULL) + return; + + RecursiveLocker locker(fLock); + + fAddresses.Remove(address); + address->GetDoublyLinkedListLink()->next = NULL; + +// TODO! +// if (_FirstForFamily(domain->family) == NULL) +// put_domain_datalink_protocols(this, domain); + + locker.Unlock(); + + MutexLocker hashLocker(sHashLock); + sAddressTable.Remove(address); +} + + +bool +Interface::GetNextAddress(InterfaceAddress** _address) +{ + RecursiveLocker locker(fLock); + + InterfaceAddress* address = *_address; + if (address == NULL) { + // get first address + address = fAddresses.First(); + } else { + // get next, if possible + InterfaceAddress* next = fAddresses.GetNext(address); + address->ReleaseReference(); + address = next; + } + + *_address = address; + + if (address == NULL) + return false; + + address->AcquireReference(); + return true; +} + + +status_t +Interface::Control(net_domain* domain, int32 option, ifreq& request, + ifreq* userRequest, size_t length) +{ + switch (option) { + case SIOCSIFFLAGS: + { + uint32 requestFlags = request.ifr_flags; + uint32 oldFlags = flags; + status_t status = B_OK; + + request.ifr_flags &= ~(IFF_UP | IFF_LINK | IFF_BROADCAST); + + if ((requestFlags & IFF_UP) != (flags & IFF_UP)) { + if ((requestFlags & IFF_UP) != 0) + status = _SetUp(); + else + _SetDown(); + } + + if (status == B_OK) { + // TODO: maybe allow deleting IFF_BROADCAST on the interface + // level? + flags &= IFF_UP | IFF_LINK | IFF_BROADCAST; + flags |= request.ifr_flags; + } + + if (oldFlags != flags) + notify_interface_changed(this, oldFlags, flags); + + return status; + } + + case SIOCSIFADDR: + case SIOCSIFNETMASK: + case SIOCSIFBRDADDR: + case SIOCSIFDSTADDR: + case SIOCDIFADDR: + { + RecursiveLocker locker(fLock); + + InterfaceAddress* address = NULL; + sockaddr_storage oldAddress; + sockaddr_storage newAddress; + + size_t size = max_c(request.ifr_addr.sa_len, sizeof(sockaddr)); + if (size > sizeof(sockaddr_storage)) + size = sizeof(sockaddr_storage); + + if (user_memcpy(&newAddress, &userRequest->ifr_addr, size) != B_OK) + return B_BAD_ADDRESS; + + if (option == SIOCDIFADDR) { + // Find referring address - we can't use the hash, as another + // interface might use the same address. + AddressList::Iterator iterator = fAddresses.GetIterator(); + while ((address = iterator.Next()) != NULL) { + if (address->domain == domain + && domain->address_module->equal_addresses( + address->local, (sockaddr*)&newAddress)) + break; + } + } else { + // Just use the first address for this family + address = _FirstForFamily(domain->family); + } + + if (address == NULL) + return B_BAD_VALUE; + + if (*address->AddressFor(option) != NULL) + memcpy(&oldAddress, *address->AddressFor(option), size); + else + oldAddress.ss_family = AF_UNSPEC; + + // TODO: mark this address busy or call while holding the lock! + address->AcquireReference(); + locker.Unlock(); + + domain_datalink* datalink = DomainDatalink(domain->family); + status_t status = datalink->first_protocol->module->change_address( + datalink->first_protocol, address, option, + oldAddress.ss_family != AF_UNSPEC + ? (sockaddr*)&oldAddress : NULL, + option != SIOCDIFADDR ? (sockaddr*)&newAddress : NULL); + + address->ReleaseReference(); + return status; + } + + default: + // pass the request into the datalink protocol stack + domain_datalink* datalink = DomainDatalink(domain->family); + if (datalink->first_info != NULL) { + return datalink->first_info->control( + datalink->first_protocol, option, userRequest, length); + } break; + } + return B_BAD_VALUE; +} + + +status_t +Interface::CreateDomainDatalinkIfNeeded(net_domain* domain) +{ + RecursiveLocker locker(fLock); + + if (fDatalinkTable.Lookup(domain->family) != NULL) + return B_OK; + + TRACE("Interface %p: create domain datalink for domain %p\n", this, domain); + + domain_datalink* datalink = new(std::nothrow) domain_datalink; + if (datalink == NULL) + return B_NO_MEMORY; + + datalink->domain = domain; + + // setup direct route for bound devices + datalink->direct_route.destination = NULL; + datalink->direct_route.mask = NULL; + datalink->direct_route.gateway = NULL; + datalink->direct_route.flags = 0; + datalink->direct_route.mtu = 0; + datalink->direct_route.interface_address = &datalink->direct_address; + datalink->direct_route.ref_count = 1; + // make sure this doesn't get deleted accidently + + // provide its link back to the interface + datalink->direct_address.local = NULL; + datalink->direct_address.destination = NULL; + datalink->direct_address.mask = NULL; + datalink->direct_address.domain = domain; + datalink->direct_address.interface = this; + + fDatalinkTable.Insert(datalink); + + status_t status = get_domain_datalink_protocols(this, domain); + if (status == B_OK) + return B_OK; + + fDatalinkTable.Remove(datalink); + delete datalink; + + return status; +} + + +domain_datalink* +Interface::DomainDatalink(uint8 family) +{ + // Note: domain datalinks cannot be removed while the interface is alive, + // since this would require us either to hold the lock while calling this + // function, or introduce reference counting for the domain_datalink + // structure. + RecursiveLocker locker(fLock); + return fDatalinkTable.Lookup(family); +} + + +#if ENABLE_DEBUGGER_COMMANDS + + +void +Interface::Dump() const +{ + kprintf("name: %s\n", name); + kprintf("device: %p\n", device); + kprintf("device_interface: %p\n", fDeviceInterface); + kprintf("index: %" B_PRIu32 "\n", index); + kprintf("flags: %#" B_PRIx32 "\n", flags); + kprintf("type: %u\n", type); + kprintf("mtu: %" B_PRIu32 "\n", mtu); + kprintf("metric: %" B_PRIu32 "\n", metric); + + kprintf("datalink protocols:\n"); + + DatalinkTable::Iterator datalinkIterator = fDatalinkTable.GetIterator(); + size_t i = 0; + while (domain_datalink* datalink = datalinkIterator.Next()) { + kprintf("%2zu. domain: %p\n", ++i, datalink->domain); + kprintf(" first_protocol: %p\n", datalink->first_protocol); + kprintf(" first_info: %p\n", datalink->first_info); + kprintf(" direct_route: %p\n", &datalink->direct_route); + } + + kprintf("addresses:\n"); + + AddressList::ConstIterator iterator = fAddresses.GetIterator(); + i = 0; + while (InterfaceAddress* address = iterator.Next()) { + address->Dump(++i, true); + } +} + + +#endif // ENABLE_DEBUGGER_COMMANDS + + +status_t +Interface::_SetUp() +{ + status_t status = up_device_interface(fDeviceInterface); + if (status != B_OK) + return status; + + // propagate flag to all datalink protocols + + RecursiveLocker locker(fLock); + + DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator(); + while (domain_datalink* datalink = iterator.Next()) { + status = datalink->first_info->interface_up(datalink->first_protocol); + if (status != B_OK) { + // Revert "up" status + DatalinkTable::Iterator secondIterator + = fDatalinkTable.GetIterator(); + while (secondIterator.HasNext()) { + domain_datalink* secondDatalink = secondIterator.Next(); + if (secondDatalink == NULL || secondDatalink == datalink) + break; + + secondDatalink->first_info->interface_down( + secondDatalink->first_protocol); + } + + down_device_interface(fDeviceInterface); + return status; + } + } + + flags |= IFF_UP; + return B_OK; +} + + +void +Interface::_SetDown() +{ + if ((flags & IFF_UP) == 0) + return; + + RecursiveLocker locker(fLock); + + DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator(); + while (domain_datalink* datalink = iterator.Next()) { + datalink->first_info->interface_down(datalink->first_protocol); + } + + down_device_interface(fDeviceInterface); + flags &= ~IFF_UP; +} + + +InterfaceAddress* +Interface::_FirstForFamily(int family) +{ + ASSERT_LOCKED_RECURSIVE(&fLock); + + AddressList::Iterator iterator = fAddresses.GetIterator(); + while (InterfaceAddress* address = iterator.Next()) { + if (address->domain != NULL && address->domain->family == family) + return address; + } + + return NULL; +} + + +// #pragma mark - + + +/*! Searches for a specific interface by name. + You need to have the interface list's lock hold when calling this function. +*/ +static struct Interface* +find_interface(const char* name) +{ + ASSERT_LOCKED_MUTEX(&sLock); + + InterfaceList::Iterator iterator = sInterfaces.GetIterator(); + while (Interface* interface = iterator.Next()) { if (!strcmp(interface->name, name)) return interface; } @@ -294,20 +808,14 @@ find_interface(struct net_domain* domain, const char* name) } -/*! Searches for a specific interface in a domain by index. - You need to have the domain's lock hold when calling this function. +/*! Searches for a specific interface by index. + You need to have the interface list's lock hold when calling this function. */ -struct net_interface_private* -find_interface(struct net_domain* domain, uint32 index) +static struct Interface* +find_interface(uint32 index) { - net_interface_private* interface = NULL; - - while (true) { - interface = (net_interface_private*)list_get_next_item( - &domain->interfaces, interface); - if (interface == NULL) - break; - + InterfaceList::Iterator iterator = sInterfaces.GetIterator(); + while (Interface* interface = iterator.Next()) { if (interface->index == index) return interface; } @@ -316,70 +824,96 @@ find_interface(struct net_domain* domain, uint32 index) } -status_t -create_interface(net_domain* domain, const char* name, const char* baseName, - net_device_interface* deviceInterface, net_interface_private** _interface) +/*! Removes the default routes as set by add_default_routes() again. */ +static void +remove_default_routes(InterfaceAddress* address, int32 option) { - net_interface_private* interface = new(std::nothrow) net_interface_private; + net_route route; + route.destination = address->local; + route.gateway = NULL; + route.interface_address = address; + + if (address->mask != NULL + && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) { + route.mask = address->mask; + route.flags = 0; + remove_route(address->domain, &route); + } + + if (option == SIOCSIFADDR) { + route.mask = NULL; + route.flags = RTF_LOCAL | RTF_HOST; + remove_route(address->domain, &route); + } +} + + +/*! Adds the default routes that every interface address needs, ie. the local + host route, and one for the subnet (if set). +*/ +static void +add_default_routes(InterfaceAddress* address, int32 option) +{ + net_route route; + route.destination = address->local; + route.gateway = NULL; + route.interface_address = address; + + if (address->mask != NULL + && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) { + route.mask = address->mask; + route.flags = 0; + add_route(address->domain, &route); + } + + if (option == SIOCSIFADDR) { + route.mask = NULL; + route.flags = RTF_LOCAL | RTF_HOST; + add_route(address->domain, &route); + } +} + + +// #pragma mark - + + +status_t +add_interface(const char* name, net_domain_private* domain, + const ifaliasreq& request, net_device_interface* deviceInterface) +{ + MutexLocker locker(sLock); + + if (find_interface(name) != NULL) + return B_NAME_IN_USE; + + Interface* interface + = new(std::nothrow) Interface(name, deviceInterface); if (interface == NULL) return B_NO_MEMORY; - strlcpy(interface->name, name, IF_NAMESIZE); - strlcpy(interface->base_name, baseName, IF_NAMESIZE); - interface->domain = domain; - interface->device = deviceInterface->device; + sInterfaces.Add(interface); + interface->AcquireReference(); + // We need another reference to be able to use the interface without + // holding sLock. - interface->address = NULL; - interface->destination = NULL; - interface->mask = NULL; + locker.Unlock(); - interface->index = ++sInterfaceIndex; - interface->flags = 0; - interface->type = 0; - interface->mtu = deviceInterface->device->mtu; - interface->metric = 0; - interface->device_interface = acquire_device_interface(deviceInterface); + notify_interface_added(interface); + add_interface_address(interface, domain, request); - // setup direct route for bound devices - interface->direct_route.destination = NULL; - interface->direct_route.mask = NULL; - interface->direct_route.gateway = NULL; - interface->direct_route.flags = 0; - interface->direct_route.mtu = 0; - interface->direct_route.interface = interface; - interface->direct_route.ref_count = 1; - // make sure this doesn't get deleted accidently + interface->ReleaseReference(); - status_t status = get_domain_datalink_protocols(interface); - if (status < B_OK) { - delete interface; - return status; - } - - // Grab a reference to the networking stack, to make sure it won't be - // unloaded as long as an interface exists - module_info* module; - get_module(gNetStackInterfaceModule.info.name, &module); - - *_interface = interface; return B_OK; } -void -interface_set_down(net_interface* interface) -{ - if ((interface->flags & IFF_UP) == 0) - return; - - interface->flags &= ~IFF_UP; - interface->first_info->interface_down(interface->first_protocol); -} - - -void -delete_interface(net_interface_private* interface) +/*! Removes the interface from the list, and puts the stack's reference to it. +*/ +status_t +remove_interface(Interface* interface) { + return B_ERROR; +#if 0 // deleting an interface is fairly complex as we need // to clear all references to it throughout the stack @@ -401,87 +935,250 @@ delete_interface(net_interface_private* interface) put_device_interface(interface->device_interface); - free(interface->address); - free(interface->destination); - free(interface->mask); - delete interface; +#endif +#if 0 + invalidate_routes(domain, interface); - // Release reference of the stack - at this point, our stack may be unloaded - // if no other interfaces or sockets are left - put_module(gNetStackInterfaceModule.info.name); + list_remove_item(&domain->interfaces, interface); + notify_interface_removed(interface); + delete_interface((net_interface_private*)interface); +#endif } void -put_interface(struct net_interface_private* interface) +interface_went_down(Interface* interface) { - // TODO: reference counting - // TODO: better locking scheme - recursive_lock_unlock(&((net_domain_private*)interface->domain)->lock); + TRACE("interface_went_down(%s)\n", interface->name); + // TODO! + //invalidate_routes(domain, interface); } -struct net_interface_private* -get_interface(net_domain* _domain, const char* name) +status_t +add_interface_address(Interface* interface, net_domain_private* domain, + const ifaliasreq& request) { - net_domain_private* domain = (net_domain_private*)_domain; - recursive_lock_lock(&domain->lock); + // Make sure the family of the provided addresses is valid + if ((request.ifra_addr.ss_family != domain->family + && request.ifra_addr.ss_family != AF_UNSPEC) + || (request.ifra_mask.ss_family != domain->family + && request.ifra_mask.ss_family != AF_UNSPEC) + || (request.ifra_broadaddr.ss_family != domain->family + && request.ifra_broadaddr.ss_family != AF_UNSPEC)) + return B_BAD_VALUE; - net_interface_private* interface = NULL; - while (true) { - interface = (net_interface_private*)list_get_next_item( - &domain->interfaces, interface); - if (interface == NULL) - break; + RecursiveLocker locker(interface->Lock()); - // TODO: We keep the domain locked for now - if (!strcmp(interface->name, name)) - return interface; + InterfaceAddress* address + = new(std::nothrow) InterfaceAddress(interface, domain); + if (address == NULL) + return B_NO_MEMORY; + + status_t status = address->SetTo(request); + if (status == B_OK) + status = interface->CreateDomainDatalinkIfNeeded(domain); + if (status == B_OK) + status = interface->AddAddress(address); + + if (status == B_OK && address->local != NULL) { + // update the datalink protocols + domain_datalink* datalink = interface->DomainDatalink(domain->family); + + status = datalink->first_protocol->module->change_address( + datalink->first_protocol, address, SIOCAIFADDR, NULL, + address->local); + if (status != B_OK) + interface->RemoveAddress(address); + } + if (status == B_OK) + notify_interface_changed(interface); + else + delete address; + + return status; +} + + +status_t +update_interface_address(InterfaceAddress* interfaceAddress, int32 option, + const sockaddr* oldAddress, const sockaddr* newAddress) +{ + MutexLocker locker(sHashLock); + + // set logical interface address + sockaddr** _address = interfaceAddress->AddressFor(option); + if (_address == NULL) + return B_BAD_VALUE; + + remove_default_routes(interfaceAddress, option); + sAddressTable.Remove(interfaceAddress); + + // Copy new address over + status_t status = InterfaceAddress::Set(_address, newAddress); + if (status == B_OK) { + sockaddr* address = *_address; + + if (option == SIOCSIFADDR || option == SIOCSIFNETMASK) { + // Reset netmask and broadcast addresses to defaults + net_domain* domain = interfaceAddress->domain; + sockaddr* netmask = NULL; + const sockaddr* oldNetmask = NULL; + if (option == SIOCSIFADDR) { + netmask = InterfaceAddress::Prepare( + &interfaceAddress->mask, address->sa_len); + } else { + oldNetmask = oldAddress; + netmask = interfaceAddress->mask; + } + + // Reset the broadcast address if the address family has + // such + sockaddr* broadcast = NULL; + if ((domain->address_module->flags + & NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0) { + broadcast = InterfaceAddress::Prepare( + &interfaceAddress->destination, address->sa_len); + } else + InterfaceAddress::Set(&interfaceAddress->destination, NULL); + + domain->address_module->set_to_defaults(netmask, broadcast, + interfaceAddress->local, oldNetmask); + } + + add_default_routes(interfaceAddress, option); + notify_interface_changed(interfaceAddress->interface); } - recursive_lock_unlock(&domain->lock); + sAddressTable.Insert(interfaceAddress); + return status; +} + + +Interface* +get_interface(net_domain* domain, uint32 index) +{ + MutexLocker locker(sLock); + + if (index == 0) + return sInterfaces.First(); + + Interface* interface = find_interface(index); + if (interface == NULL) + return NULL; + + if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK) + return NULL; + + interface->AcquireReference(); + return interface; +} + + +Interface* +get_interface(net_domain* domain, const char* name) +{ + MutexLocker locker(sLock); + + Interface* interface = find_interface(name); + if (interface == NULL) + return NULL; + + if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK) + return NULL; + + interface->AcquireReference(); + return interface; +} + + +Interface* +get_interface_for_device(net_domain* domain, uint32 index) +{ + MutexLocker locker(sLock); + + InterfaceList::Iterator iterator = sInterfaces.GetIterator(); + while (Interface* interface = iterator.Next()) { + if (interface->device->index == index) { + if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK) + return NULL; + + interface->AcquireReference(); + return interface; + } + } + return NULL; } -// #pragma mark - device interfaces - - -void -get_device_interface_address(net_device_interface* interface, sockaddr* _address) +InterfaceAddress* +get_interface_address(const sockaddr* local) { - sockaddr_dl &address = *(sockaddr_dl*)_address; + if (local->sa_family == AF_UNSPEC) + return NULL; - address.sdl_family = AF_LINK; - address.sdl_index = interface->device->index; - address.sdl_type = interface->device->type; - address.sdl_nlen = strlen(interface->device->name); - address.sdl_slen = 0; - memcpy(address.sdl_data, interface->device->name, address.sdl_nlen); + MutexLocker locker(sHashLock); - address.sdl_alen = interface->device->address.length; - memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen); + InterfaceAddress* address = sAddressTable.Lookup(local); + if (address == NULL) + return NULL; - address.sdl_len = sizeof(sockaddr_dl) - sizeof(address.sdl_data) - + address.sdl_nlen + address.sdl_alen; + address->AcquireReference(); + return address; +} + + +InterfaceAddress* +get_interface_address_for_destination(net_domain* domain, + const struct sockaddr* destination) +{ + MutexLocker locker(sLock); + + InterfaceList::Iterator iterator = sInterfaces.GetIterator(); + while (Interface* interface = iterator.Next()) { + InterfaceAddress* address + = interface->AddressForDestination(domain, destination); + if (address != NULL) + return address; + } + + return NULL; +} + + +InterfaceAddress* +get_interface_address_for_link(net_domain* domain, + const struct sockaddr* _linkAddress, bool unconfiguredOnly) +{ + sockaddr_dl& linkAddress = *(sockaddr_dl*)_linkAddress; + + MutexLocker locker(sLock); + + InterfaceList::Iterator iterator = sInterfaces.GetIterator(); + while (Interface* interface = iterator.Next()) { + if (linkAddress.sdl_alen == interface->device->address.length + && memcmp(LLADDR(&linkAddress), interface->device->address.data, + linkAddress.sdl_alen) == 0) { + // link address matches + if (unconfiguredOnly) + return interface->FirstUnconfiguredForFamily(domain->family); + + return interface->FirstForFamily(domain->family); + } + } + + return NULL; } uint32 -count_device_interfaces() +count_interfaces() { - MutexLocker locker(sInterfaceLock); + MutexLocker locker(sLock); - DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); - uint32 count = 0; - - while (iterator.HasNext()) { - iterator.Next(); - count++; - } - - return count; + return sInterfaces.Count(); } @@ -490,19 +1187,31 @@ count_device_interfaces() returned. */ status_t -list_device_interfaces(void* _buffer, size_t* bufferSize) +list_interfaces(int family, void* _buffer, size_t* bufferSize) { - MutexLocker locker(sInterfaceLock); + MutexLocker locker(sLock); - DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); UserBuffer buffer(_buffer, *bufferSize); - while (net_device_interface* interface = iterator.Next()) { + InterfaceList::Iterator iterator = sInterfaces.GetIterator(); + while (Interface* interface = iterator.Next()) { ifreq request; - strlcpy(request.ifr_name, interface->device->name, IF_NAMESIZE); - get_device_interface_address(interface, &request.ifr_addr); + strlcpy(request.ifr_name, interface->name, IF_NAMESIZE); - if (buffer.Copy(&request, IF_NAMESIZE + request.ifr_addr.sa_len) == NULL) + InterfaceAddress* address = interface->FirstForFamily(family); + if (address != NULL && address->local != NULL) { + // copy actual address + memcpy(&request.ifr_addr, address->local, address->local->sa_len); + } else { + // empty address + request.ifr_addr.sa_len = 2; + request.ifr_addr.sa_family = AF_UNSPEC; + } + if (address != NULL) + address->ReleaseReference(); + + if (buffer.Copy(&request, IF_NAMESIZE + + request.ifr_addr.sa_len) == NULL) return buffer.Status(); } @@ -511,398 +1220,28 @@ list_device_interfaces(void* _buffer, size_t* bufferSize) } -/*! Releases the reference for the interface. When all references are - released, the interface is removed. -*/ -void -put_device_interface(struct net_device_interface* interface) -{ - if (atomic_add(&interface->ref_count, -1) != 1) - return; - - { - MutexLocker locker(sInterfaceLock); - sInterfaces.Remove(interface); - } - - uninit_fifo(&interface->receive_queue); - status_t status; - wait_for_thread(interface->consumer_thread, &status); - - net_device* device = interface->device; - const char* moduleName = device->module->info.name; - - device->module->uninit_device(device); - put_module(moduleName); - - recursive_lock_destroy(&interface->receive_lock); - delete interface; -} - - -/*! Finds an interface by the specified index and acquires a reference to it. -*/ -struct net_device_interface* -get_device_interface(uint32 index) -{ - MutexLocker locker(sInterfaceLock); - - // TODO: maintain an array of all device interfaces instead - DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); - while (net_device_interface* interface = iterator.Next()) { - if (interface->device->index == index) { - if (atomic_add(&interface->ref_count, 1) != 0) - return interface; - } - } - - return NULL; -} - - -/*! Finds an interface by the specified name and grabs a reference to it. - If the interface does not yet exist, a new one is created. -*/ -struct net_device_interface* -get_device_interface(const char* name, bool create) -{ - MutexLocker locker(sInterfaceLock); - - net_device_interface* interface = find_device_interface(name); - if (interface != NULL) { - if (atomic_add(&interface->ref_count, 1) != 0) - return interface; - - // try to recreate interface - it just got removed - } - - if (!create) - return NULL; - - void* cookie = open_module_list("network/devices"); - if (cookie == NULL) - return NULL; - - while (true) { - char moduleName[B_FILE_NAME_LENGTH]; - size_t length = sizeof(moduleName); - if (read_next_module_name(cookie, moduleName, &length) != B_OK) - break; - - TRACE(("get_device_interface: ask \"%s\" for %s\n", moduleName, name)); - - net_device_module_info* module; - if (get_module(moduleName, (module_info**)&module) == B_OK) { - net_device* device; - status_t status = module->init_device(name, &device); - if (status == B_OK) { - interface = allocate_device_interface(device, module); - if (interface != NULL) - return interface; - - module->uninit_device(device); - } - put_module(moduleName); - } - } - - return NULL; -} - - -void -down_device_interface(net_device_interface* interface) -{ - // Receive lock must be held when calling down_device_interface. - // Known callers are `interface_protocol_down' which gets - // here via one of the following paths: - // - // - domain_interface_control() [rx lock held, domain lock held] - // interface_set_down() - // interface_protocol_down() - // - // - domain_interface_control() [rx lock held, domain lock held] - // remove_interface_from_domain() - // delete_interface() - // interface_set_down() - - net_device* device = interface->device; - - device->flags &= ~IFF_UP; - device->module->down(device); - - notify_device_monitors(interface, B_DEVICE_GOING_DOWN); - - if (device->module->receive_data != NULL) { - thread_id readerThread = interface->reader_thread; - - // make sure the reader thread is gone before shutting down the interface - status_t status; - wait_for_thread(readerThread, &status); - } -} - - -// #pragma mark - devices stack API - - -/*! Unregisters a previously registered deframer function. */ -status_t -unregister_device_deframer(net_device* device) -{ - MutexLocker locker(sInterfaceLock); - - // find device interface for this device - net_device_interface* interface = find_device_interface(device->name); - if (interface == NULL) - return ENODEV; - - RecursiveLocker _(interface->receive_lock); - - if (--interface->deframe_ref_count == 0) - interface->deframe_func = NULL; - - return B_OK; -} - - -/*! Registers the deframer function for the specified \a device. - Note, however, that right now, you can only register one single - deframer function per device. - - If the need arises, we might want to lift that limitation at a - later time (which would require a slight API change, though). -*/ -status_t -register_device_deframer(net_device* device, net_deframe_func deframeFunc) -{ - MutexLocker locker(sInterfaceLock); - - // find device interface for this device - net_device_interface* interface = find_device_interface(device->name); - if (interface == NULL) - return ENODEV; - - RecursiveLocker _(interface->receive_lock); - - if (interface->deframe_func != NULL - && interface->deframe_func != deframeFunc) - return B_ERROR; - - interface->deframe_func = deframeFunc; - interface->deframe_ref_count++; - return B_OK; -} - - -/*! Registers a domain to receive net_buffers from the specified \a device. */ -status_t -register_domain_device_handler(struct net_device* device, int32 type, - struct net_domain* _domain) -{ - net_domain_private* domain = (net_domain_private*)_domain; - if (domain->module == NULL || domain->module->receive_data == NULL) - return B_BAD_VALUE; - - return register_device_handler(device, type, &domain_receive_adapter, - domain); -} - - -/*! Registers a receiving function callback for the specified \a device. */ -status_t -register_device_handler(struct net_device* device, int32 type, - net_receive_func receiveFunc, void* cookie) -{ - MutexLocker locker(sInterfaceLock); - - // find device interface for this device - net_device_interface* interface = find_device_interface(device->name); - if (interface == NULL) - return ENODEV; - - RecursiveLocker _(interface->receive_lock); - - // see if such a handler already for this device - - DeviceHandlerList::Iterator iterator - = interface->receive_funcs.GetIterator(); - while (net_device_handler* handler = iterator.Next()) { - if (handler->type == type) - return B_ERROR; - } - - // Add new handler - - net_device_handler* handler = new(std::nothrow) net_device_handler; - if (handler == NULL) - return B_NO_MEMORY; - - handler->func = receiveFunc; - handler->type = type; - handler->cookie = cookie; - interface->receive_funcs.Add(handler); - return B_OK; -} - - -/*! Unregisters a previously registered device handler. */ -status_t -unregister_device_handler(struct net_device* device, int32 type) -{ - MutexLocker locker(sInterfaceLock); - - // find device interface for this device - net_device_interface* interface = find_device_interface(device->name); - if (interface == NULL) - return ENODEV; - - RecursiveLocker _(interface->receive_lock); - - // search for the handler - - DeviceHandlerList::Iterator iterator - = interface->receive_funcs.GetIterator(); - while (net_device_handler* handler = iterator.Next()) { - if (handler->type == type) { - // found it - iterator.Remove(); - delete handler; - return B_OK; - } - } - - return B_BAD_VALUE; -} - - -/*! Registers a device monitor for the specified device. */ -status_t -register_device_monitor(net_device* device, net_device_monitor* monitor) -{ - if (monitor->receive == NULL || monitor->event == NULL) - return B_BAD_VALUE; - - MutexLocker locker(sInterfaceLock); - - // find device interface for this device - net_device_interface* interface = find_device_interface(device->name); - if (interface == NULL) - return ENODEV; - - RecursiveLocker _(interface->receive_lock); - interface->monitor_funcs.Add(monitor); - return B_OK; -} - - -/*! Unregisters a previously registered device monitor. */ -status_t -unregister_device_monitor(net_device* device, net_device_monitor* monitor) -{ - MutexLocker locker(sInterfaceLock); - - // find device interface for this device - net_device_interface* interface = find_device_interface(device->name); - if (interface == NULL) - return ENODEV; - - RecursiveLocker _(interface->receive_lock); - - // search for the monitor - - DeviceMonitorList::Iterator iterator = interface->monitor_funcs.GetIterator(); - while (iterator.HasNext()) { - if (iterator.Next() == monitor) { - iterator.Remove(); - return B_OK; - } - } - - return B_BAD_VALUE; -} - - -/*! This function is called by device modules in case their link - state changed, ie. if an ethernet cable was plugged in or - removed. -*/ -status_t -device_link_changed(net_device* device) -{ - notify_link_changed(device); - return B_OK; -} - - -/*! This function is called by device modules once their device got - physically removed, ie. a USB networking card is unplugged. -*/ -status_t -device_removed(net_device* device) -{ - MutexLocker locker(sInterfaceLock); - - // hold a reference to the device interface being removed - // so our put_() will (eventually) do the final cleanup - net_device_interface* interface = get_device_interface(device->name, false); - if (interface == NULL) - return ENODEV; - - // Propagate the loss of the device throughout the stack. - // This is very complex, refer to delete_interface() for - // further details. - - domain_removed_device_interface(interface); - - notify_device_monitors(interface, B_DEVICE_BEING_REMOVED); - - // By now all of the monitors must have removed themselves. If they - // didn't, they'll probably wait forever to be callback'ed again. - interface->monitor_funcs.RemoveAll(); - - // All of the readers should be gone as well since we are out of - // interfaces and put_domain_datalink_protocols() is called for - // each delete_interface(). - - put_device_interface(interface); - - return B_OK; -} - - -status_t -device_enqueue_buffer(net_device* device, net_buffer* buffer) -{ - net_device_interface* interface = get_device_interface(device->index); - if (interface == NULL) - return ENODEV; - - status_t status = fifo_enqueue_buffer(&interface->receive_queue, buffer); - - put_device_interface(interface); - return status; -} - - // #pragma mark - status_t init_interfaces() { - mutex_init(&sInterfaceLock, "net interfaces"); + mutex_init(&sLock, "net interfaces"); + mutex_init(&sHashLock, "net local addresses"); - new (&sInterfaces) DeviceInterfaceList; + new (&sInterfaces) InterfaceList; + new (&sAddressTable) AddressTable; // static C++ objects are not initialized in the module startup #if ENABLE_DEBUGGER_COMMANDS add_debugger_command("net_interface", &dump_interface, "Dump the given network interface"); - add_debugger_command("net_device_interface", &dump_device_interface, - "Dump the given network device interface"); - add_debugger_command("net_device_interfaces", &dump_device_interfaces, - "Dump network device interfaces"); + add_debugger_command("net_interfaces", &dump_interfaces, + "Dump all network interfaces"); + add_debugger_command("net_local", &dump_local, + "Dump all local interface addresses"); + add_debugger_command("net_route", &dump_route, + "Dump the given network route"); #endif return B_OK; } @@ -913,11 +1252,10 @@ uninit_interfaces() { #if ENABLE_DEBUGGER_COMMANDS remove_debugger_command("net_interface", &dump_interface); - remove_debugger_command("net_device_interface", &dump_device_interface); - remove_debugger_command("net_device_interfaces", &dump_device_interfaces); #endif - mutex_destroy(&sInterfaceLock); + mutex_destroy(&sLock); + mutex_destroy(&sHashLock); return B_OK; } diff --git a/src/add-ons/kernel/network/stack/interfaces.h b/src/add-ons/kernel/network/stack/interfaces.h index 024931f00e..4eec34831b 100644 --- a/src/add-ons/kernel/network/stack/interfaces.h +++ b/src/add-ons/kernel/network/stack/interfaces.h @@ -1,5 +1,5 @@ /* - * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -9,93 +9,175 @@ #define INTERFACES_H +#include "routes.h" +#include "stack_private.h" + #include #include +#include + #include +#include -struct net_device_handler : DoublyLinkedListLinkImpl { - net_receive_func func; - int32 type; - void* cookie; +struct net_device_interface; + + +struct InterfaceAddress : DoublyLinkedListLinkImpl, + net_interface_address, Referenceable { + InterfaceAddress(); + InterfaceAddress(net_interface* interface, + net_domain* domain); + virtual ~InterfaceAddress(); + + status_t SetTo(const ifaliasreq& request); + + status_t SetLocal(const sockaddr* to); + status_t SetDestination(const sockaddr* to); + status_t SetMask(const sockaddr* to); + + sockaddr** AddressFor(int32 option); + + InterfaceAddress*& HashTableLink() { return fLink; } + +#if ENABLE_DEBUGGER_COMMANDS + void Dump(size_t index = 0, + bool hideInterface = false); +#endif + + static status_t Set(sockaddr** _address, const sockaddr* to); + static sockaddr* Prepare(sockaddr** _address, size_t length); + +private: + void _Init(net_interface* interface, + net_domain* domain); + +private: + InterfaceAddress* fLink; }; -typedef DoublyLinkedList DeviceHandlerList; +typedef DoublyLinkedList AddressList; -typedef DoublyLinkedList > DeviceMonitorList; +struct domain_datalink { + domain_datalink* hash_link; + net_domain* domain; -struct net_device_interface : DoublyLinkedListLinkImpl { - struct net_device* device; - thread_id reader_thread; - uint32 up_count; - // a device can be brought up by more than one interface - int32 ref_count; + struct net_datalink_protocol* first_protocol; + struct net_datalink_protocol_module_info* first_info; - net_deframe_func deframe_func; - int32 deframe_ref_count; - - DeviceMonitorList monitor_funcs; - DeviceHandlerList receive_funcs; - - recursive_lock receive_lock; - - thread_id consumer_thread; - net_fifo receive_queue; -}; - -typedef DoublyLinkedList DeviceInterfaceList; - -struct net_interface_private : net_interface { - char base_name[IF_NAMESIZE]; - net_device_interface* device_interface; + // support for binding to an interface net_route_private direct_route; + InterfaceAddress direct_address; }; +struct DatalinkHashDefinition { + typedef const int KeyType; + typedef domain_datalink ValueType; + + DatalinkHashDefinition() + { + } + + size_t HashKey(const KeyType& key) const + { + return (size_t)key; + } + + size_t Hash(domain_datalink* datalink) const + { + return datalink->domain->family; + } + + bool Compare(const KeyType& key, domain_datalink* datalink) const + { + return datalink->domain->family == key; + } + + domain_datalink*& GetLink(domain_datalink* datalink) const + { + return datalink->hash_link; + } +}; + +typedef BOpenHashTable DatalinkTable; + + +class Interface : public DoublyLinkedListLinkImpl, + public net_interface, public Referenceable { +public: + Interface(const char* name, + net_device_interface* deviceInterface); + virtual ~Interface(); + + InterfaceAddress* FirstForFamily(int family); + InterfaceAddress* FirstUnconfiguredForFamily(int family); + InterfaceAddress* AddressForDestination(net_domain* domain, + const sockaddr* destination); + + status_t AddAddress(InterfaceAddress* address); + void RemoveAddress(InterfaceAddress* address); + bool GetNextAddress(InterfaceAddress** _address); + + status_t Control(net_domain* domain, int32 option, + ifreq& request, ifreq* userRequest, + size_t length); + + recursive_lock& Lock() { return fLock; } + + net_device_interface* DeviceInterface() { return fDeviceInterface; } + + status_t CreateDomainDatalinkIfNeeded( + net_domain* domain); + domain_datalink* DomainDatalink(uint8 family); + domain_datalink* DomainDatalink(net_domain* domain) + { return DomainDatalink(domain->family); } + +#if ENABLE_DEBUGGER_COMMANDS + void Dump() const; +#endif + +private: + status_t _SetUp(); + void _SetDown(); + InterfaceAddress* _FirstForFamily(int family); + status_t _AddDomainDatalink(net_domain* domain); + +private: + recursive_lock fLock; + net_device_interface* fDeviceInterface; + AddressList fAddresses; + DatalinkTable fDatalinkTable; +}; + +typedef DoublyLinkedList InterfaceList; + status_t init_interfaces(); status_t uninit_interfaces(); // interfaces -struct net_interface_private* find_interface(struct net_domain* domain, - const char* name); -struct net_interface_private* find_interface(struct net_domain* domain, - uint32 index); -void put_interface(struct net_interface_private* interface); -struct net_interface_private* get_interface(net_domain* domain, - const char* name); -status_t create_interface(net_domain* domain, const char* name, - const char* baseName, net_device_interface* deviceInterface, - struct net_interface_private** _interface); -void delete_interface(net_interface_private* interface); -void interface_set_down(net_interface* interface); +status_t add_interface(const char* name, net_domain_private* domain, + const ifaliasreq& request, net_device_interface* deviceInterface); +status_t remove_interface(Interface* interface); +void interface_went_down(Interface* interface); -// device interfaces -void get_device_interface_address(net_device_interface* interface, - sockaddr* address); -uint32 count_device_interfaces(); -status_t list_device_interfaces(void* buffer, size_t* _bufferSize); -void put_device_interface(struct net_device_interface* interface); -struct net_device_interface* get_device_interface(uint32 index); -struct net_device_interface* get_device_interface(const char* name, - bool create = true); -void down_device_interface(net_device_interface* interface); +status_t add_interface_address(Interface* interface, net_domain_private* domain, + const ifaliasreq& request); +status_t update_interface_address(InterfaceAddress* interfaceAddress, + int32 option, const sockaddr* oldAddress, const sockaddr* newAddress); + +Interface* get_interface(net_domain* domain, uint32 index); +Interface* get_interface(net_domain* domain, const char* name); +Interface* get_interface_for_device(net_domain* domain, uint32 index); +InterfaceAddress* get_interface_address(const struct sockaddr* address); +InterfaceAddress* get_interface_address_for_destination(net_domain* domain, + const struct sockaddr* destination); +InterfaceAddress* get_interface_address_for_link(net_domain* domain, + const struct sockaddr* linkAddress, bool unconfiguredOnly); + +uint32 count_interfaces(); +status_t list_interfaces(int family, void* buffer, size_t* _bufferSize); -// devices -status_t unregister_device_deframer(net_device* device); -status_t register_device_deframer(net_device* device, net_deframe_func deframeFunc); -status_t register_domain_device_handler(struct net_device* device, int32 type, - struct net_domain* domain); -status_t register_device_handler(struct net_device* device, int32 type, - net_receive_func receiveFunc, void* cookie); -status_t unregister_device_handler(struct net_device* device, int32 type); -status_t register_device_monitor(struct net_device* device, - struct net_device_monitor* monitor); -status_t unregister_device_monitor(struct net_device* device, - struct net_device_monitor* monitor); -status_t device_link_changed(net_device* device); -status_t device_removed(net_device* device); -status_t device_enqueue_buffer(net_device* device, net_buffer* buffer); #endif // INTERFACES_H diff --git a/src/add-ons/kernel/network/stack/link.cpp b/src/add-ons/kernel/network/stack/link.cpp index 101b1f259b..010950d7a9 100644 --- a/src/add-ons/kernel/network/stack/link.cpp +++ b/src/add-ons/kernel/network/stack/link.cpp @@ -1,16 +1,18 @@ /* - * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Axel Dörfler, axeld@pinc-software.de */ + //! The net_protocol one talks to when using the AF_LINK protocol + #include "datalink.h" +#include "device_interfaces.h" #include "domains.h" -#include "interfaces.h" #include "link.h" #include "stack_private.h" #include "utility.h" diff --git a/src/add-ons/kernel/network/stack/net_buffer.cpp b/src/add-ons/kernel/network/stack/net_buffer.cpp index 602bc77d83..d2ef188d3f 100644 --- a/src/add-ons/kernel/network/stack/net_buffer.cpp +++ b/src/add-ons/kernel/network/stack/net_buffer.cpp @@ -28,6 +28,7 @@ #include #include "ancillary_data.h" +#include "interfaces.h" #include "paranoia_config.h" @@ -127,6 +128,10 @@ struct data_node { } }; + +// TODO: we should think about moving the address fields into the buffer +// data itself via associated data or something like this. Or this +// structure as a whole, too... struct net_buffer_private : net_buffer { struct list buffers; data_header* allocation_header; @@ -578,15 +583,24 @@ private: static void -dump_address(const char* prefix, sockaddr* address) +dump_address(const char* prefix, sockaddr* address, + net_interface_address* interfaceAddress) { if (address == NULL || address->sa_len == 0) return; - dprintf(" %s: length %u, family %u\n", prefix, address->sa_len, - address->sa_family); + if (interfaceAddress == NULL || interfaceAddress->domain == NULL) { + dprintf(" %s: length %u, family %u\n", prefix, address->sa_len, + address->sa_family); - dump_block((char*)address + 2, address->sa_len - 2, " "); + dump_block((char*)address + 2, address->sa_len - 2, " "); + } else { + char buffer[64]; + interfaceAddress->domain->address_module->print_address_buffer(address, + buffer, sizeof(buffer), true); + + dprintf(" %s: %s\n", prefix, buffer); + } } @@ -596,11 +610,11 @@ dump_buffer(net_buffer* _buffer) net_buffer_private* buffer = (net_buffer_private*)_buffer; dprintf("buffer %p, size %" B_PRIu32 ", flags %" B_PRIx32 ", stored header " - "%" B_PRIu32 "\n", buffer, buffer->size, buffer->flags, - buffer->stored_header_length); + "%" B_PRIu32 ", interface address %p\n", buffer, buffer->size, + buffer->flags, buffer->stored_header_length, buffer->interface_address); - dump_address("source", buffer->source); - dump_address("destination", buffer->destination); + dump_address("source", buffer->source, buffer->interface_address); + dump_address("destination", buffer->destination, buffer->interface_address); data_node* node = NULL; while ((node = (data_node*)list_get_next_item(&buffer->buffers, node)) @@ -1060,7 +1074,7 @@ copy_metadata(net_buffer* destination, const net_buffer* source) min_c(source->destination->sa_len, sizeof(sockaddr_storage))); destination->flags = source->flags; - destination->interface = source->interface; + destination->interface_address = source->interface_address; destination->offset = source->offset; destination->protocol = source->protocol; destination->type = source->type; @@ -1107,13 +1121,11 @@ create_buffer(size_t headerSpace) buffer->storage.source.ss_len = 0; buffer->storage.destination.ss_len = 0; - buffer->interface = NULL; + buffer->interface_address = NULL; buffer->offset = 0; buffer->flags = 0; buffer->size = 0; - buffer->type = -1; - CHECK_BUFFER(buffer); CREATE_PARANOIA_CHECK_SET(buffer, "net_buffer"); SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, @@ -2086,23 +2098,29 @@ status_t restore_header(net_buffer* _buffer, uint32 offset, void* data, size_t bytes) { net_buffer_private* buffer = (net_buffer_private*)_buffer; - data_node* node = (data_node*)list_get_first_item(&buffer->buffers); - if (node == NULL - || offset + bytes > buffer->stored_header_length + buffer->size) - return B_BAD_VALUE; - - // We have the data, so copy it out - - memcpy(data, node->start - buffer->stored_header_length, - std::min(bytes, buffer->stored_header_length)); - if (bytes <= buffer->stored_header_length) - return B_OK; + if (offset < buffer->stored_header_length) { + data_node* node = (data_node*)list_get_first_item(&buffer->buffers); + if (node == NULL + || offset + bytes > buffer->stored_header_length + buffer->size) + return B_BAD_VALUE; - data = (uint8*)data + buffer->stored_header_length; - bytes -= buffer->stored_header_length; + // We have the data, so copy it out - return read_data(_buffer, 0, data, bytes); + size_t copied = std::min(bytes, buffer->stored_header_length - offset); + memcpy(data, node->start + offset - buffer->stored_header_length, + copied); + + if (copied == bytes) + return B_OK; + + data = (uint8*)data + copied; + bytes -= copied; + offset = 0; + } else + offset -= buffer->stored_header_length; + + return read_data(_buffer, offset, data, bytes); } @@ -2116,25 +2134,30 @@ append_restored_header(net_buffer* buffer, net_buffer* _source, uint32 offset, size_t bytes) { net_buffer_private* source = (net_buffer_private*)_source; - data_node* node = (data_node*)list_get_first_item(&source->buffers); - if (node == NULL - || offset + bytes > source->stored_header_length + source->size) - return B_BAD_VALUE; - // We have the data, so copy it out + if (offset < source->stored_header_length) { + data_node* node = (data_node*)list_get_first_item(&source->buffers); + if (node == NULL + || offset + bytes > source->stored_header_length + source->size) + return B_BAD_VALUE; - status_t status = append_data(buffer, - node->start - source->stored_header_length, - std::min(bytes, source->stored_header_length)); - if (status != B_OK) - return status; + // We have the data, so copy it out - if (bytes <= source->stored_header_length) - return B_OK; + size_t appended = std::min(bytes, source->stored_header_length - offset); + status_t status = append_data(buffer, + node->start + offset - source->stored_header_length, appended); + if (status != B_OK) + return status; - bytes -= source->stored_header_length; + if (appended == bytes) + return B_OK; - return append_cloned_data(buffer, source, 0, bytes); + bytes -= appended; + offset = 0; + } else + offset -= source->stored_header_length; + + return append_cloned_data(buffer, source, offset, bytes); } diff --git a/src/add-ons/kernel/network/stack/routes.cpp b/src/add-ons/kernel/network/stack/routes.cpp index e5e0aba3a2..659a11583e 100644 --- a/src/add-ons/kernel/network/stack/routes.cpp +++ b/src/add-ons/kernel/network/stack/routes.cpp @@ -31,9 +31,9 @@ //#define TRACE_ROUTES #ifdef TRACE_ROUTES -# define TRACE(x) dprintf x +# define TRACE(x...) dprintf(STACK_DEBUG_PREFIX x) #else -# define TRACE(x) ; +# define TRACE(x...) ; #endif @@ -131,8 +131,9 @@ find_route(struct net_domain* _domain, const net_route* description) if ((route->flags & RTF_DEFAULT) != 0 && (description->flags & RTF_DEFAULT) != 0) { - // there can only be one default route per interface - if (route->interface == description->interface) + // there can only be one default route per interface address family + // TODO: check this better + if (route->interface_address == description->interface_address) return route; continue; @@ -147,8 +148,8 @@ find_route(struct net_domain* _domain, const net_route* description) description->mask) && domain->address_module->equal_addresses(route->gateway, description->gateway) - && (description->interface == NULL - || description->interface == route->interface)) + && (description->interface_address == NULL + || description->interface_address == route->interface_address)) return route; } @@ -166,8 +167,8 @@ find_route(net_domain* _domain, const sockaddr* address) RouteList::Iterator iterator = domain->routes.GetIterator(); net_route_private* candidate = NULL; - TRACE(("test address %s for routes...\n", - AddressString(domain, address).Data())); + TRACE("test address %s for routes...\n", + AddressString(domain, address).Data()); // TODO: alternate equal default routes @@ -186,17 +187,18 @@ find_route(net_domain* _domain, const sockaddr* address) continue; // neglect routes that point to devices that have no link - if ((route->interface->device->flags & IFF_LINK) == 0) { + if ((route->interface_address->interface->device->flags & IFF_LINK) + == 0) { if (candidate == NULL) { - TRACE((" found candidate: %s, flags %lx\n", AddressString( - domain, route->destination).Data(), route->flags)); + TRACE(" found candidate: %s, flags %lx\n", AddressString( + domain, route->destination).Data(), route->flags); candidate = route; } continue; } - TRACE((" found route: %s, flags %lx\n", - AddressString(domain, route->destination).Data(), route->flags)); + TRACE(" found route: %s, flags %lx\n", + AddressString(domain, route->destination).Data(), route->flags); return route; } @@ -215,6 +217,9 @@ put_route_internal(struct net_domain_private* domain, net_route* _route) return; // delete route - it must already have been removed at this point + if (route->interface_address != NULL) + ((InterfaceAddress*)route->interface_address)->ReleaseReference(); + delete route; } @@ -234,7 +239,7 @@ get_route_internal(struct net_domain_private* domain, while (iterator.HasNext()) { route = iterator.Next(); - net_device* device = route->interface->device; + net_device* device = route->interface_address->interface->device; if ((link->sdl_nlen > 0 && !strncmp(device->name, (const char*)link->sdl_data, @@ -291,7 +296,7 @@ fill_route_entry(route_entry* target, void* _buffer, size_t bufferSize, target->destination = copy_address(buffer, route->destination); target->mask = copy_address(buffer, route->mask); target->gateway = copy_address(buffer, route->gateway); - target->source = copy_address(buffer, route->interface->address); + target->source = copy_address(buffer, route->interface_address->local); target->flags = route->flags; target->mtu = route->mtu; @@ -375,7 +380,8 @@ list_routes(net_domain_private* domain, void* buffer, size_t size) return ENOBUFS; ifreq request; - strlcpy(request.ifr_name, route->interface->name, IF_NAMESIZE); + strlcpy(request.ifr_name, route->interface_address->interface->name, + IF_NAMESIZE); request.ifr_route.destination = destination; request.ifr_route.mask = mask; request.ifr_route.gateway = gateway; @@ -402,10 +408,10 @@ list_routes(net_domain_private* domain, void* buffer, size_t size) status_t -control_routes(struct net_interface* interface, int32 option, void* argument, - size_t length) +control_routes(struct net_interface* _interface, net_domain* domain, + int32 option, void* argument, size_t length) { - net_domain_private* domain = (net_domain_private*)interface->domain; + Interface* interface = (Interface*)_interface; switch (option) { case SIOCADDRT: @@ -429,14 +435,20 @@ control_routes(struct net_interface* interface, int32 option, void* argument, != B_OK) return status; + InterfaceAddress* address + = interface->FirstForFamily(domain->family); + route.mtu = entry.mtu; route.flags = entry.flags; - route.interface = interface; + route.interface_address = address; if (option == SIOCADDRT) - return add_route(domain, &route); + status = add_route(domain, &route); + else + status = remove_route(domain, &route); - return remove_route(domain, &route); + address->ReleaseReference(); + return status; } } return B_BAD_VALUE; @@ -448,16 +460,20 @@ add_route(struct net_domain* _domain, const struct net_route* newRoute) { struct net_domain_private* domain = (net_domain_private*)_domain; - TRACE(("add route to domain %s: dest %s, mask %s, gw %s, flags %lx\n", + TRACE("add route to domain %s: dest %s, mask %s, gw %s, flags %lx\n", domain->name, - AddressString(domain, newRoute->destination ? newRoute->destination : NULL).Data(), + AddressString(domain, newRoute->destination + ? newRoute->destination : NULL).Data(), AddressString(domain, newRoute->mask ? newRoute->mask : NULL).Data(), - AddressString(domain, newRoute->gateway ? newRoute->gateway : NULL).Data(), - newRoute->flags)); + AddressString(domain, newRoute->gateway + ? newRoute->gateway : NULL).Data(), + newRoute->flags); - if (domain == NULL || newRoute == NULL || newRoute->interface == NULL + if (domain == NULL || newRoute == NULL + || newRoute->interface_address == NULL || ((newRoute->flags & RTF_HOST) != 0 && newRoute->mask != NULL) - || ((newRoute->flags & RTF_DEFAULT) == 0 && newRoute->destination == NULL) + || ((newRoute->flags & RTF_DEFAULT) == 0 + && newRoute->destination == NULL) || ((newRoute->flags & RTF_GATEWAY) != 0 && newRoute->gateway == NULL) || !domain->address_module->check_mask(newRoute->mask)) return B_BAD_VALUE; @@ -484,7 +500,8 @@ add_route(struct net_domain* _domain, const struct net_route* newRoute) } route->flags = newRoute->flags; - route->interface = newRoute->interface; + route->interface_address = newRoute->interface_address; + ((InterfaceAddress*)route->interface_address)->AcquireReference(); route->mtu = 0; route->ref_count = 1; @@ -504,8 +521,8 @@ add_route(struct net_domain* _domain, const struct net_route* newRoute) && (before->flags & RTF_DEFAULT) != 0) { // both routes are equal - let the link speed decide the // order - if (before->interface->device->link_speed - < route->interface->device->link_speed) + if (before->interface_address->interface->device->link_speed + < route->interface_address->interface->device->link_speed) break; } } @@ -522,12 +539,15 @@ remove_route(struct net_domain* _domain, const struct net_route* removeRoute) { struct net_domain_private* domain = (net_domain_private*)_domain; - TRACE(("remove route from domain %s: dest %s, mask %s, gw %s, flags %lx\n", + TRACE("remove route from domain %s: dest %s, mask %s, gw %s, flags %lx\n", domain->name, - AddressString(domain, removeRoute->destination ? removeRoute->destination : NULL).Data(), - AddressString(domain, removeRoute->mask ? removeRoute->mask : NULL).Data(), - AddressString(domain, removeRoute->gateway ? removeRoute->gateway : NULL).Data(), - removeRoute->flags)); + AddressString(domain, removeRoute->destination + ? removeRoute->destination : NULL).Data(), + AddressString(domain, removeRoute->mask + ? removeRoute->mask : NULL).Data(), + AddressString(domain, removeRoute->gateway + ? removeRoute->gateway : NULL).Data(), + removeRoute->flags); RecursiveLocker locker(domain->lock); @@ -578,9 +598,8 @@ get_route_information(struct net_domain* _domain, void* value, size_t length) void invalidate_routes(net_domain* _domain, net_interface* interface) { - // this function is called with the domain locked - // (see domain_interface_went_down) net_domain_private* domain = (net_domain_private*)_domain; + RecursiveLocker locker(domain->lock); dprintf("invalidate_routes(%i, %s)\n", domain->family, interface->name); @@ -588,7 +607,7 @@ invalidate_routes(net_domain* _domain, net_interface* interface) while (iterator.HasNext()) { net_route* route = iterator.Next(); - if (route->interface->index == interface->index) + if (route->interface_address->interface == interface) remove_route(domain, route); } } @@ -605,28 +624,20 @@ get_route(struct net_domain* _domain, const struct sockaddr* address) status_t -get_device_route(struct net_domain* _domain, uint32 index, net_route** _route) +get_device_route(struct net_domain* domain, uint32 index, net_route** _route) { - net_domain_private* domain = (net_domain_private*)_domain; + Interface* interface = get_interface_for_device(domain, index); + if (interface == NULL) + return ENETUNREACH; - RecursiveLocker _(domain->lock); + net_route_private* route + = &interface->DomainDatalink(domain->family)->direct_route; - net_interface_private* interface = NULL; + atomic_add(&route->ref_count, 1); + *_route = route; - while (true) { - interface = (net_interface_private*)list_get_next_item( - &domain->interfaces, interface); - if (interface == NULL) - break; - - if (interface->device->index == index) { - atomic_add(&interface->direct_route.ref_count, 1); - *_route = &interface->direct_route; - return B_OK; - } - } - - return ENETUNREACH; + interface->ReleaseReference(); + return B_OK; } @@ -647,9 +658,10 @@ get_buffer_route(net_domain* _domain, net_buffer* buffer, net_route** _route) // TODO: we are quite relaxed in the address checking here // as we might proceed with source = INADDR_ANY. - if (route->interface != NULL && route->interface->address != NULL) { + if (route->interface_address != NULL + && route->interface_address->local != NULL) { status = domain->address_module->update_to(source, - route->interface->address); + route->interface_address->local); } if (status != B_OK) diff --git a/src/add-ons/kernel/network/stack/routes.h b/src/add-ons/kernel/network/stack/routes.h index 60c1f37abc..c1bc6f742a 100644 --- a/src/add-ons/kernel/network/stack/routes.h +++ b/src/add-ons/kernel/network/stack/routes.h @@ -31,7 +31,7 @@ typedef DoublyLinkedListfirst_protocol; + net_datalink_protocol* protocol = datalink->first_protocol; while (protocol != NULL) { net_datalink_protocol* next = protocol->next; protocol->module->uninit_protocol(protocol); @@ -511,22 +512,21 @@ uninit_domain_datalink_protocols(net_interface* interface) protocol = next; } - interface->first_protocol = NULL; - interface->first_info = NULL; + datalink->first_protocol = NULL; + datalink->first_info = NULL; } status_t -get_domain_datalink_protocols(net_interface* _interface) +get_domain_datalink_protocols(Interface* interface, net_domain* domain) { - struct net_interface_private* interface = (net_interface_private*)_interface; struct chain* chain; { MutexLocker _(sChainLock); - chain = chain::Lookup(sDatalinkProtocolChains, interface->domain->family, - interface->device_interface->device->type, 0); + chain = chain::Lookup(sDatalinkProtocolChains, domain->family, + interface->DeviceInterface()->device->type, 0); if (chain == NULL) return EAFNOSUPPORT; } @@ -542,21 +542,26 @@ get_domain_datalink_protocols(net_interface* _interface) for (int32 i = 0; chain->infos[i] != NULL; i++) { net_datalink_protocol* protocol; status_t status = ((net_datalink_protocol_module_info*) - chain->infos[i])->init_protocol(interface, &protocol); - if (status < B_OK) { + chain->infos[i])->init_protocol(interface, domain, &protocol); + if (status != B_OK) { // free protocols we already initialized - uninit_domain_datalink_protocols(interface); + uninit_domain_datalink_protocols( + interface->DomainDatalink(domain->family)); chain->Release(); return status; } protocol->module = (net_datalink_protocol_module_info*)chain->infos[i]; protocol->interface = interface; + protocol->domain = domain; protocol->next = NULL; if (last == NULL) { - interface->first_protocol = protocol; - interface->first_info = protocol->module; + domain_datalink* datalink + = interface->DomainDatalink(domain->family); + + datalink->first_protocol = protocol; + datalink->first_info = protocol->module; } else last->next = protocol; @@ -568,21 +573,20 @@ get_domain_datalink_protocols(net_interface* _interface) status_t -put_domain_datalink_protocols(net_interface* _interface) +put_domain_datalink_protocols(Interface* interface, net_domain* domain) { - struct net_interface_private* interface = (net_interface_private*)_interface; struct chain* chain; { MutexLocker _(sChainLock); - chain = chain::Lookup(sDatalinkProtocolChains, interface->domain->family, - interface->device_interface->device->type, 0); + chain = chain::Lookup(sDatalinkProtocolChains, domain->family, + interface->DeviceInterface()->device->type, 0); if (chain == NULL) return B_ERROR; } - uninit_domain_datalink_protocols(interface); + uninit_domain_datalink_protocols(interface->DomainDatalink(domain->family)); chain->Release(); return B_OK; } @@ -756,10 +760,14 @@ init_stack() if (status != B_OK) goto err1; - status = init_timers(); + status = init_device_interfaces(); if (status != B_OK) goto err2; + status = init_timers(); + if (status != B_OK) + goto err3; + status = init_notifications(); if (status < B_OK) { // If this fails, it just means there won't be any notifications, @@ -771,7 +779,7 @@ init_stack() module_info* dummy; status = get_module(NET_SOCKET_MODULE_NAME, &dummy); if (status != B_OK) - goto err3; + goto err4; mutex_init(&sChainLock, "net chains"); mutex_init(&sInitializeChainLock, "net intialize chains"); @@ -816,7 +824,6 @@ init_stack() register_domain_datalink_protocols(AF_INET6, IFT_LOOP, "network/datalink_protocols/loopback_frame/v1", NULL); register_domain_datalink_protocols(AF_INET, IFT_ETHER, - "network/datalink_protocols/ipv4_datagram/v1", "network/datalink_protocols/arp/v1", "network/datalink_protocols/ethernet_frame/v1", NULL); @@ -836,8 +843,10 @@ err6: err5: mutex_destroy(&sInitializeChainLock); mutex_destroy(&sChainLock); -err3: +err4: uninit_timers(); +err3: + uninit_device_interfaces(); err2: uninit_interfaces(); err1: @@ -853,6 +862,7 @@ uninit_stack() put_module(NET_SOCKET_MODULE_NAME); uninit_timers(); + uninit_device_interfaces(); uninit_interfaces(); uninit_domains(); uninit_notifications(); diff --git a/src/add-ons/kernel/network/stack/stack_private.h b/src/add-ons/kernel/network/stack/stack_private.h index fab5f4bdea..4736a31ba2 100644 --- a/src/add-ons/kernel/network/stack/stack_private.h +++ b/src/add-ons/kernel/network/stack/stack_private.h @@ -18,6 +18,14 @@ #include +// Stack-wide configuration +#define ENABLE_DEBUGGER_COMMANDS 1 +#define STACK_DEBUG_PREFIX "\33[31mnet:\33[0m " + + +class Interface; + + extern net_stack_module_info gNetStackModule; extern net_buffer_module_info gNetBufferModule; extern net_socket_module_info gNetSocketModule; @@ -28,10 +36,12 @@ extern net_stack_interface_module_info gNetStackInterfaceModule; // stack.cpp status_t register_domain_datalink_protocols(int family, int type, ...); status_t register_domain_protocols(int family, int type, int protocol, ...); -status_t get_domain_protocols(net_socket *socket); -status_t put_domain_protocols(net_socket *socket); -status_t get_domain_datalink_protocols(net_interface *interface); -status_t put_domain_datalink_protocols(net_interface *interface); +status_t get_domain_protocols(net_socket* socket); +status_t put_domain_protocols(net_socket* socket); +status_t get_domain_datalink_protocols(Interface* interface, + net_domain* domain); +status_t put_domain_datalink_protocols(Interface* interface, + net_domain* domain); // notifications.cpp status_t notify_interface_added(net_interface* interface); diff --git a/src/bin/debug/strace/ioctl.cpp b/src/bin/debug/strace/ioctl.cpp index 895016abce..e463c0af70 100644 --- a/src/bin/debug/strace/ioctl.cpp +++ b/src/bin/debug/strace/ioctl.cpp @@ -1,13 +1,15 @@ /* - * Copyright 2007, Haiku Inc. All rights reserved. + * Copyright 2007-2010, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Hugo Santos */ + #include #include + #include #include #include @@ -16,6 +18,7 @@ #include "Syscall.h" #include "TypeHandler.h" + struct ioctl_info { int index; const char *name; @@ -83,7 +86,7 @@ static const ioctl_info kIOCtls[] = { IOCTL_INFO_ENTRY_TYPE(SIOCGIFMETRIC, struct ifreq *), IOCTL_INFO_ENTRY_TYPE(SIOCSIFMETRIC, struct ifreq *), IOCTL_INFO_ENTRY_TYPE(SIOCDIFADDR, struct ifreq *), - IOCTL_INFO_ENTRY_TYPE(SIOCAIFADDR, struct ifreq *), + IOCTL_INFO_ENTRY_TYPE(SIOCAIFADDR, struct ifaliasreq *), IOCTL_INFO_ENTRY(SIOCADDMULTI), IOCTL_INFO_ENTRY(SIOCDELMULTI), IOCTL_INFO_ENTRY_TYPE(SIOCGIFMTU, struct ifreq *), @@ -93,7 +96,6 @@ static const ioctl_info kIOCtls[] = { IOCTL_INFO_ENTRY(SIOCGRTSIZE), IOCTL_INFO_ENTRY(SIOCGRTTABLE), IOCTL_INFO_ENTRY_TYPE(SIOCGIFSTATS, struct ifreq *), - IOCTL_INFO_ENTRY_TYPE(SIOCGIFPARAM, struct ifreq *), IOCTL_INFO_ENTRY(SIOCGIFTYPE), IOCTL_INFO_ENTRY(SIOCSPACKETCAP), IOCTL_INFO_ENTRY(SIOCCPACKETCAP), diff --git a/src/bin/network/ifconfig/ifconfig.cpp b/src/bin/network/ifconfig/ifconfig.cpp index 9c620c670b..b686724618 100644 --- a/src/bin/network/ifconfig/ifconfig.cpp +++ b/src/bin/network/ifconfig/ifconfig.cpp @@ -541,32 +541,29 @@ list_interface(const char* name, int addressFamily) char address[256]; strcpy(address, "none"); - if (ioctl(socket, SIOCGIFPARAM, &request, sizeof(struct ifreq)) == 0) { - prepare_request(request, request.ifr_parameter.device); - if (ioctl(linkSocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) - == 0) { - sockaddr_dl &link = *(sockaddr_dl*)&request.ifr_addr; + if (ioctl(linkSocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) + == 0) { + sockaddr_dl &link = *(sockaddr_dl*)&request.ifr_addr; - switch (link.sdl_type) { - case IFT_ETHER: - { - type = "Ethernet"; + switch (link.sdl_type) { + case IFT_ETHER: + { + type = "Ethernet"; - if (link.sdl_alen > 0) { - uint8 *mac = (uint8*)LLADDR(&link); - sprintf(address, "%02x:%02x:%02x:%02x:%02x:%02x", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - } else - strcpy(address, "not available"); - break; - } - case IFT_LOOP: - type = "Local Loopback"; - break; - case IFT_MODEM: - type = "Modem"; - break; + if (link.sdl_alen > 0) { + uint8 *mac = (uint8*)LLADDR(&link); + sprintf(address, "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } else + strcpy(address, "not available"); + break; } + case IFT_LOOP: + type = "Local Loopback"; + break; + case IFT_MODEM: + type = "Modem"; + break; } } @@ -778,10 +775,12 @@ configure_interface(const char* name, char* const* args, if (index == 0) { // the interface does not exist yet, we have to add it first - request.ifr_parameter.base_name[0] = '\0'; - request.ifr_parameter.device[0] = '\0'; - request.ifr_parameter.sub_type = 0; - // the default device is okay for us + ifaliasreq request; + strlcpy(request.ifra_name, name, IF_NAMESIZE); + + request.ifra_addr.ss_family = AF_UNSPEC; + request.ifra_mask.ss_family = AF_UNSPEC; + request.ifra_broadaddr.ss_family = AF_UNSPEC; if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) { fprintf(stderr, "%s: Could not add interface: %s\n", kProgramName, diff --git a/src/bin/network/setwep/setwep.c b/src/bin/network/setwep/setwep.c index 9033c9c629..f3ec45c5da 100644 --- a/src/bin/network/setwep/setwep.c +++ b/src/bin/network/setwep/setwep.c @@ -64,7 +64,7 @@ get_string(const char* val, const char* sep, u_int8_t* buf, int* lenp) if (hexstr) printf("%s: hexadecimal digits too long", __func__); else - printf("string too long", __func__); + printf("%s: string too long", __func__); return NULL; } if (hexstr) { diff --git a/src/bin/network/tcpdump/libpcap/pcap-haiku.cpp b/src/bin/network/tcpdump/libpcap/pcap-haiku.cpp index 1033835024..3af1bddc90 100644 --- a/src/bin/network/tcpdump/libpcap/pcap-haiku.cpp +++ b/src/bin/network/tcpdump/libpcap/pcap-haiku.cpp @@ -176,18 +176,11 @@ pcap_open_live(const char *device, int snapLength, int /*promisc*/, return NULL; } - // get link level interface for this interface - - if (ioctl(socket, SIOCGIFPARAM, &request, sizeof(struct ifreq)) < 0) { - snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "Cannot get link level: %s\n", - strerror(errno)); - close(socket); - return NULL; - } - close(socket); // no longer needed after this point + // get link level interface for this interface + socket = ::socket(AF_LINK, SOCK_DGRAM, 0); if (socket < 0) { snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "No link level: %s\n", @@ -196,7 +189,6 @@ pcap_open_live(const char *device, int snapLength, int /*promisc*/, } // start monitoring - prepare_request(request, request.ifr_parameter.device); if (ioctl(socket, SIOCSPACKETCAP, &request, sizeof(struct ifreq)) < 0) { snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "Cannot start monitoring: %s\n", strerror(errno)); @@ -318,16 +310,12 @@ pcap_platform_finddevs(pcap_if_t** _allDevices, char* errorBuffer) return -1; } - if (ioctl(socket, SIOCGIFPARAM, &request, sizeof(struct ifreq)) + if (ioctl(linkSocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) == 0) { - prepare_request(request, request.ifr_parameter.device); - if (ioctl(linkSocket, SIOCGIFADDR, &request, - sizeof(struct ifreq)) == 0) { - sockaddr_dl &link = *(sockaddr_dl*)&request.ifr_addr; + sockaddr_dl &link = *(sockaddr_dl*)&request.ifr_addr; - if (link.sdl_type == IFT_LOOP) - flags = IFF_LOOPBACK; - } + if (link.sdl_type == IFT_LOOP) + flags = IFF_LOOPBACK; } close(linkSocket); } diff --git a/src/servers/net/DHCPClient.cpp b/src/servers/net/DHCPClient.cpp index b8f89695b8..6dc7f8c1e2 100644 --- a/src/servers/net/DHCPClient.cpp +++ b/src/servers/net/DHCPClient.cpp @@ -503,6 +503,8 @@ DHCPClient::_Negotiate(dhcp_state state) case DHCP_OFFER: { + syslog(LOG_DEBUG, "DHCP received offer for %s\n", Device()); + // first offer wins if (state != INIT) break; @@ -537,6 +539,7 @@ DHCPClient::_Negotiate(dhcp_state state) case DHCP_ACK: { + syslog(LOG_DEBUG, "DHCP received ack for %s\n", Device()); if (state != REQUESTING && state != REBINDING && state != RENEWAL) continue; @@ -565,6 +568,8 @@ DHCPClient::_Negotiate(dhcp_state state) } case DHCP_NACK: + syslog(LOG_DEBUG, "DHCP received nack for %s\n", Device()); + if (state != REQUESTING) continue; @@ -638,7 +643,7 @@ DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address, case OPTION_DOMAIN_NAME_SERVER: { for (uint32 i = 0; i < size / 4; i++) { - syslog(LOG_INFO, "DNS: %s\n", + syslog(LOG_INFO, "DHCP for %s got DNS: %s\n", Device(), _ToString(&data[i * 4]).String()); resolverConfiguration.AddString("nameserver", _ToString(&data[i * 4]).String()); @@ -770,8 +775,8 @@ DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries) if (++tries > 2) return false; } - syslog(LOG_DEBUG, "DHCP timeout shift: %lu secs (try %lu)\n", timeout, - tries); + syslog(LOG_DEBUG, "DHCP timeout shift for %s: %lu secs (try %lu)\n", + Device(), timeout, tries); struct timeval value; value.tv_sec = timeout; @@ -802,6 +807,9 @@ status_t DHCPClient::_SendMessage(int socket, dhcp_message& message, sockaddr_in& address) const { + syslog(LOG_DEBUG, "DHCP send message %u for %s\n", message.Type(), + Device()); + ssize_t bytesSent = sendto(socket, &message, message.Size(), address.sin_addr.s_addr == INADDR_BROADCAST ? MSG_BCAST : 0, (struct sockaddr*)&address, sizeof(sockaddr_in)); diff --git a/src/servers/net/NetServer.cpp b/src/servers/net/NetServer.cpp index 82de140ca4..ae4c087a03 100644 --- a/src/servers/net/NetServer.cpp +++ b/src/servers/net/NetServer.cpp @@ -406,14 +406,10 @@ NetServer::_IsValidInterface(int socket, const char* name) // check if it has a hardware address, too, in case of ethernet - if (ioctl(socket, SIOCGIFPARAM, &request, sizeof(struct ifreq)) < 0) - return false; - int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0); if (linkSocket < 0) return false; - prepare_request(request, request.ifr_parameter.device); if (ioctl(linkSocket, SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0) { close(linkSocket); return false; @@ -623,10 +619,12 @@ NetServer::_ConfigureInterface(int socket, BMessage& interface, if (interfaceIndex == 0) { // we need to create the interface first - request.ifr_parameter.base_name[0] = '\0'; - request.ifr_parameter.device[0] = '\0'; - request.ifr_parameter.sub_type = 0; - // the default device is okay for us + ifaliasreq request; + strlcpy(request.ifra_name, device, IF_NAMESIZE); + + request.ifra_addr.ss_family = AF_UNSPEC; + request.ifra_mask.ss_family = AF_UNSPEC; + request.ifra_broadaddr.ss_family = AF_UNSPEC; if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) { fprintf(stderr, "%s: Could not add interface: %s\n", Name(), diff --git a/src/system/kernel/fs/vfs_net_boot.cpp b/src/system/kernel/fs/vfs_net_boot.cpp index e39b4cf66a..5e5879d14d 100644 --- a/src/system/kernel/fs/vfs_net_boot.cpp +++ b/src/system/kernel/fs/vfs_net_boot.cpp @@ -159,11 +159,17 @@ private: if (ioctl(fSocket, SIOCGIFINDEX, &request, sizeof(request)) < 0) { // not known yet -- add it - request.ifr_parameter.base_name[0] = '\0'; - request.ifr_parameter.device[0] = '\0'; - request.ifr_parameter.sub_type = 0; + ifaliasreq aliasRequest; + strcpy(aliasRequest.ifra_name, path); + aliasRequest.ifra_addr.ss_family = AF_UNSPEC; + aliasRequest.ifra_addr.ss_len = 2; + aliasRequest.ifra_broadaddr.ss_family = AF_UNSPEC; + aliasRequest.ifra_broadaddr.ss_len = 2; + aliasRequest.ifra_mask.ss_family = AF_UNSPEC; + aliasRequest.ifra_mask.ss_len = 2; - if (ioctl(fSocket, SIOCAIFADDR, &request, sizeof(request)) < 0) { + if (ioctl(fSocket, SIOCAIFADDR, &aliasRequest, + sizeof(aliasRequest)) < 0) { dprintf("NetStackInitializer: adding interface failed for " "device %s: %s\n", path, strerror(errno)); return;