Removed version number from file header.
[samba.git] / source / nmbd / nmbd_become_lmb.c
index b97da7d8b4ee4aa54d5fa346d40bcdec26827e86..3e0884567e76dce17db29651a50a150a990f1fe8 100644 (file)
@@ -1,6 +1,5 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    NBT netbios routines and daemon - version 2
    Copyright (C) Andrew Tridgell 1994-1998
    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
@@ -24,8 +23,6 @@
 
 #include "includes.h"
 
-extern int DEBUGLEVEL;
-extern pstring scope;
 extern pstring global_myname;
 
 extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
@@ -43,8 +40,9 @@ void insert_permanent_name_into_unicast( struct subnet_record *subrec,
   if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL)
   {
     /* The name needs to be created on the unicast subnet. */
-    add_name_to_subnet( unicast_subnet, nmbname->name, nmbname->name_type,
-                        nb_type, PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
+    (void)add_name_to_subnet( unicast_subnet, nmbname->name,
+                              nmbname->name_type, nb_type,
+                              PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
   }
   else
   {
@@ -77,7 +75,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;
@@ -124,29 +123,41 @@ in workgroup %s on subnet %s\n",
    * master browser.
    */
 
-  make_nmb_name(&nmbname, work->work_group, 0x1d, scope);
+  make_nmb_name(&nmbname, work->work_group, 0x1d);
 
   remove_permanent_name_from_unicast( subrec, &nmbname);
 
+  if(force_new_election)
+    work->needelection = True;
 }
 
 /*******************************************************************
   Unbecome the local master browser name release success function.
 ******************************************************************/
 
-void unbecome_local_master_success(struct subnet_record *subrec,
+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",
-             namestr(released_name)));
+             nmb_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));
+  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 );
+  }
 
 }
 
@@ -154,13 +165,17 @@ on subnet %s *****\n\n", timestring(), global_myname, released_name->name, subre
   Unbecome the local master browser name release fail function.
 ******************************************************************/
 
-void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec,
+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", namestr(fail_name)));
+Removing from namelist anyway.\n", nmb_namestr(fail_name)));
 
   /* Do it anyway. */
   namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
@@ -168,30 +183,51 @@ 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 );
-
-  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));
+  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 );
+  }
 }
 
 /*******************************************************************
- 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;
 
-  make_nmb_name(&nmbname, workgroup_name, 0x1d, scope);
+  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,
-                 NULL);
+                 userdata);
+
+    zero_free(userdata, size);
   }
 }
 
@@ -205,12 +241,10 @@ static void release_msbrowse_name_success(struct subnet_record *subrec,
                       struct in_addr released_ip)
 {
   DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
-           namestr(released_name), subrec->subnet_name ));
+           nmb_namestr(released_name), subrec->subnet_name ));
 
   /* Remove the permanent MSBROWSE name added into the unicast subnet. */
   remove_permanent_name_from_unicast( subrec, released_name);
-
-  release_1d_name( subrec, userdata->data );
 }
 
 /*******************************************************************
@@ -221,11 +255,10 @@ 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.",
-           namestr(fail_name), subrec->subnet_name ));
+           nmb_namestr(fail_name), subrec->subnet_name ));
 
   /* Release the name anyway. */
   namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
@@ -234,27 +267,25 @@ 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. */
 
   DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \
 on subnet %s\n",work->work_group, subrec->subnet_name));
   
-  if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
+  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",
@@ -266,29 +297,30 @@ 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);
+  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,
-                 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));
 }
 
 /****************************************************************************
@@ -368,8 +400,14 @@ on subnet %s\n", work->work_group, subrec->subnet_name));
      master browser as soon as possible that we are a local master browser. */
   reset_announce_timer();
 
-  DEBUG(0,("\n%s *****   Samba name server %s is now a local master browser for workgroup %s \
-on subnet %s *****\n\n", timestring(), global_myname, work->work_group, subrec->subnet_name));
+  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 );
+  }
 
 }
 
@@ -383,7 +421,7 @@ static void become_local_master_fail2(struct subnet_record *subrec,
   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", namestr(fail_name), subrec->subnet_name));
+Failed to become a local master browser.\n", nmb_namestr(fail_name), subrec->subnet_name));
 
   if(!work)
   {
@@ -393,7 +431,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);
 }
 
 /****************************************************************************
@@ -447,7 +485,6 @@ static void become_local_master_fail1(struct subnet_record *subrec,
 {
   char *work_name = rrec->userdata->data;
   struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
-  struct server_record *servrec;
 
   if(!work)
   {
@@ -456,7 +493,7 @@ workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
     return;
   }
 
-  if((servrec = find_server_in_workgroup(work, global_myname)) == NULL)
+  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",
@@ -464,11 +501,11 @@ 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",
-       work->work_group, subrec->subnet_name, namestr(fail_name)));
+       work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
 }
 
 /******************************************************************
@@ -482,8 +519,8 @@ workgroup %s on subnet %s. Couldn't register name %s.\n",
 
 void become_local_master_browser(struct subnet_record *subrec, struct work_record *work)
 {
-  struct server_record *servrec;
   struct userdata_struct *userdata;
+  int size = sizeof(struct userdata_struct) + sizeof(fstring) + 1;
 
   /* Sanity check. */
   if (!lp_local_master())
@@ -499,7 +536,7 @@ void become_local_master_browser(struct subnet_record *subrec, struct work_recor
     return;
   }
 
-  if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
+  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",
@@ -519,7 +556,7 @@ in workgroup %s on subnet %s\n",
   subrec->work_changed = True;
 
   /* Setup the userdata_struct. */
-  if((userdata = (struct userdata_struct *)malloc(sizeof(struct userdata_struct) + sizeof(fstring)+1)) == NULL)
+  if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
   {
     DEBUG(0,("become_local_master_browser: malloc fail.\n"));
     return;
@@ -536,7 +573,7 @@ in workgroup %s on subnet %s\n",
                 become_local_master_fail1,
                 userdata);
 
-  free((char *)userdata);
+  zero_free(userdata, size);
 }
 
 /***************************************************************