Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1996
+ Copyright (C) Andrew Tridgell 1994-1997
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
extern pstring scope;
extern pstring myname;
+extern fstring myworkgroup;
extern struct in_addr ipzero;
-extern struct in_addr ipgrp;
-
-/* machine comment for host announcements */
-extern pstring ServerComment;
+extern struct in_addr wins_ip;
/* here are my election parameters */
extern uint16 nb_type; /* samba's NetBIOS name type */
+
/*******************************************************************
occasionally check to see if the master browser is around
******************************************************************/
-void check_master_browser(void)
+void check_master_browser(time_t t)
{
static time_t lastrun=0;
- time_t t = time(NULL);
struct subnet_record *d;
if (!lastrun) lastrun = t;
- if (t < lastrun + CHECK_TIME_MST_BROWSE * 60)
- return;
+ if (t < lastrun + CHECK_TIME_MST_BROWSE * 60) return;
+
lastrun = t;
dump_workgroups();
- for (d = subnetlist; d; d = d->next)
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
{
- struct work_record *work;
+ if (strequal(work->work_group, myworkgroup) && !AM_MASTER(work))
+ {
+ if (lp_local_master())
+ {
+ /* potential master browser - not a master browser. force
+ becoming a master browser, hence the log message.
+ */
- for (work = d->workgrouplist; work; work = work->next)
- {
- /* if we are not the browse master of a workgroup, and we can't
- find a browser on the subnet, do something about it. */
+ DEBUG(0,("%s potential master for %s %s - force election\n",
+ timestring(), work->work_group,
+ inet_ntoa(d->bcast_ip)));
- if (!AM_MASTER(work))
- {
- queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
- work->work_group,0x1d,0,0,0,NULL,NULL,
- True,False,d->bcast_ip,d->bcast_ip);
- }
- }
+ browser_gone(work->work_group, d->bcast_ip);
+ }
+ else
+ {
+ /* if we are not the browse master of a workgroup,
+ and we can't find a browser on the subnet, do
+ something about it.
+ */
+
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
+ work->work_group,0x1d,0,0,0,NULL,NULL,
+ True,False,d->bcast_ip,d->bcast_ip);
+ }
+ }
}
+ }
}
/*******************************************************************
- what to do if a master browser DOESN't exist
+ what to do if a master browser DOESN't exist.
+
+ option 1: force an election, and participate in it
+ option 2: force an election, and let everyone else participate.
+
******************************************************************/
void browser_gone(char *work_name, struct in_addr ip)
{
/* i don't know about this workgroup, therefore i don't care */
if (!work || !d) return;
-
- if (strequal(work->work_group, lp_workgroup()))
+
+ /* don't do election stuff on the WINS subnet */
+ if (ip_equal(d->bcast_ip,wins_ip))
+ return;
+
+ if (strequal(work->work_group, myworkgroup))
{
+ if (lp_local_master())
+ {
+ /* we have discovered that there is no local master
+ browser, and we are configured to initiate
+ an election under exactly such circumstances.
+ */
DEBUG(2,("Forcing election on %s %s\n",
work->work_group,inet_ntoa(d->bcast_ip)));
/* we can attempt to become master browser */
work->needelection = True;
- }
- else
- {
- /* local interfaces: force an election */
- send_election(d, work->work_group, 0, 0, myname);
-
- /* only removes workgroup completely on a local interface
- persistent lmhosts entries on a local interface _will_ be removed).
- */
- remove_workgroup(d, work,True);
+ }
+ else
+ {
+ /* we need to force an election, because we are configured
+ not to _become_ the local master, but we still _need_ one,
+ having detected that one doesn't exist.
+ */
+
+ /* local interfaces: force an election */
+ send_election(d, work->work_group, 0, 0, myname);
+
+ /* only removes workgroup completely on a local interface
+ persistent lmhosts entries on a local interface _will_ be removed).
+ */
+ remove_workgroup(d, work,True);
+ add_workgroup_to_subnet(d, work->work_group);
+ }
}
}
strupper(p);
p = skip_string(p,1);
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
+ send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
+ outbuf,PTR_DIFF(p,outbuf),
name,group,0,0x1e,d->bcast_ip,*iface_ip(d->bcast_ip));
}
void name_unregister_work(struct subnet_record *d, char *name, int name_type)
{
struct work_record *work;
+ int remove_type_local = 0;
+ int remove_type_domain = 0;
+ int remove_type_logon = 0;
remove_netbios_name(d,name,name_type,SELF,ipzero);
if (!(work = find_workgroupstruct(d, name, False))) return;
- if (ms_browser_name(name, name_type) ||
- (AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 &&
- (name_type == 0x1d || name_type == 0x1b)))
+ /* work out what to unbecome, from the name type being removed */
+
+ if (ms_browser_name(name, name_type))
+ {
+ remove_type_local |= SV_TYPE_MASTER_BROWSER;
+ }
+ if (AM_MASTER(work) && strequal(name, myworkgroup) && name_type == 0x1d)
+ {
+ remove_type_local |= SV_TYPE_MASTER_BROWSER;
+ }
+ if (AM_DOMMST(work) && strequal(name, myworkgroup) && name_type == 0x1b)
{
- int remove_type = 0;
-
- if (ms_browser_name(name, name_type))
- remove_type = SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER;
- if (name_type == 0x1d)
- remove_type = SV_TYPE_MASTER_BROWSER;
- if (name_type == 0x1b)
- remove_type = SV_TYPE_DOMAIN_MASTER;
-
- become_nonmaster(d, work, remove_type);
+ remove_type_domain |= SV_TYPE_DOMAIN_MASTER;
}
+ if (AM_DOMMEM(work) && strequal(name, myworkgroup) && name_type == 0x1c)
+ {
+ remove_type_logon|= SV_TYPE_DOMAIN_MEMBER;
+ }
+
+ if (remove_type_local ) unbecome_local_master (d, work, remove_type_local );
+ if (remove_type_domain) unbecome_domain_master(d, work, remove_type_domain);
+ if (remove_type_logon ) unbecome_logon_server (d, work, remove_type_logon );
}
int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast)
{
enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ?
- SELF : REGISTER;
+ SELF : REGISTER;
if (source == SELF)
- {
- struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False);
+ {
+ struct work_record *work = find_workgroupstruct(d,
+ myworkgroup, False);
- add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast);
+ add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast);
- if (work)
- {
- if (work->state != MST_NONE)
+ if (work)
{
- /* samba is in the process of working towards master browser-ness.
- initiate the next stage.
- */
- become_master(d, work);
- return;
+ int add_type_local = False;
+ int add_type_domain = False;
+ int add_type_logon = False;
+
+ DEBUG(4,("checking next stage: name_register_work %s\n", name));
+
+ /* work out what to become, from the name type being added */
+
+ if (ms_browser_name(name, name_type))
+ {
+ add_type_local = True;
+ }
+ if (strequal(name, myworkgroup) && name_type == 0x1d)
+ {
+ add_type_local = True;
+ }
+ if (strequal(name, myworkgroup) && name_type == 0x1b)
+ {
+ add_type_domain = True;
+ }
+ if (strequal(name, myworkgroup) && name_type == 0x1c)
+ {
+ add_type_logon = True;
+ }
+
+ if (add_type_local ) become_local_master (d, work);
+ if (add_type_domain) become_domain_master(d, work);
+ if (add_type_logon ) become_logon_server (d, work);
}
}
- }
}
/*******************************************************************
- become the master browser.
+ become the local master browser.
this is done in stages. note that this could take a while,
particularly on a broadcast subnet, as we have to wait for
the implicit registration of each name to be accepted.
- as each name is successfully registered, become_master() is
+ as each name is successfully registered, become_local_master() is
called again, in order to initiate the next stage. see
dead_netbios_entry() - deals with implicit name registration
and response_name_reg() - deals with explicit registration
with a WINS server.
- stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1.
- stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d)
- stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b)
- stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...)
+ stage 1: was MST_POTENTIAL - go to MST_POTENTIAL and register ^1^2__MSBROWSE__^2^1.
+ stage 2: was MST_BACK - go to MST_MSB and register WORKGROUP(0x1d)
+ stage 3: was MST_MSB - go to MST_BROWSER and stay there
XXXX note: this code still does not cope with the distinction
between different types of nodes, particularly between M and P
nodes. that comes later.
******************************************************************/
-void become_master(struct subnet_record *d, struct work_record *work)
+void become_local_master(struct subnet_record *d, struct work_record *work)
{
- uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_SERVER_UNIX|0x00400000;
-
- if (!work) return;
+ /* domain type must be limited to domain enum + server type. it must
+ not have SV_TYPE_SERVER or anything else with SERVER in it, else
+ clients get confused and start thinking this entry is a server
+ not a workgroup
+ */
+ uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
+
+ if (!work || !d)
+ return;
+ if (!lp_local_master())
+ {
+ DEBUG(0,("Samba not configured as a local master browser.\n"));
+ return;
+ }
+
DEBUG(2,("Becoming master for %s %s (currently at stage %d)\n",
- work->work_group,inet_ntoa(d->bcast_ip),work->state));
+ work->work_group,inet_ntoa(d->bcast_ip),work->mst_state));
- switch (work->state)
+ switch (work->mst_state)
{
- case MST_NONE: /* while we were nothing but a server... */
+ case MST_POTENTIAL: /* while we were nothing but a server... */
{
DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n"));
- work->state = MST_WON; /* ... an election win was successful */
+ work->mst_state = MST_BACK; /* an election win was successful */
work->ElectionCriterion |= 0x5;
/* update our server status */
work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
- add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
+ add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True);
/* add special browser name */
- add_my_name_entry(d,MSBROWSE ,0x01,nb_type|NB_ACTIVE|NB_GROUP);
+ add_my_name_entry(d,MSBROWSE,0x01,nb_type|NB_ACTIVE|NB_GROUP,False);
/* DON'T do anything else after calling add_my_name_entry() */
- return;
+ break;
}
- case MST_WON: /* while nothing had happened except we won an election... */
+
+ case MST_BACK: /* while nothing had happened except we won an election... */
{
DEBUG(3,("go to second stage: register as master browser\n"));
- work->state = MST_MSB; /* ... registering MSBROWSE was successful */
+ work->mst_state = MST_MSB; /* registering MSBROWSE was successful */
/* add server entry on successful registration of MSBROWSE */
add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
/* add master name */
- add_my_name_entry(d,work->work_group,0x1d,nb_type|NB_ACTIVE);
+ add_my_name_entry(d,work->work_group,0x1d,nb_type|NB_ACTIVE,False);
/* DON'T do anything else after calling add_my_name_entry() */
- return;
+ break;
}
+
case MST_MSB: /* while we were still only registered MSBROWSE state... */
{
- DEBUG(3,("2nd stage complete: registered as master browser\n"));
- work->state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */
+ int i = 0;
+ struct server_record *sl;
+
+ DEBUG(3,("2nd stage complete: registered as master browser for workgroup %s \
+on subnet %s\n", work->work_group, inet_ntoa(d->bcast_ip)));
+ work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
/* update our server status */
work->ServerType |= SV_TYPE_MASTER_BROWSER;
- add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
- if (work->serverlist == NULL) /* no servers! */
+ DEBUG(3,("become_local_master: updating our server %s to type %x\n",
+ myname, work->ServerType));
+
+ add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True);
+
+ /* Count the number of servers we have on our list. If it's
+ less than 10 (just a heuristic) request the servers
+ to announce themselves.
+ */
+ for( sl = work->serverlist; sl != NULL; sl = sl->next)
+ i++;
+
+ if (i < 10)
{
/* ask all servers on our local net to announce to us */
announce_request(work, d->bcast_ip);
}
+
+ /* Reset the announce master timer so that we do an announce as soon as possible
+ now we are a master. */
+ reset_announce_timer();
+
+ DEBUG(0,("Samba is now a local master browser for workgroup %s on subnet %s\n",
+ work->work_group, inet_ntoa(d->bcast_ip)));
+
break;
- }
+ }
- case MST_BROWSER:
- {
+ case MST_BROWSER:
+ {
/* don't have to do anything: just report success */
DEBUG(3,("3rd stage: become master browser!\n"));
-
break;
- }
+ }
+ }
+}
- case MST_DOMAIN_NONE:
- {
- if (lp_domain_master())
- {
- work->state = MST_DOMAIN_MEM; /* ... become domain member */
- DEBUG(3,("domain first stage: register as domain member\n"));
- /* add domain member name */
- add_my_name_entry(d,work->work_group,0x1e,nb_type|NB_ACTIVE|NB_GROUP);
+/*******************************************************************
+ become the domain master browser.
- /* DON'T do anything else after calling add_my_name_entry() */
- return;
- }
- else
- {
- DEBUG(4,("samba not configured as a domain master.\n"));
- }
-
- break;
- }
+ this is done in stages. note that this could take a while,
+ particularly on a broadcast subnet, as we have to wait for
+ the implicit registration of each name to be accepted.
- case MST_DOMAIN_MEM:
- {
- if (lp_domain_master())
- {
- work->state = MST_DOMAIN_TST; /* ... possibly become domain master */
- DEBUG(3,("domain second stage: register as domain master\n"));
+ as each name is successfully registered, become_domain_master() is
+ called again, in order to initiate the next stage. see
+ dead_netbios_entry() - deals with implicit name registration
+ and response_name_reg() - deals with explicit registration
+ with a WINS server.
- if (lp_domain_logons())
- {
- work->ServerType |= SV_TYPE_DOMAIN_MEMBER;
- add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
- }
+ stage 1: was DOMAIN_NONE - go to DOMAIN_MST
- /* add domain master name */
- add_my_name_entry(d,work->work_group,0x1b,nb_type|NB_ACTIVE );
+ XXXX note: this code still does not cope with the distinction
+ between different types of nodes, particularly between M and P
+ nodes. that comes later.
- /* DON'T do anything else after calling add_my_name_entry() */
- return;
- }
- else
- {
- DEBUG(4,("samba not configured as a domain master.\n"));
- }
+ ******************************************************************/
+void become_domain_master(struct subnet_record *d, struct work_record *work)
+{
+ /* domain type must be limited to domain enum + server type. it must
+ not have SV_TYPE_SERVER or anything else with SERVER in it, else
+ clients get confused and start thinking this entry is a server
+ not a workgroup
+ */
+
+ if (!work || !d) return;
+
+ if (!lp_domain_master())
+ {
+ DEBUG(0,("Samba not configured as a domain master browser.\n"));
+ return;
+ }
+
+ DEBUG(2,("Becoming domain master for %s %s (currently at stage %d)\n",
+ work->work_group,inet_ntoa(d->bcast_ip),work->dom_state));
+ switch (work->dom_state)
+ {
+ case DOMAIN_NONE: /* while we were nothing but a server... */
+ {
+ DEBUG(3,("become_domain_master: go to first stage: register <1b> name\n"));
+ work->dom_state = DOMAIN_WAIT;
+
+ /* Registering the DOMAIN<1b> name is very tricky. We need to
+ do this on all our subnets, but don't want to bradcast it
+ on locally connected subnets (WinNT doesn't do this). Also,
+ previous versions of Samba screw up royally when we do this.
+ We need to register it immediatly on our local subnet, but
+ also actually check with the WINS server if it exists. If the name
+ has already been claimed by someone else in the WINS server
+ then we need to back out all our local registrations and
+ fail. Thus we only directly enter the name on local subnets,
+ on the WINS subnet we actually check...
+ */
+ /* XXXX the 0x1b is domain master browser name */
+ if(d == wins_subnet)
+ add_my_name_entry(d, work->work_group,0x1b,nb_type|NB_ACTIVE,False);
+ else
+ add_my_name_entry(d, work->work_group,0x1b,nb_type|NB_ACTIVE,True);
+
+ /* DON'T do anything else after calling add_my_name_entry() */
break;
}
- case MST_DOMAIN_TST: /* while we were still a master browser... */
+ case DOMAIN_WAIT:
{
+ work->dom_state = DOMAIN_MST; /* ... become domain master */
+ DEBUG(3,("become_domain_master: first stage - register as domain member\n"));
+
/* update our server status */
- if (lp_domain_master())
- {
- struct subnet_record *d1;
- uint32 update_type = 0;
+ work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER;
+ add_server_entry(d,work,myname,work->ServerType,0,
+ lp_serverstring(),True);
- DEBUG(3,("domain third stage: samba is now a domain master.\n"));
- work->state = MST_DOMAIN; /* ... registering WORKGROUP(1b) succeeded */
+ DEBUG(0,("Samba is now a domain master browser for workgroup %s on subnet %s\n",
+ work->work_group, inet_ntoa(d->bcast_ip)));
- update_type |= SV_TYPE_DOMAIN_MASTER;
-
- if (lp_domain_logons())
- {
- update_type |= SV_TYPE_DOMAIN_CTRL;
- }
+ break;
+ }
- work->ServerType |= update_type;
- add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
+ case DOMAIN_MST:
+ {
+ /* don't have to do anything: just report success */
+ DEBUG(3,("domain second stage: there isn't one!\n"));
+ break;
+ }
+ }
+}
- for (d1 = subnetlist; d1; d1 = d1->next)
- {
- struct work_record *w;
- if (ip_equal(d1->bcast_ip, d->bcast_ip)) continue;
- for (w = d1->workgrouplist; w; w = w->next)
- {
- struct server_record *s = find_server(w, myname);
- if (strequal(w->work_group, work->work_group))
- {
- w->ServerType |= update_type;
- }
- if (s)
- {
- s->serv.type |= update_type;
- DEBUG(4,("found server %s on %s: update to %8x\n",
- s->serv.name, inet_ntoa(d1->bcast_ip),
- s->serv.type));
- }
- }
- }
- }
+/*******************************************************************
+ become a logon server.
+ ******************************************************************/
+void become_logon_server(struct subnet_record *d, struct work_record *work)
+{
+ if (!work || !d) return;
+ if (lp_domain_logons())
+ {
+ DEBUG(0,("samba not configured as a logon master.\n"));
+ return;
+ }
+
+ DEBUG(2,("Becoming logon server for %s %s (currently at stage %d)\n",
+ work->work_group,inet_ntoa(d->bcast_ip),work->log_state));
+
+ switch (work->log_state)
+ {
+ case LOGON_NONE: /* while we were nothing but a server... */
+ {
+ DEBUG(3,("go to first stage: register <1c> name\n"));
+ work->log_state = LOGON_WAIT;
+
+ /* XXXX the 0x1c is apparently something to do with domain logons */
+ add_my_name_entry(d, myworkgroup,0x1c,nb_type|NB_ACTIVE|NB_GROUP,False);
+
+ /* DON'T do anything else after calling add_my_name_entry() */
break;
}
- case MST_DOMAIN:
+ case LOGON_WAIT:
{
- /* don't have to do anything: just report success */
- DEBUG(3,("fifth stage: there isn't one yet!\n"));
+ work->log_state = LOGON_SRV; /* ... become logon server */
+ DEBUG(3,("logon second stage: register \n"));
+
+ /* update our server status */
+ work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MEMBER;
+ add_server_entry(d,work,myname,work->ServerType,0,
+ lp_serverstring(),True);
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ break;
+ }
+
+ case LOGON_SRV:
+ {
+ DEBUG(3,("logon third stage: there isn't one!\n"));
break;
}
}
/*******************************************************************
- unbecome the master browser. initates removal of necessary netbios
+ unbecome the local master browser. initates removal of necessary netbios
names, and tells the world that we are no longer a master browser.
+
+ XXXX this _should_ be used to demote to a backup master browser, without
+ going straight to non-master browser. another time.
+
******************************************************************/
-void become_nonmaster(struct subnet_record *d, struct work_record *work,
+void unbecome_local_master(struct subnet_record *d, struct work_record *work,
int remove_type)
{
int new_server_type = work->ServerType;
- DEBUG(2,("Becoming non-master for %s\n",work->work_group));
-
- /* can only remove master or domain types with this function */
- remove_type &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER);
-
- /* unbecome a master browser; unbecome a domain master, too :-( */
- if (remove_type & SV_TYPE_MASTER_BROWSER)
- remove_type |= SV_TYPE_DOMAIN_MASTER;
+ /* can only remove master types with this function */
+ remove_type &= SV_TYPE_MASTER_BROWSER;
new_server_type &= ~remove_type;
- if (!(new_server_type & (SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER)))
+ if (remove_type)
{
+ DEBUG(2,("Becoming local non-master for %s\n",work->work_group));
+
/* no longer a master browser of any sort */
- work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
+ work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
work->ElectionCriterion &= ~0x4;
- work->state = MST_NONE;
+ work->mst_state = MST_POTENTIAL;
/* announce ourselves as no longer active as a master browser. */
announce_server(d, work, work->work_group, myname, 0, 0);
- remove_name_entry(d,MSBROWSE ,0x01);
+ remove_name_entry(d,MSBROWSE ,0x01,False);
+ remove_name_entry(d,work->work_group,0x1d,False);
}
+}
+
+
+/*******************************************************************
+ unbecome the domain master browser. initates removal of necessary netbios
+ names, and tells the world that we are no longer a domain browser.
+ ******************************************************************/
+void unbecome_domain_master(struct subnet_record *d, struct work_record *work,
+ int remove_type)
+{
+ int new_server_type = work->ServerType;
+
+ DEBUG(2,("Becoming domain non-master for %s\n",work->work_group));
- work->ServerType = new_server_type;
+ /* can only remove master or domain types with this function */
+ remove_type &= SV_TYPE_DOMAIN_MASTER;
+
+ new_server_type &= ~remove_type;
- if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
+ if (remove_type)
{
- if (work->state == MST_DOMAIN)
- work->state = MST_BROWSER;
- remove_name_entry(d,work->work_group,0x1b);
-
+ /* no longer a domain master browser of any sort */
+
+ work->dom_state = DOMAIN_NONE;
+
+ /* announce ourselves as no longer active as a master browser on
+ all our local subnets. */
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
+ {
+ work = find_workgroupstruct(d, myworkgroup, False);
+
+ announce_server(d, work, work->work_group, myname, 0, 0);
+ /* Remove the name entry without any NetBIOS traffic as that's
+ how it was registered. */
+ remove_name_entry(d,work->work_group,0x1b,True);
+ }
}
+}
- if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
+
+/*******************************************************************
+ unbecome the logon server. initates removal of necessary netbios
+ names, and tells the world that we are no longer a logon server.
+ ******************************************************************/
+void unbecome_logon_server(struct subnet_record *d, struct work_record *work,
+ int remove_type)
+{
+ int new_server_type = work->ServerType;
+
+ DEBUG(2,("Becoming logon non-server for %s\n",work->work_group));
+
+ /* can only remove master or domain types with this function */
+ remove_type &= SV_TYPE_DOMAIN_MEMBER;
+
+ new_server_type &= ~remove_type;
+
+ if (remove_type)
{
- if (work->state >= MST_BROWSER)
- work->state = MST_NONE;
- remove_name_entry(d,work->work_group,0x1d);
+ /* no longer a master browser of any sort */
+
+ work->log_state = LOGON_NONE;
+
+ /* announce ourselves as no longer active as a master browser. */
+ announce_server(d, work, work->work_group, myname, 0, 0);
+ remove_name_entry(d,work->work_group,0x1c,False);
}
}
/*******************************************************************
run the election
******************************************************************/
-void run_elections(void)
+void run_elections(time_t t)
{
- time_t t = time(NULL);
static time_t lastime = 0;
struct subnet_record *d;
lastime = t;
- for (d = subnetlist; d; d = d->next)
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
{
struct work_record *work;
+
for (work = d->workgrouplist; work; work = work->next)
{
if (work->RunningElection)
work->work_group,inet_ntoa(d->bcast_ip)));
work->RunningElection = False;
- work->state = MST_NONE;
+ work->mst_state = MST_POTENTIAL;
- become_master(d, work);
+ become_local_master(d, work);
}
}
}
static BOOL win_election(struct work_record *work,int version,uint32 criterion,
int timeup,char *name)
{
- time_t t = time(NULL);
- uint32 mycriterion;
+ int mytimeup = time(NULL) - StartupTime;
+ uint32 mycriterion = work->ElectionCriterion;
+
+ /* If local master is false then never win
+ in election broadcasts. */
+ if(!lp_local_master())
+ {
+ DEBUG(3,("win_election: Losing election as local master == False\n"));
+ return False;
+ }
+
+ DEBUG(4,("election comparison: %x:%x %x:%x %d:%d %s:%s\n",
+ version,ELECTION_VERSION,
+ criterion,mycriterion,
+ timeup,mytimeup,
+ name,myname));
+
if (version > ELECTION_VERSION) return(False);
if (version < ELECTION_VERSION) return(True);
- mycriterion = work->ElectionCriterion;
-
if (criterion > mycriterion) return(False);
if (criterion < mycriterion) return(True);
- if (timeup > (t - StartupTime)) return(False);
- if (timeup < (t - StartupTime)) return(True);
+ if (timeup > mytimeup) return(False);
+ if (timeup < mytimeup) return(True);
if (strcasecmp(myname,name) > 0) return(False);
******************************************************************/
void process_election(struct packet_struct *p,char *buf)
{
- struct dgram_packet *dgram = &p->packet.dgram;
- struct in_addr ip = dgram->header.source_ip;
- struct subnet_record *d = find_subnet(ip);
- int version = CVAL(buf,0);
- uint32 criterion = IVAL(buf,1);
- int timeup = IVAL(buf,5)/1000;
- char *name = buf+13;
- struct work_record *work;
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct subnet_record *d = find_subnet(ip);
+ int version = CVAL(buf,0);
+ uint32 criterion = IVAL(buf,1);
+ int timeup = IVAL(buf,5)/1000;
+ char *name = buf+13;
+ struct work_record *work;
+
+ if (!d) return;
+
+ if (ip_equal(d->bcast_ip,wins_ip))
+ {
+ DEBUG(3,("Unexpected election request from %s %s on WINS net\n",
+ name, inet_ntoa(p->ip)));
+ return;
+ }
- if (!d) return;
-
- name[15] = 0;
+ name[15] = 0;
- DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n",
- name,version,criterion,timeup));
-
- if (same_context(dgram)) return;
-
- for (work = d->workgrouplist; work; work = work->next)
- {
- if (listening_name(work, &dgram->dest_name) &&
- strequal(work->work_group, lp_workgroup()))
+ DEBUG(3,("Election request from %s %s vers=%d criterion=%08x timeup=%d\n",
+ name,inet_ntoa(p->ip),version,criterion,timeup));
+
+ if (same_context(dgram)) return;
+
+ for (work = d->workgrouplist; work; work = work->next)
{
- if (win_election(work, version,criterion,timeup,name))
- {
- if (!work->RunningElection)
+ if (!strequal(work->work_group, myworkgroup))
+ continue;
+
+ if (win_election(work, version,criterion,timeup,name))
{
- work->needelection = True;
- work->ElectionCount=0;
- work->state = MST_NONE;
+ if (!work->RunningElection)
+ {
+ work->needelection = True;
+ work->ElectionCount=0;
+ work->mst_state = MST_POTENTIAL;
+ }
}
- }
- else
- {
- work->needelection = False;
-
- if (work->RunningElection)
+ else
{
- work->RunningElection = False;
- DEBUG(3,(">>> Lost election on %s %s <<<\n",
- work->work_group,inet_ntoa(d->bcast_ip)));
-
- /* if we are the master then remove our masterly names */
- if (AM_MASTER(work))
- {
- become_nonmaster(d, work,
- SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER);
- }
+ work->needelection = False;
+
+ if (work->RunningElection || AM_MASTER(work))
+ {
+ work->RunningElection = False;
+ DEBUG(3,(">>> Lost election on %s %s <<<\n",
+ work->work_group,inet_ntoa(d->bcast_ip)));
+ if (AM_MASTER(work))
+ {
+ unbecome_local_master(d, work, SV_TYPE_MASTER_BROWSER);
+ }
+ }
}
- }
}
- }
}
struct subnet_record *d;
BOOL run_any_election = False;
- for (d = subnetlist; d; d = d->next)
+ for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d))
{
struct work_record *work;
for (work = d->workgrouplist; work; work = work->next)