#include "includes.h"
extern pstring global_myname;
extern uint16 samba_nb_type;
void insert_permanent_name_into_unicast( struct subnet_record *subrec,
struct nmb_name *nmbname, uint16 nb_type )
{
struct name_record *namerec;
if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL)
{
(void)add_name_to_subnet( unicast_subnet, nmbname->name,
nmbname->name_type, nb_type,
PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
}
else
{
add_ip_to_name_record( namerec, subrec->myip);
}
}
static void remove_permanent_name_from_unicast( struct subnet_record *subrec,
struct nmb_name *nmbname )
{
struct name_record *namerec;
if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) != NULL)
{
remove_ip_from_name_record( namerec, subrec->myip);
if(namerec->data.num_ips == 0)
remove_name_from_namelist( unicast_subnet, namerec);
}
}
static void reset_workgroup_state( struct subnet_record *subrec, char *workgroup_name,
BOOL force_new_election )
{
struct work_record *work;
struct server_record *servrec;
struct nmb_name nmbname;
if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL)
{
DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
subnet %s.\n", workgroup_name, subrec->subnet_name ));
return;
}
if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
{
DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
in workgroup %s on subnet %s\n",
global_myname, work->work_group, subrec->subnet_name));
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
return;
}
servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
subrec->work_changed = True;
work->ElectionCriterion &= ~0x4;
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
set_workgroup_local_master_browser_name( work, "");
make_nmb_name(&nmbname, work->work_group, 0x1d);
remove_permanent_name_from_unicast( subrec, &nmbname);
if(force_new_election)
work->needelection = True;
}
static void unbecome_local_master_success(struct subnet_record *subrec,
struct userdata_struct *userdata,
struct nmb_name *released_name,
struct in_addr released_ip)
{
BOOL force_new_election = False;
memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
DEBUG(3,("unbecome_local_master_success: released name %s.\n",
nmb_namestr(released_name)));
reset_workgroup_state( subrec, released_name->name, force_new_election );
if( DEBUGLVL( 0 ) )
{
dbgtext( "*****\n\n" );
dbgtext( "Samba name server %s ", global_myname );
dbgtext( "has stopped being a local master browser " );
dbgtext( "for workgroup %s ", released_name->name );
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
}
}
static void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec,
struct nmb_name *fail_name)
{
struct name_record *namerec;
struct userdata_struct *userdata = rrec->userdata;
BOOL force_new_election = False;
memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
DEBUG(0,("unbecome_local_master_fail: failed to release name %s. \
Removing from namelist anyway.\n", nmb_namestr(fail_name)));
namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
if(namerec)
remove_name_from_namelist(subrec, namerec);
reset_workgroup_state( subrec, fail_name->name, force_new_election );
if( DEBUGLVL( 0 ) )
{
dbgtext( "*****\n\n" );
dbgtext( "Samba name server %s ", global_myname );
dbgtext( "has stopped being a local master browser " );
dbgtext( "for workgroup %s ", fail_name->name );
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
}
}
static void release_1d_name( struct subnet_record *subrec, char *workgroup_name,
BOOL force_new_election)
{
struct nmb_name nmbname;
struct name_record *namerec;
make_nmb_name(&nmbname, workgroup_name, 0x1d);
if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
{
struct userdata_struct *userdata;
int size = sizeof(struct userdata_struct) + sizeof(BOOL);
if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
{
DEBUG(0,("release_1d_name: malloc fail.\n"));
return;
}
userdata->copy_fn = NULL;
userdata->free_fn = NULL;
userdata->userdata_len = sizeof(BOOL);
memcpy((char *)userdata->data, &force_new_election, sizeof(BOOL));
release_name(subrec, namerec,
unbecome_local_master_success,
unbecome_local_master_fail,
userdata);
zero_free(userdata, size);
}
}
static void release_msbrowse_name_success(struct subnet_record *subrec,
struct userdata_struct *userdata,
struct nmb_name *released_name,
struct in_addr released_ip)
{
DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
nmb_namestr(released_name), subrec->subnet_name ));
remove_permanent_name_from_unicast( subrec, released_name);
}
static void release_msbrowse_name_fail( struct subnet_record *subrec,
struct response_record *rrec,
struct nmb_name *fail_name)
{
struct name_record *namerec;
DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
nmb_namestr(fail_name), subrec->subnet_name ));
namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
if(namerec)
remove_name_from_namelist(subrec, namerec);
remove_permanent_name_from_unicast( subrec, fail_name);
}
void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work,
BOOL force_new_election)
{
struct name_record *namerec;
struct nmb_name nmbname;
DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \
on subnet %s\n",work->work_group, subrec->subnet_name));
if(find_server_in_workgroup( work, global_myname) == NULL)
{
DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
in workgroup %s on subnet %s\n",
global_myname, work->work_group, subrec->subnet_name));
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
return;
}
work->mst_state = MST_UNBECOMING_MASTER;
release_1d_name( subrec, work->work_group, force_new_election);
make_nmb_name(&nmbname, MSBROWSE, 0x1);
if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
{
release_name(subrec, namerec,
release_msbrowse_name_success,
release_msbrowse_name_fail,
NULL);
}
retransmit_or_expire_response_records(time(NULL));
}
static void become_local_master_stage2(struct subnet_record *subrec,
struct userdata_struct *userdata,
struct nmb_name *registered_name,
uint16 nb_flags,
int ttl, struct in_addr registered_ip)
{
int i = 0;
struct server_record *sl;
struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
struct server_record *servrec;
if(!work)
{
DEBUG(0,("become_local_master_stage2: Error - cannot find \
workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
return;
}
if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
{
DEBUG(0,("become_local_master_stage2: Error - cannot find server %s \
in workgroup %s on subnet %s\n",
global_myname, registered_name->name, subrec->subnet_name));
work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
return;
}
DEBUG(3,("become_local_master_stage2: registered as master browser for workgroup %s \
on subnet %s\n", work->work_group, subrec->subnet_name));
work->mst_state = MST_BROWSER;
servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
subrec->work_changed = True;
set_workgroup_local_master_browser_name( work, global_myname);
for( sl = work->serverlist; sl != NULL; sl = sl->next)
i++;
if (i < 10)
{
broadcast_announce_request(subrec, work);
}
insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
reset_announce_timer();
if( DEBUGLVL( 0 ) )
{
dbgtext( "*****\n\n" );
dbgtext( "Samba name server %s ", global_myname );
dbgtext( "is now a local master browser " );
dbgtext( "for workgroup %s ", work->work_group );
dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
}
}
static void become_local_master_fail2(struct subnet_record *subrec,
struct response_record *rrec,
struct nmb_name *fail_name)
{
struct work_record *work = find_workgroup_on_subnet( subrec, fail_name->name);
DEBUG(0,("become_local_master_fail2: failed to register name %s on subnet %s. \
Failed to become a local master browser.\n", nmb_namestr(fail_name), subrec->subnet_name));
if(!work)
{
DEBUG(0,("become_local_master_fail2: Error - cannot find \
workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
return;
}
unbecome_local_master_browser(subrec, work, False);
}
static void become_local_master_stage1(struct subnet_record *subrec,
struct userdata_struct *userdata,
struct nmb_name *registered_name,
uint16 nb_flags,
int ttl, struct in_addr registered_ip)
{
char *work_name = userdata->data;
struct work_record *work = find_workgroup_on_subnet( subrec, work_name);
if(!work)
{
DEBUG(0,("become_local_master_stage1: Error - cannot find \
workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
return;
}
DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n",
work->work_group));
work->mst_state = MST_MSB;
insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
register_name(subrec, work->work_group,0x1d,samba_nb_type,
become_local_master_stage2,
become_local_master_fail2,
NULL);
}
static void become_local_master_fail1(struct subnet_record *subrec,
struct response_record *rrec,
struct nmb_name *fail_name)
{
char *work_name = rrec->userdata->data;
struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
if(!work)
{
DEBUG(0,("become_local_master_fail1: Error - cannot find \
workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
return;
}
if(find_server_in_workgroup(work, global_myname) == NULL)
{
DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
in workgroup %s on subnet %s\n",
global_myname, work->work_group, subrec->subnet_name));
return;
}
reset_workgroup_state( subrec, work->work_group, False );
DEBUG(0,("become_local_master_fail1: Failed to become a local master browser for \
workgroup %s on subnet %s. Couldn't register name %s.\n",
work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
}
void become_local_master_browser(struct subnet_record *subrec, struct work_record *work)
{
struct userdata_struct *userdata;
int size = sizeof(struct userdata_struct) + sizeof(fstring) + 1;
if (!lp_local_master())
{
DEBUG(0,("become_local_master_browser: Samba not configured as a local master browser.\n"));
return;
}
if(!AM_POTENTIAL_MASTER_BROWSER(work))
{
DEBUG(2,("become_local_master_browser: Awaiting potential browser state. Current state is %d\n",
work->mst_state ));
return;
}
if(find_server_in_workgroup( work, global_myname) == NULL)
{
DEBUG(0,("become_local_master_browser: Error - cannot find server %s \
in workgroup %s on subnet %s\n",
global_myname, work->work_group, subrec->subnet_name));
return;
}
DEBUG(2,("become_local_master_browser: Starting to become a master browser for workgroup \
%s on subnet %s\n", work->work_group, subrec->subnet_name));
DEBUG(3,("become_local_master_browser: first stage - attempt to register ^1^2__MSBROWSE__^2^1\n"));
work->mst_state = MST_BACKUP;
work->ElectionCriterion |= 0x5;
subrec->work_changed = True;
if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
{
DEBUG(0,("become_local_master_browser: malloc fail.\n"));
return;
}
userdata->copy_fn = NULL;
userdata->free_fn = NULL;
userdata->userdata_len = strlen(work->work_group)+1;
pstrcpy(userdata->data, work->work_group);
register_name(subrec, MSBROWSE, 0x01, samba_nb_type|NB_GROUP,
become_local_master_stage1,
become_local_master_fail1,
userdata);
zero_free(userdata, size);
}
void set_workgroup_local_master_browser_name( struct work_record *work, char *newname)
{
DEBUG(5,("set_workgroup_local_master_browser_name: setting local master name to '%s' \
for workgroup %s.\n", newname, work->work_group ));
#if 0
if(strequal( work->work_group, newname))
{
DEBUG(5, ("set_workgroup_local_master_browser_name: Refusing to set \
local_master_browser_name for workgroup %s to workgroup name.\n",
work->work_group ));
return;
}
#endif
StrnCpy(work->local_master_browser_name, newname,
sizeof(work->local_master_browser_name)-1);
}