X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fnetutils.c;h=9ad5cf63448b8fcfc286a76a30e710c6247d58e8;hb=74e8f4f6ac00d56ac3cbc2412fb19fe489ac5218;hp=19e70b7a5adc7db754f6207ceb7fb49dad34602a;hpb=4c1e42491706df9ceede5d7f63b33b4d4b65f427;p=vlc diff --git a/src/misc/netutils.c b/src/misc/netutils.c index 19e70b7a5a..9ad5cf6344 100644 --- a/src/misc/netutils.c +++ b/src/misc/netutils.c @@ -1,290 +1,518 @@ -/******************************************************************************* +/***************************************************************************** * netutils.c: various network functions - * (c)1999 VideoLAN - ******************************************************************************* - * ?? - ******************************************************************************* - * Required headers: - * - *******************************************************************************/ - -/******************************************************************************* + ***************************************************************************** + * Copyright (C) 1999-2001 VideoLAN + * $Id: netutils.c,v 1.74 2002/10/05 19:26:23 jlj Exp $ + * + * Authors: Vincent Seguin + * Benoit Steiner + * Henri Fallon + * Xavier Marchesini + * Christophe Massiot + * Samuel Hocevar + * Jon Lech Johansen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** * Preamble - *******************************************************************************/ -#include -#include + *****************************************************************************/ +#include /* free(), realloc(), atoi() */ +#include /* errno() */ +#include /* memset() */ + +#include + +#ifdef HAVE_UNISTD_H +# include /* gethostname() */ +#elif defined( _MSC_VER ) && defined( _WIN32 ) +# include +#endif + +#if !defined( _MSC_VER ) +#include /* gettimeofday */ +#endif + +#ifdef WIN32 +# include +#else +# include /* hostent ... */ +# include /* BSD: struct sockaddr */ +# include /* BSD: struct in_addr */ +# ifdef HAVE_ARPA_INET_H +# include /* inet_ntoa(), inet_aton() */ +# endif +#endif + +#ifdef SYS_LINUX +#include /* ioctl() */ +#endif + +#ifdef SYS_DARWIN +#include +#include +#include +#endif + +#if defined( WIN32 ) /* tools to get the MAC adress from */ +#include /* the interface under Windows */ #include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "common.h" -#include "mtime.h" - -#include "intf_msg.h" -#include "debug.h" +#include +#endif + +#ifdef HAVE_NET_IF_H +#include /* interface (arch-dependent) */ +#endif + +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif #include "netutils.h" +#include "vlc_playlist.h" -/******************************************************************************* - * BuildInetAddr: build an Internet address descriptor - ******************************************************************************* - * Build an internet socket descriptor from a host name, or an ip, and a port. - * If the address is NULL, then INADDR_ANY will be used, allowing to receive - * on any address for a local socket. Usually, in this case, 'port' is also null - * and the function always succeeds. - *******************************************************************************/ -int BuildInetAddr( struct sockaddr_in *p_sa_in, char *psz_in_addr, int i_port ) -{ - struct hostent *p_hostent; /* host descriptor */ - - bzero( p_sa_in, sizeof( struct sockaddr_in ) ); - p_sa_in->sin_family = AF_INET; /* family */ - p_sa_in->sin_port = htons( i_port ); /* port */ - - /* Use INADDR_ANY if psz_in_addr is NULL */ - if( psz_in_addr == NULL ) - { - p_sa_in->sin_addr.s_addr = htonl(INADDR_ANY); - } - /* Try to convert address directly from in_addr - this will work if - * psz_in_addr is dotted decimal. */ - else if( !inet_aton( psz_in_addr, &p_sa_in->sin_addr) ) - { - /* The convertion failed: the address is an host name, which needs - * to be resolved */ - intf_DbgMsg("debug: resolving internet address %s...\n", psz_in_addr); - if ( (p_hostent = gethostbyname(psz_in_addr)) == NULL) - { - intf_ErrMsg("error: unknown host %s\n", psz_in_addr); - return( -1 ); - } +#include "network.h" - /* Copy the first address of the host in the socket address */ - bcopy( p_hostent->h_addr_list[0], &p_sa_in->sin_addr, p_hostent->h_length); - } - return( 0 ); -} +/***************************************************************************** + * input_channel_t: channel library data + ***************************************************************************** + * Store global channel library data. + * The part of the code concerning the channel changing process is unstable + * as it depends on the VideoLAN channel server, which isn't frozen for + * the time being. + *****************************************************************************/ +struct input_channel_t +{ + int i_channel; /* current channel number */ + mtime_t last_change; /* last change date */ +}; +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int GetMacAddress ( vlc_object_t *, int i_fd, char *psz_mac ); +#ifdef SYS_DARWIN +static int GetNetIntfCtrl ( const char *psz_interface, + io_object_t *ctrl_service ); +#elif defined( WIN32 ) +static int GetAdapterInfo ( int i_adapter, char *psz_string ); +#endif -/******************************************************************************* - * ServerPort: extract port from a "server:port" adress - ******************************************************************************* - * Returns the port number in a "server:port" address and replace the ":" by - * a NUL character, or returns -1. - *******************************************************************************/ -int ServerPort( char *psz_addr ) +/***************************************************************************** + * network_ChannelCreate: initialize global channel method data + ***************************************************************************** + * Initialize channel input method global data. This function should be called + * once before any input thread is created or any call to other + * input_Channel*() function is attempted. + *****************************************************************************/ +int __network_ChannelCreate( vlc_object_t *p_this ) { - char *psz_index; +#if !defined( SYS_LINUX ) && !defined( WIN32 ) + msg_Err( p_this, "VLAN-based channels are not supported " + "on this architecture" ); +#endif - /* Scan string for ':' */ - for( psz_index = psz_addr; *psz_index && (*psz_index != ':'); psz_index++ ) + /* Allocate structure */ + p_this->p_vlc->p_channel = malloc( sizeof( input_channel_t ) ); + if( p_this->p_vlc->p_channel == NULL ) { - ; - } - - /* If a port number has been found, convert it and return it */ - if( *psz_index == ':' ) - { - *psz_index = '\0'; - return( atoi( psz_index + 1 ) ); + msg_Err( p_this, "out of memory" ); + return( -1 ); } - return( - 1 ); + /* Initialize structure */ + p_this->p_vlc->p_channel->i_channel = 0; + p_this->p_vlc->p_channel->last_change = 0; + + msg_Dbg( p_this, "channels initialized" ); + return( 0 ); } +/***************************************************************************** + * network_ChannelJoin: join a channel + ***************************************************************************** + * This function will try to join a channel. If the relevant interface is + * already on the good channel, nothing will be done. Else, and if possible + * (if the interface is not locked), the channel server will be contacted + * and a change will be requested. The function will block until the change + * is effective. Note that once a channel is no more used, its interface + * should be unlocked using input_ChannelLeave(). + * Non 0 will be returned in case of error. + *****************************************************************************/ +int __network_ChannelJoin( vlc_object_t *p_this, int i_channel ) +{ +#define VLCS_VERSION 13 +#define MESSAGE_LENGTH 256 + + module_t * p_network; + char * psz_network = NULL; + network_socket_t socket_desc; + char psz_mess[ MESSAGE_LENGTH ]; + char psz_mac[ 40 ]; + int i_fd, i_port; + char *psz_vlcs; + struct timeval delay; + fd_set fds; -/******************************************************************************* - * ReadIfConf: Read the configuration of an interface - ******************************************************************************* - * i_sockfd must reference a socket open as follow: AF_INET, DOCK_DGRAM, 0 - *******************************************************************************/ -int ReadIfConf(int i_sockfd, if_descr_t* p_ifdescr, char* psz_name) -{ - struct ifreq ifr_config; - int i_rc = 0; - - ASSERT(p_ifdescr); - ASSERT(psz_name); - - /* Which interface are we interested in ? */ - strcpy(ifr_config.ifr_name, psz_name); - - /* Read the flags for that interface */ - i_rc = ioctl(i_sockfd, SIOCGIFFLAGS, (byte_t *)&ifr_config); - if( !i_rc ) + if( p_this->p_vlc->p_channel->i_channel == i_channel ) { - p_ifdescr->i_flags = ifr_config.ifr_flags; - intf_DbgMsg("%s flags: 0x%x\n", psz_name, p_ifdescr->i_flags); + return 0; } - else + + if( !config_GetInt( p_this, "network-channel" ) ) { - intf_ErrMsg("Cannot read flags for interface %s: %s\n", psz_name, - strerror(errno)); + msg_Err( p_this, "channels disabled, to enable them, use the" + " --channels option" ); return -1; } - /* Read physical address of the interface and store it in our description */ - i_rc = ioctl(i_sockfd, SIOCGIFHWADDR, (byte_t *)&ifr_config); - if( !i_rc ) + if( config_GetInt( p_this, "ipv4" ) ) { - memcpy(&p_ifdescr->sa_phys_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr)); - intf_DbgMsg("%s MAC address: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", psz_name, - p_ifdescr->sa_phys_addr.sa_data[0]&0xff, - p_ifdescr->sa_phys_addr.sa_data[1]&0xff, - p_ifdescr->sa_phys_addr.sa_data[2]&0xff, - p_ifdescr->sa_phys_addr.sa_data[3]&0xff, - p_ifdescr->sa_phys_addr.sa_data[4]&0xff, - p_ifdescr->sa_phys_addr.sa_data[5]&0xff); + psz_network = "ipv4"; } - else + if( config_GetInt( p_this, "ipv6" ) ) + { + psz_network = "ipv6"; + } + + /* Getting information about the channel server */ + if( !(psz_vlcs = config_GetPsz( p_this, "channel-server" )) ) { - intf_ErrMsg("Cannot read hardware address for interface %s: %s\n", - psz_name, strerror(errno)); + msg_Err( p_this, "configuration variable channel-server empty" ); return -1; } - - /* Read IP address of the interface and store it in our description */ - i_rc = ioctl(i_sockfd, SIOCGIFADDR, (byte_t *)&ifr_config); - if( !i_rc ) + + i_port = config_GetInt( p_this, "channel-port" ); + + msg_Dbg( p_this, "connecting to %s:%d", psz_vlcs, i_port ); + + /* Prepare the network_socket_t structure */ + socket_desc.i_type = NETWORK_UDP; + socket_desc.psz_bind_addr = ""; + socket_desc.i_bind_port = 4321; + socket_desc.psz_server_addr = psz_vlcs; + socket_desc.i_server_port = i_port; + + /* Find an appropriate network module */ + p_network = module_Need( p_this, "network", psz_network/*, &socket_desc*/ ); + if( p_network == NULL ) { - memcpy(&p_ifdescr->sa_net_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr)); - intf_DbgMsg("%s IP address: %s\n", psz_name, - inet_ntoa(p_ifdescr->sa_net_addr.sin_addr)); + return( -1 ); } - else + module_Unneed( p_this, p_network ); + + free( psz_vlcs ); /* Do we really need this ? -- Meuuh */ + i_fd = socket_desc.i_handle; + + /* Look for the interface MAC address */ + if( GetMacAddress( p_this, i_fd, psz_mac ) ) { - intf_ErrMsg("Cannot read network address for interface %s: %s\n", - psz_name, strerror(errno)); + msg_Err( p_this, "failed getting MAC address" ); + close( i_fd ); return -1; } - - /* Read broadcast address of the interface and store it in our description */ - if(p_ifdescr->i_flags & IFF_POINTOPOINT) + + msg_Dbg( p_this, "MAC address is %s", psz_mac ); + + /* Build the message */ + sprintf( psz_mess, "%d %u %lu %s \n", i_channel, VLCS_VERSION, + (unsigned long)(mdate() / (u64)1000000), + psz_mac ); + + /* Send the message */ + send( i_fd, psz_mess, MESSAGE_LENGTH, 0 ); + + msg_Dbg( p_this, "attempting to join channel %d", i_channel ); + + /* We have changed channels ! (or at least, we tried) */ + p_this->p_vlc->p_channel->last_change = mdate(); + p_this->p_vlc->p_channel->i_channel = i_channel; + + /* Wait 5 sec for an answer from the server */ + delay.tv_sec = 5; + delay.tv_usec = 0; + FD_ZERO( &fds ); + FD_SET( i_fd, &fds ); + + switch( select( i_fd + 1, &fds, NULL, NULL, &delay ) ) { - intf_DbgMsg("%s doen't not support broadcast\n", psz_name); - i_rc = ioctl(i_sockfd, SIOCGIFDSTADDR, (byte_t *)&ifr_config); + case 0: + msg_Err( p_this, "no answer from vlcs" ); + close( i_fd ); + return -1; + + case -1: + msg_Err( p_this, "error while listening to vlcs" ); + close( i_fd ); + return -1; } - else + + recv( i_fd, psz_mess, MESSAGE_LENGTH, 0 ); + psz_mess[ MESSAGE_LENGTH - 1 ] = '\0'; + + if( !strncasecmp( psz_mess, "E:", 2 ) ) { - intf_DbgMsg("%s supports broadcast\n", psz_name); - i_rc = ioctl(i_sockfd, SIOCGIFBRDADDR, (byte_t *)&ifr_config); + msg_Err( p_this, "vlcs said '%s'", psz_mess + 2 ); + close( i_fd ); + return -1; } - if( !i_rc ) + else if( !strncasecmp( psz_mess, "I:", 2 ) ) { - memcpy(&p_ifdescr->sa_bcast_addr, &ifr_config.ifr_addr, sizeof(struct sockaddr)); - intf_DbgMsg("%s broadcast address: %s\n", psz_name, - inet_ntoa(p_ifdescr->sa_bcast_addr.sin_addr)); + msg_Dbg( p_this, "vlcs said '%s'", psz_mess + 2 ); } else { - intf_ErrMsg("Cannot read broadcast address for interface %s: %s\n", - psz_name, strerror(errno)); - return -1; + /* We got something to play ! */ + playlist_t *p_playlist; + p_playlist = vlc_object_find( p_this, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( p_playlist != NULL ) + { + playlist_Add( p_playlist, psz_mess, + PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END ); + vlc_object_release( p_playlist ); + } } - - return i_rc; -} + /* Close the socket and return nicely */ +#ifndef WIN32 + close( i_fd ); +#else + closesocket( i_fd ); +#endif + + return 0; +} +/* Following functions are local */ -/******************************************************************************* - * ReadNetConf: Retrieve the network configuration of the host - ******************************************************************************* - * Only IP interfaces are listed, and only if they are up - * i_sockfd must reference a socket open as follow: AF_INET, DOCK_DGRAM, 0 - *******************************************************************************/ -int ReadNetConf(int i_sockfd, net_descr_t* p_net_descr) +/***************************************************************************** + * GetMacAddress: extract the MAC Address + *****************************************************************************/ +static int GetMacAddress( vlc_object_t *p_this, int i_fd, char *psz_mac ) { - struct ifreq* a_ifr_ifconf = NULL; - struct ifreq* p_ifr_current_if; - struct ifconf ifc_netconf; - - int i_if_number; - int i_remaining; - int i_rc = 0; - - ASSERT(p_net_descr); - - /* Start by assuming we have few than 3 interfaces (i_if_number will - be incremented by 1 when entering the loop) */ - i_if_number = 2; - - /* Retrieve network configuration for that host */ - do +#if defined( SYS_LINUX ) + struct ifreq interface; + int i_ret; + char *psz_interface; + + /* + * Looking for information about the eth0 interface + */ + interface.ifr_addr.sa_family = AF_INET; + if( !(psz_interface = config_GetPsz( p_this, "iface" )) ) { - i_if_number++; - a_ifr_ifconf = realloc(a_ifr_ifconf, i_if_number*sizeof(struct ifreq)); - ifc_netconf.ifc_len = i_if_number*sizeof(struct ifreq); - ifc_netconf.ifc_req = a_ifr_ifconf; + msg_Err( p_this, "configuration variable iface empty" ); + return -1; + } + strcpy( interface.ifr_name, psz_interface ); + free( psz_interface ); - i_rc = ioctl(i_sockfd, SIOCGIFCONF, (byte_t*)&ifc_netconf); - if( i_rc ) - { - intf_ErrMsg("Cannot read network configuration: %s\n", - strerror(errno)); - break; - } + i_ret = ioctl( i_fd, SIOCGIFHWADDR, &interface ); + + if( i_ret ) + { + msg_Err( p_this, "ioctl SIOCGIFHWADDR failed" ); + return( i_ret ); } - /* If we detected ifc_len interfaces, this may mean that others have - been missed because the a_ifr_ifconf was to little, so increase - it's size and retry */ - while( ifc_netconf.ifc_len >= i_if_number*sizeof(struct ifreq) ); - /* No see what we detected */ - if( !i_rc ) + sprintf( psz_mac, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", + interface.ifr_hwaddr.sa_data[0] & 0xff, + interface.ifr_hwaddr.sa_data[1] & 0xff, + interface.ifr_hwaddr.sa_data[2] & 0xff, + interface.ifr_hwaddr.sa_data[3] & 0xff, + interface.ifr_hwaddr.sa_data[4] & 0xff, + interface.ifr_hwaddr.sa_data[5] & 0xff ); + + return( 0 ); + +#elif defined( SYS_DARWIN ) + char *psz_interface; + io_object_t ctrl_service; + CFTypeRef cfd_mac_address; + UInt8 ui_mac_address[kIOEthernetAddressSize]; + + if( !(psz_interface = config_GetPsz( p_this, "iface" )) ) + { + msg_Err( p_this, "configuration variable iface empty" ); + return( -1 ); + } + + if( GetNetIntfCtrl( psz_interface, &ctrl_service ) ) { - /* Init the given net_descr_t struct */ - p_net_descr->i_if_number = 0; - p_net_descr->a_if = NULL; - - /* Iterate through the entries of the a_ifr_ifconf table */ - p_ifr_current_if = ifc_netconf.ifc_req; - for( i_remaining = ifc_netconf.ifc_len / sizeof (struct ifreq); - i_remaining-- > 0; p_ifr_current_if++ ) + msg_Err( p_this, "GetNetIntfCtrl failed" ); + return( -1 ); + } + + cfd_mac_address = IORegistryEntryCreateCFProperty( ctrl_service, + CFSTR(kIOMACAddress), + kCFAllocatorDefault, + 0 ); + IOObjectRelease( ctrl_service ); + if( cfd_mac_address == NULL ) + { + msg_Err( p_this, "IORegistryEntryCreateCFProperty failed" ); + return( -1 ); + } + + CFDataGetBytes( cfd_mac_address, + CFRangeMake(0, kIOEthernetAddressSize), + ui_mac_address ); + CFRelease( cfd_mac_address ); + + sprintf( psz_mac, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", + ui_mac_address[0], ui_mac_address[1], + ui_mac_address[2], ui_mac_address[3], + ui_mac_address[4], ui_mac_address[5] ); + + return( 0 ); + +#elif defined( WIN32 ) + int i, i_ret = -1; + + /* Get adapter list - support for more than one adapter */ + LANA_ENUM AdapterList; + NCB Ncb; + + msg_Dbg( p_this, "looking for MAC address" ); + + memset( &Ncb, 0, sizeof( NCB ) ); + Ncb.ncb_command = NCBENUM; + Ncb.ncb_buffer = (unsigned char *)&AdapterList; + Ncb.ncb_length = sizeof( AdapterList ); + Netbios( &Ncb ); + + /* Get all of the local ethernet addresses */ + for ( i = 0; i < AdapterList.length ; ++i ) + { + if ( GetAdapterInfo ( AdapterList.lana[ i ], psz_mac ) == 0 ) { - intf_DbgMsg("Found interface %s\n", p_ifr_current_if->ifr_name); - - /* Don't use an interface devoted to an address family other than IP */ - if(p_ifr_current_if->ifr_addr.sa_family != AF_INET) - continue; - - /* Read the status of this interface */ - if( ioctl(i_sockfd, SIOCGIFFLAGS, (byte_t *)p_ifr_current_if) < 0 ) - { - intf_ErrMsg("Cannot access interface %s: %s\n", - p_ifr_current_if->ifr_name, strerror(errno)); - i_rc = -1; - break; - } - else - { - /* Skip this interface if it is not up or if this is a loopback one */ - if( !p_ifr_current_if->ifr_flags & IFF_UP || - p_ifr_current_if->ifr_flags & IFF_LOOPBACK ) - continue; - - /* Add an entry to the net_descr struct to store the description of - that interface */ - p_net_descr->i_if_number++; - p_net_descr->a_if = realloc(p_net_descr->a_if, - p_net_descr->i_if_number*sizeof(if_descr_t)); - /* Read the info ??? */ - i_rc = ReadIfConf(i_sockfd, &p_net_descr->a_if[p_net_descr->i_if_number-1], - p_ifr_current_if->ifr_name); - } + i_ret = 0; } } - - /* Don't need the a_ifr_ifconf anymore */ - free( a_ifr_ifconf ); - return i_rc; + + return( i_ret ); + +#else + strcpy( psz_mac, "00:00:00:00:00:00" ); + return( 0 ); + +#endif +} + +#ifdef SYS_DARWIN +/***************************************************************************** + * GetNetIntfCtrl : get parent controller for network interface + *****************************************************************************/ +static int GetNetIntfCtrl( const char *psz_interface, + io_object_t *ctrl_service ) +{ + mach_port_t port; + kern_return_t ret; + io_object_t intf_service; + io_iterator_t intf_iterator; + + /* get port for IOKit communication */ + if( ( ret = IOMasterPort( MACH_PORT_NULL, &port ) ) != KERN_SUCCESS ) + { + return( -1 ); + } + + /* look up the IOService object for the interface */ + ret = IOServiceGetMatchingServices( port, IOBSDNameMatching( port, 0, + psz_interface ), &intf_iterator ); + if( ret != KERN_SUCCESS ) + { + return( -1 ); + } + + intf_service = IOIteratorNext( intf_iterator ); + if( intf_service == NULL ) + { + return( -1 ); + } + + ret = IORegistryEntryGetParentEntry( intf_service, + kIOServicePlane, + ctrl_service ); + IOObjectRelease( intf_service ); + if( ret != KERN_SUCCESS ) + { + return( -1 ); + } + + return( 0 ); } +#elif defined( WIN32 ) +/***************************************************************************** + * GetAdapterInfo : gets some informations about the interface using NETBIOS + *****************************************************************************/ +static int GetAdapterInfo( int i_adapter, char *psz_string ) +{ + struct ASTAT + { + ADAPTER_STATUS adapt; + NAME_BUFFER psz_name[30]; + } Adapter; + + /* Reset the LAN adapter so that we can begin querying it */ + NCB Ncb; + memset( &Ncb, 0, sizeof ( Ncb ) ); + Ncb.ncb_command = NCBRESET; + Ncb.ncb_lana_num = i_adapter; + + if( Netbios( &Ncb ) != NRC_GOODRET ) + { +//X intf_ErrMsg( "network error: reset returned %i", Ncb.ncb_retcode ); + return -1; + } + + /* Prepare to get the adapter status block */ + memset( &Ncb, 0, sizeof( Ncb ) ) ; /* Initialization */ + Ncb.ncb_command = NCBASTAT; + Ncb.ncb_lana_num = i_adapter; + + strcpy( (char *)Ncb.ncb_callname, "*" ); + + memset( &Adapter, 0, sizeof ( Adapter ) ); + Ncb.ncb_buffer = ( unsigned char * ) &Adapter; + Ncb.ncb_length = sizeof ( Adapter ); + + /* Get the adapter's info and, if this works, return it in standard, + * colon-delimited form. */ + if ( Netbios( &Ncb ) == 0 ) + { + sprintf ( psz_string, "%02X:%02X:%02X:%02X:%02X:%02X", + (int) ( Adapter.adapt.adapter_address[0] ), + (int) ( Adapter.adapt.adapter_address[1] ), + (int) ( Adapter.adapt.adapter_address[2] ), + (int) ( Adapter.adapt.adapter_address[3] ), + (int) ( Adapter.adapt.adapter_address[4] ), + (int) ( Adapter.adapt.adapter_address[5] ) ); + +//X intf_WarnMsg( 2, "network: found MAC address %s", psz_string ); + + return 0; + } + else + { +//X intf_ErrMsg( "network error: ASTAT returned %i", Ncb.ncb_retcode ); + return -1; + } +} +#endif /* WIN32 */