* Reworked the complete stack to allow more than one address per network
interface - this caused quite a number of changes. * Network interfaces, and its addresses are now reference counted (not yet complete, though, InterfaceAddresses need to hold references to their interface as well). * There are two known regressions of this commit that I will fix later: - you cannot remove interfaces anymore - IPv4 multicast was broken anyway, but now it's disabled, too. * Moved a device_interfaces.cpp|h out of interfaces.cpp. * The datalink layer chain is now instantiated per domain per interface, not just per interface anymore. * When a buffer reaches the network layer, it has no known interface yet, ie. the ipv4|6|whatever modules need to set this manually. * Added more debug output, and some new debugger commands, the control option is now printed in clear text. * Added hash_address() function to the address modules. Added "const" to set_to_defaults() where needed. * Fixed net_buffer's restore header functions offset use as reported by Atis. * Improved buffer dump output, use the domain module to print the address if available. * Moved net_buffer::type into the union, as it's not needed by the upper layers anymore. * Moved IPv6 specific code from {add|remove}_default_route() to where it belongs, but disabled it for the time being. * Completely discarded useless ipv4_datagram module. * Added ping6 to the build. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37794 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
b216fbd077
commit
61729d9323
@ -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 <module>arp loopback_frame
|
||||
ipv4_datagram ;
|
||||
SYSTEM_NETWORK_DATALINK_PROTOCOLS = ethernet_frame <module>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
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 ;
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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<ether_header> 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<ether_header> 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
|
||||
};
|
||||
|
@ -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 <support/Errors.h> 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 ;
|
@ -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 <net_datalink.h>
|
||||
#include <net_datalink_protocol.h>
|
||||
#include <net_device.h>
|
||||
#include <net_stack.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <net/ethernet.h> // for ETHER_TYPE_IP
|
||||
#include <net/if_types.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
|
||||
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
|
||||
};
|
@ -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,
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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<icmp_header> 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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 <new>
|
||||
|
||||
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<typename Addressing>
|
||||
MulticastGroupInterface<Addressing>::MulticastGroupInterface(Filter *parent,
|
||||
const AddressType &address, net_interface *interface)
|
||||
: fParent(parent), fMulticastAddress(address), fInterface(interface)
|
||||
:
|
||||
fParent(parent),
|
||||
fMulticastAddress(address),
|
||||
fInterface(interface)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 <net_datalink.h>
|
||||
|
||||
#include <ByteOrder.h>
|
||||
@ -20,15 +21,13 @@
|
||||
#include <bluetooth/bdaddrUtils.h>
|
||||
#include <bluetooth/L2CAP/btL2CAP.h>
|
||||
|
||||
#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 '<none>').
|
||||
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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<tcp_header> bufferHeader(buffer);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -17,6 +17,7 @@ UsePrivateHeaders net shared ;
|
||||
KernelAddon stack :
|
||||
ancillary_data.cpp
|
||||
datalink.cpp
|
||||
device_interfaces.cpp
|
||||
domains.cpp
|
||||
interfaces.cpp
|
||||
net_buffer.cpp
|
||||
|
File diff suppressed because it is too large
Load Diff
797
src/add-ons/kernel/network/stack/device_interfaces.cpp
Normal file
797
src/add-ons/kernel/network/stack/device_interfaces.cpp
Normal file
@ -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 <net_device.h>
|
||||
|
||||
#include <lock.h>
|
||||
#include <util/AutoLock.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <net/if_dl.h>
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//#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;
|
||||
}
|
||||
|
84
src/add-ons/kernel/network/stack/device_interfaces.h
Normal file
84
src/add-ons/kernel/network/stack/device_interfaces.h
Normal file
@ -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 <net_datalink.h>
|
||||
#include <net_stack.h>
|
||||
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
|
||||
struct net_device_handler : DoublyLinkedListLinkImpl<net_device_handler> {
|
||||
net_receive_func func;
|
||||
int32 type;
|
||||
void* cookie;
|
||||
};
|
||||
|
||||
typedef DoublyLinkedList<net_device_handler> DeviceHandlerList;
|
||||
|
||||
typedef DoublyLinkedList<net_device_monitor,
|
||||
DoublyLinkedListCLink<net_device_monitor> > DeviceMonitorList;
|
||||
|
||||
struct net_device_interface : DoublyLinkedListLinkImpl<net_device_interface> {
|
||||
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<net_device_interface> 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
|
@ -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;
|
||||
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 <net_datalink.h>
|
||||
#include <net_stack.h>
|
||||
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
|
||||
struct net_device_handler : DoublyLinkedListLinkImpl<net_device_handler> {
|
||||
net_receive_func func;
|
||||
int32 type;
|
||||
void* cookie;
|
||||
struct net_device_interface;
|
||||
|
||||
|
||||
struct InterfaceAddress : DoublyLinkedListLinkImpl<InterfaceAddress>,
|
||||
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<net_device_handler> DeviceHandlerList;
|
||||
typedef DoublyLinkedList<InterfaceAddress> AddressList;
|
||||
|
||||
typedef DoublyLinkedList<net_device_monitor,
|
||||
DoublyLinkedListCLink<net_device_monitor> > DeviceMonitorList;
|
||||
struct domain_datalink {
|
||||
domain_datalink* hash_link;
|
||||
net_domain* domain;
|
||||
|
||||
struct net_device_interface : DoublyLinkedListLinkImpl<net_device_interface> {
|
||||
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<net_device_interface> 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<DatalinkHashDefinition, true, true> DatalinkTable;
|
||||
|
||||
|
||||
class Interface : public DoublyLinkedListLinkImpl<Interface>,
|
||||
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<Interface> 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
|
||||
|
@ -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"
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <sys/uio.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -31,7 +31,7 @@ typedef DoublyLinkedList<net_route_info,
|
||||
uint32 route_table_size(struct net_domain_private* domain);
|
||||
status_t list_routes(struct net_domain_private* domain, void* buffer,
|
||||
size_t size);
|
||||
status_t control_routes(struct net_interface* interface,
|
||||
status_t control_routes(struct net_interface* interface, net_domain* domain,
|
||||
int32 option, void* argument, size_t length);
|
||||
|
||||
status_t add_route(struct net_domain* domain,
|
||||
|
@ -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:
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
#include "ancillary_data.h"
|
||||
#include "device_interfaces.h"
|
||||
#include "domains.h"
|
||||
#include "interfaces.h"
|
||||
#include "link.h"
|
||||
@ -501,9 +502,9 @@ put_domain_protocols(net_socket* socket)
|
||||
|
||||
|
||||
static void
|
||||
uninit_domain_datalink_protocols(net_interface* interface)
|
||||
uninit_domain_datalink_protocols(domain_datalink* datalink)
|
||||
{
|
||||
net_datalink_protocol* protocol = interface->first_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();
|
||||
|
@ -18,6 +18,14 @@
|
||||
#include <net_stack_interface.h>
|
||||
|
||||
|
||||
// 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);
|
||||
|
@ -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 <hugosantos@gmail.com>
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/sockio.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <Drivers.h>
|
||||
#include <tty.h>
|
||||
#include <scsi.h>
|
||||
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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(),
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user