summaryrefslogtreecommitdiff
path: root/source3/nmbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/nmbd')
-rw-r--r--source3/nmbd/nmbd_become_lmb.c83
-rw-r--r--source3/nmbd/nmbd_elections.c43
-rw-r--r--source3/nmbd/nmbd_incomingdgrams.c9
-rw-r--r--source3/nmbd/nmbd_namelistdb.c2
-rw-r--r--source3/nmbd/nmbd_packets.c11
-rw-r--r--source3/nmbd/nmbd_subnetdb.c17
-rw-r--r--source3/nmbd/nmbd_workgroupdb.c2
7 files changed, 122 insertions, 45 deletions
diff --git a/source3/nmbd/nmbd_become_lmb.c b/source3/nmbd/nmbd_become_lmb.c
index 7329de6f69..f66723eb17 100644
--- a/source3/nmbd/nmbd_become_lmb.c
+++ b/source3/nmbd/nmbd_become_lmb.c
@@ -78,7 +78,8 @@ static void remove_permanent_name_from_unicast( struct subnet_record *subrec,
state back to potential browser, or none.
******************************************************************/
-static void reset_workgroup_state( struct subnet_record *subrec, char *workgroup_name )
+static void reset_workgroup_state( struct subnet_record *subrec, char *workgroup_name,
+ BOOL force_new_election )
{
struct work_record *work;
struct server_record *servrec;
@@ -129,6 +130,8 @@ in workgroup %s on subnet %s\n",
remove_permanent_name_from_unicast( subrec, &nmbname);
+ if(force_new_election)
+ work->needelection = True;
}
/*******************************************************************
@@ -140,11 +143,15 @@ void unbecome_local_master_success(struct subnet_record *subrec,
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",
namestr(released_name)));
/* Now reset the workgroup and server state. */
- reset_workgroup_state( subrec, released_name->name );
+ reset_workgroup_state( subrec, released_name->name, force_new_election );
DEBUG(0,("\n%s ***** Samba name server %s has stopped being a local master browser for workgroup %s \
on subnet %s *****\n\n", timestring(), global_myname, released_name->name, subrec->subnet_name));
@@ -159,6 +166,10 @@ void unbecome_local_master_fail(struct subnet_record *subrec, struct response_re
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", namestr(fail_name)));
@@ -169,19 +180,18 @@ Removing from namelist anyway.\n", namestr(fail_name)));
remove_name_from_namelist(subrec, namerec);
/* Now reset the workgroup and server state. */
- reset_workgroup_state( subrec, fail_name->name );
+ reset_workgroup_state( subrec, fail_name->name, force_new_election );
DEBUG(0,("\n%s ***** Samba name server %s has stopped being a local master browser for workgroup %s \
on subnet %s *****\n\n", timestring(), global_myname, fail_name->name, subrec->subnet_name));
-
}
/*******************************************************************
- Utility function to remove the WORKGROUP<1d> name called by both
- success and fail of releasing the MSBROWSE name.
+ Utility function to remove the WORKGROUP<1d> name.
******************************************************************/
-void release_1d_name( struct subnet_record *subrec, char *workgroup_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;
@@ -189,10 +199,26 @@ void release_1d_name( struct subnet_record *subrec, char *workgroup_name)
make_nmb_name(&nmbname, workgroup_name, 0x1d, scope);
if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
{
+ struct userdata_struct *userdata;
+
+ if((userdata = (struct userdata_struct *)malloc(
+ sizeof(struct userdata_struct) + sizeof(BOOL))) == 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,
- NULL);
+ userdata);
+
+ free((char *)userdata);
}
}
@@ -210,8 +236,6 @@ static void release_msbrowse_name_success(struct subnet_record *subrec,
/* Remove the permanent MSBROWSE name added into the unicast subnet. */
remove_permanent_name_from_unicast( subrec, released_name);
-
- release_1d_name( subrec, userdata->data );
}
/*******************************************************************
@@ -222,7 +246,6 @@ static void release_msbrowse_name_fail( struct subnet_record *subrec,
struct response_record *rrec,
struct nmb_name *fail_name)
{
- struct userdata_struct *userdata = rrec->userdata;
struct name_record *namerec;
DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
@@ -235,20 +258,19 @@ static void release_msbrowse_name_fail( struct subnet_record *subrec,
/* Remove the permanent MSBROWSE name added into the unicast subnet. */
remove_permanent_name_from_unicast( subrec, fail_name);
-
- release_1d_name( subrec, userdata->data );
}
/*******************************************************************
- Unbecome the local master browser.
+ Unbecome the local master browser. If force_new_election is true, restart
+ the election process after we've unbecome the local master.
******************************************************************/
-void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work)
+void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work,
+ BOOL force_new_election)
{
struct server_record *servrec;
struct name_record *namerec;
struct nmb_name nmbname;
- struct userdata_struct *userdata;
/* Sanity check. */
@@ -267,17 +289,12 @@ in workgroup %s on subnet %s\n",
/* Set the state to unbecoming. */
work->mst_state = MST_UNBECOMING_MASTER;
- /* Setup the userdata for the MSBROWSE name release. */
- if((userdata = (struct userdata_struct *)malloc( sizeof(struct userdata_struct) + sizeof(fstring)+1)) == NULL)
- {
- DEBUG(0,("unbecome_local_master_browser: malloc fail.\n"));
- return;
- }
+ /*
+ * Release the WORKGROUP<1d> name asap to allow another machine to
+ * claim it.
+ */
- userdata->copy_fn = NULL;
- userdata->free_fn = NULL;
- userdata->userdata_len = strlen(work->work_group)+1;
- pstrcpy(userdata->data, work->work_group);
+ release_1d_name( subrec, work->work_group, force_new_election);
/* Deregister any browser names we may have. */
make_nmb_name(&nmbname, MSBROWSE, 0x1, scope);
@@ -286,10 +303,16 @@ in workgroup %s on subnet %s\n",
release_name(subrec, namerec,
release_msbrowse_name_success,
release_msbrowse_name_fail,
- userdata);
+ NULL);
}
- free((char *)userdata);
+ /*
+ * Ensure we have sent and processed these release packets
+ * before returning - we don't want to process any election
+ * packets before dealing with the 1d release.
+ */
+
+ retransmit_or_expire_response_records(time(NULL));
}
/****************************************************************************
@@ -394,7 +417,7 @@ workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
}
/* Roll back all the way by calling unbecome_local_master_browser(). */
- unbecome_local_master_browser(subrec, work);
+ unbecome_local_master_browser(subrec, work, False);
}
/****************************************************************************
@@ -465,7 +488,7 @@ in workgroup %s on subnet %s\n",
return;
}
- reset_workgroup_state( subrec, work->work_group );
+ 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",
diff --git a/source3/nmbd/nmbd_elections.c b/source3/nmbd/nmbd_elections.c
index 569b653129..4be5b73508 100644
--- a/source3/nmbd/nmbd_elections.c
+++ b/source3/nmbd/nmbd_elections.c
@@ -26,6 +26,8 @@
extern int DEBUGLEVEL;
+extern pstring scope;
+
extern pstring global_myname;
extern fstring global_myworkgroup;
@@ -58,7 +60,7 @@ static void send_election_dgram(struct subnet_record *subrec, char *workgroup_na
p = skip_string(p,1);
send_mailslot(False, BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
- server_name, 0,
+ global_myname, 0,
workgroup_name, 0x1e,
subrec->bcast_ip, subrec->myip);
}
@@ -117,7 +119,7 @@ static void check_for_master_browser_fail( struct subnet_record *subrec,
not to become the local master, but we still need one,
having detected that one doesn't exist.
*/
- send_election_dgram(subrec, work->work_group, 0, 0, global_myname);
+ send_election_dgram(subrec, work->work_group, 0, 0, "");
}
}
}
@@ -171,8 +173,8 @@ void run_elections(time_t t)
struct subnet_record *subrec;
- /* Send election packets once a second - note */
- if (lastime && (t - lastime <= 0))
+ /* Send election packets once every 2 seconds - note */
+ if (lastime && (t - lastime < 2))
return;
lastime = t;
@@ -185,6 +187,20 @@ void run_elections(time_t t)
{
if (work->RunningElection)
{
+ /*
+ * We can only run an election for a workgroup if we have
+ * registered the WORKGROUP<1e> name, as that's the name
+ * we must listen to.
+ */
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, work->work_group, 0x1e, scope);
+ if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
+ DEBUG(8,("run_elections: Cannot send election packet yet as name %s not \
+yet registered on subnet %s\n", namestr(&nmbname), subrec->subnet_name ));
+ continue;
+ }
+
send_election_dgram(subrec, work->work_group, work->ElectionCriterion,
t - StartupTime, global_myname);
@@ -308,7 +324,7 @@ is not my workgroup.\n", work->work_group, subrec->subnet_name ));
DEBUG(3,("process_election: >>> Lost election for workgroup %s on subnet %s <<<\n",
work->work_group, subrec->subnet_name ));
if (AM_LOCAL_MASTER_BROWSER(work))
- unbecome_local_master_browser(subrec, work);
+ unbecome_local_master_browser(subrec, work, False);
}
}
}
@@ -335,12 +351,29 @@ BOOL check_elections(void)
/* Only start an election if we are in the potential browser state. */
if (work->needelection && !work->RunningElection && AM_POTENTIAL_MASTER_BROWSER(work))
{
+ /*
+ * We can only run an election for a workgroup if we have
+ * registered the WORKGROUP<1e> name, as that's the name
+ * we must listen to.
+ */
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, work->work_group, 0x1e, scope);
+ if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
+ DEBUG(8,("check_elections: Cannot send election packet yet as name %s not \
+yet registered on subnet %s\n", namestr(&nmbname), subrec->subnet_name ));
+ continue;
+ }
+
DEBUG(3,("check_elections: >>> Starting election for workgroup %s on subnet %s <<<\n",
work->work_group, subrec->subnet_name ));
work->ElectionCount = 0;
work->RunningElection = True;
work->needelection = False;
+
+ /* Send a force election packet to begin. */
+ send_election_dgram(subrec, work->work_group, 0, 0, "");
}
}
}
diff --git a/source3/nmbd/nmbd_incomingdgrams.c b/source3/nmbd/nmbd_incomingdgrams.c
index 62dc444e0c..daa321b3ae 100644
--- a/source3/nmbd/nmbd_incomingdgrams.c
+++ b/source3/nmbd/nmbd_incomingdgrams.c
@@ -318,12 +318,10 @@ a local master browser for workgroup %s and we think we are master. Forcing elec
/* We should demote ourself and force an election. */
- unbecome_local_master_browser( subrec, work);
+ unbecome_local_master_browser( subrec, work, True);
/* The actual election requests are handled in
nmbd_election.c */
-
- work->needelection = True;
return;
}
@@ -722,10 +720,7 @@ request from %s IP %s state=0x%X\n",
for (work = sr->workgrouplist; work; work = work->next)
{
if (AM_LOCAL_MASTER_BROWSER(work))
- {
- unbecome_local_master_browser(sr, work);
- work->needelection = True;
- }
+ unbecome_local_master_browser(sr, work, True);
}
}
}
diff --git a/source3/nmbd/nmbd_namelistdb.c b/source3/nmbd/nmbd_namelistdb.c
index d2c9ea2e71..b7f185deeb 100644
--- a/source3/nmbd/nmbd_namelistdb.c
+++ b/source3/nmbd/nmbd_namelistdb.c
@@ -86,7 +86,7 @@ static void upcase_name( struct nmb_name *target, struct nmb_name *source )
* Add a new or overwrite an existing namelist entry.
* ************************************************************************** **
*/
-void update_name_in_namelist( struct subnet_record *subrec,
+static void update_name_in_namelist( struct subnet_record *subrec,
struct name_record *namerec )
{
struct name_record *oldrec = NULL;
diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c
index e07391fb48..23db845348 100644
--- a/source3/nmbd/nmbd_packets.c
+++ b/source3/nmbd/nmbd_packets.c
@@ -602,6 +602,17 @@ struct response_record *queue_release_name( struct subnet_record *subrec,
return NULL;
}
+ /*
+ * For a broadcast release packet, only send once.
+ * This will cause us to remove the name asap. JRA.
+ */
+
+ if(bcast)
+ {
+ rrec->repeat_count = 0;
+ rrec->repeat_time = 0;
+ }
+
return rrec;
}
diff --git a/source3/nmbd/nmbd_subnetdb.c b/source3/nmbd/nmbd_subnetdb.c
index 2b29d1b45b..40ae1db1b3 100644
--- a/source3/nmbd/nmbd_subnetdb.c
+++ b/source3/nmbd/nmbd_subnetdb.c
@@ -75,12 +75,27 @@ static void add_subnet(struct subnet_record *subrec)
/* CRH!!! */
/* ************************************************************************** ** * This will go away when we move to a "real" database back-end.
+ Note that we cannot use memcmp here as we have no control
+ over how the struct nmb_name structures are packed in memory. JRA.
* ************************************************************************** ** */
int namelist_entry_compare( ubi_trItemPtr Item, ubi_trNodePtr Node )
{
struct name_record *NR = (struct name_record *)Node;
+ struct nmb_name *nmbname = (struct nmb_name *)Item;
+ int ret;
- return( memcmp( Item, &(NR->name), sizeof(struct nmb_name) ) );
+ if(nmb_name_equal( &NR->name, nmbname))
+ return 0;
+
+ ret = strcmp( nmbname->name, NR->name.name);
+ if(ret)
+ return ret;
+
+ ret = strcmp( nmbname->scope, NR->name.scope);
+ if(ret)
+ return ret;
+
+ return nmbname->name_type - NR->name.name_type;
} /* namelist_entry_compare */
/* CRH!!! */
diff --git a/source3/nmbd/nmbd_workgroupdb.c b/source3/nmbd/nmbd_workgroupdb.c
index 0b392680df..818875c820 100644
--- a/source3/nmbd/nmbd_workgroupdb.c
+++ b/source3/nmbd/nmbd_workgroupdb.c
@@ -125,7 +125,7 @@ static struct work_record *create_workgroup(char *name, int ttl)
/* WfWg uses 01040b01 */
/* Win95 uses 01041501 */
/* NTAS uses ???????? */
- work->ElectionCriterion = (MAINTAIN_LIST)|(ELECTION_VERSION<<8);
+ work->ElectionCriterion = (MAINTAIN_LIST)|(BROWSER_ELECTION_VERSION<<8);
work->ElectionCriterion |= (lp_os_level() << 24);
if (lp_domain_master())
work->ElectionCriterion |= 0x80;