diff options
Diffstat (limited to 'source3/nmbd')
-rw-r--r-- | source3/nmbd/nmbd_become_lmb.c | 83 | ||||
-rw-r--r-- | source3/nmbd/nmbd_elections.c | 43 | ||||
-rw-r--r-- | source3/nmbd/nmbd_incomingdgrams.c | 9 | ||||
-rw-r--r-- | source3/nmbd/nmbd_namelistdb.c | 2 | ||||
-rw-r--r-- | source3/nmbd/nmbd_packets.c | 11 | ||||
-rw-r--r-- | source3/nmbd/nmbd_subnetdb.c | 17 | ||||
-rw-r--r-- | source3/nmbd/nmbd_workgroupdb.c | 2 |
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; |