2 Unix SMB/Netbios implementation.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1995
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 14 jan 96: lkcl@pires.co.uk
24 added multiple workgroup domain master support
32 extern int DEBUGLEVEL;
35 extern pstring myname;
37 /* machine comment for host announcements */
38 extern pstring ServerComment;
40 /* here are my election parameters */
42 extern time_t StartupTime;
44 #define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
46 #define MSBROWSE "\001\002__MSBROWSE__\002"
47 #define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
49 extern struct domain_record *domainlist;
52 /*******************************************************************
53 occasionally check to see if the master browser is around
54 ******************************************************************/
55 void check_master_browser(void)
57 static time_t lastrun=0;
58 time_t t = time(NULL);
59 struct domain_record *d;
61 if (!lastrun) lastrun = t;
62 if (t < lastrun + 2*60) return;
65 for (d = domainlist; d; d = d->next)
67 struct work_record *work;
69 for (work = d->workgrouplist; work; work = work->next)
71 /* if we are not the browse master of a workgroup, and we can't
72 find a browser on the subnet, do something about it. */
76 queue_netbios_packet(ClientNMB,NMB_QUERY,CHECK_MASTER,
77 work->work_group,0x1d,0,
78 True,False,d->bcast_ip);
85 /*******************************************************************
86 what to do if a master browser DOESN't exist
87 ******************************************************************/
88 void browser_gone(char *work_name, struct in_addr ip)
90 struct domain_record *d = find_domain(ip);
91 struct work_record *work = find_workgroupstruct(d, work_name, False);
93 if (!work || !d) return;
95 DEBUG(2,("Forcing election on %s\n",work->work_group));
97 if (strequal(work->work_group, lp_workgroup()) &&
98 ip_equal(bcast_ip, d->bcast_ip))
100 /* we can attempt to become master browser */
101 work->needelection = True;
105 DEBUG(2,("no master browser for persistent entry %s %s\n",
106 work->work_group, inet_ntoa(d->bcast_ip)));
108 /* XXXX oh dear. we are going to have problems here. the
109 entry is a persistent one, there isn't anyone responsible
110 for this workgroup up and running, yet we can't find it
111 and we are going to continually have name_queries until
112 a master browser is found for this workgroup on the
117 /****************************************************************************
118 send an election packet
119 **************************************************************************/
120 void send_election(struct domain_record *d, char *group,uint32 criterion,
121 int timeup,char *name)
128 DEBUG(2,("Sending election to %s for workgroup %s\n",
129 inet_ntoa(d->bcast_ip),group));
131 bzero(outbuf,sizeof(outbuf));
133 CVAL(p,0) = 8; /* election */
136 CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
137 SIVAL(p,1,criterion);
138 SIVAL(p,5,timeup*1000); /* ms - despite the spec */
142 p = skip_string(p,1);
144 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
145 name,group,0,0x1e,d->bcast_ip,myip);
149 /*******************************************************************
150 become the master browser
151 ******************************************************************/
152 static void become_master(struct domain_record *d, struct work_record *work)
154 uint32 domain_type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_SERVER_UNIX | 0x00400000;
158 DEBUG(2,("Becoming master for %s\n",work->work_group));
160 work->ServerType |= SV_TYPE_MASTER_BROWSER;
161 work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
162 work->ElectionCriterion |= 0x5;
164 /* add browse, master and general names to database or register with WINS */
165 add_name_entry(MSBROWSE ,0x01,NB_ACTIVE|NB_GROUP);
166 add_name_entry(work->work_group,0x1d,NB_ACTIVE );
168 if (lp_domain_master())
170 DEBUG(4,("Domain master: adding names...\n"));
172 /* add domain master and domain member names or register with WINS */
173 add_name_entry(work->work_group,0x1b,NB_ACTIVE );
174 add_name_entry(work->work_group,0x1c,NB_ACTIVE|NB_GROUP);
176 work->ServerType |= SV_TYPE_DOMAIN_MASTER;
178 if (lp_domain_logons())
180 work->ServerType |= SV_TYPE_DOMAIN_CTRL;
181 work->ServerType |= SV_TYPE_DOMAIN_MEMBER;
185 /* update our server status */
186 add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
187 add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
189 if (ip_equal(bcast_ip, d->bcast_ip))
191 /* ask all servers on our local net to announce to us */
192 announce_request(work, d->bcast_ip);
197 /*******************************************************************
198 unbecome the master browser
199 ******************************************************************/
200 void become_nonmaster(struct domain_record *d, struct work_record *work)
202 DEBUG(2,("Becoming non-master for %s\n",work->work_group));
204 work->ServerType &= ~SV_TYPE_MASTER_BROWSER;
205 work->ServerType &= ~SV_TYPE_DOMAIN_MASTER;
206 work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
208 work->ElectionCriterion &= ~0x4;
210 remove_name_entry(work->work_group,0x1b);
211 remove_name_entry(work->work_group,0x1c);
212 remove_name_entry(work->work_group,0x1d);
213 remove_name_entry(MSBROWSE ,0x01);
217 /*******************************************************************
219 ******************************************************************/
220 void run_elections(void)
222 time_t t = time(NULL);
223 static time_t lastime = 0;
225 struct domain_record *d;
227 /* send election packets once a second */
228 if (lastime && t-lastime <= 0) return;
232 for (d = domainlist; d; d = d->next)
234 struct work_record *work;
235 for (work = d->workgrouplist; work; work = work->next)
237 if (work->RunningElection)
239 send_election(d,work->work_group, work->ElectionCriterion,
240 t-StartupTime,myname);
242 if (work->ElectionCount++ >= 4)
244 /* I won! now what :-) */
245 DEBUG(2,(">>> Won election on %s <<<\n",work->work_group));
247 work->RunningElection = False;
248 become_master(d, work);
256 /*******************************************************************
257 work out if I win an election
258 ******************************************************************/
259 static BOOL win_election(struct work_record *work,int version,uint32 criterion,
260 int timeup,char *name)
262 time_t t = time(NULL);
264 if (version > ELECTION_VERSION) return(False);
265 if (version < ELECTION_VERSION) return(True);
267 mycriterion = work->ElectionCriterion;
269 if (criterion > mycriterion) return(False);
270 if (criterion < mycriterion) return(True);
272 if (timeup > (t - StartupTime)) return(False);
273 if (timeup < (t - StartupTime)) return(True);
275 if (strcasecmp(myname,name) > 0) return(False);
281 /*******************************************************************
282 process a election packet
284 An election dynamically decides who will be the master.
285 ******************************************************************/
286 void process_election(struct packet_struct *p,char *buf)
288 struct dgram_packet *dgram = &p->packet.dgram;
289 struct in_addr ip = dgram->header.source_ip;
290 struct domain_record *d = find_domain(ip);
291 int version = CVAL(buf,0);
292 uint32 criterion = IVAL(buf,1);
293 int timeup = IVAL(buf,5)/1000;
295 struct work_record *work;
301 DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n",
302 name,version,criterion,timeup));
304 if (same_context(dgram)) return;
306 for (work = d->workgrouplist; work; work = work->next)
308 if (listening_name(work, &dgram->dest_name) &&
309 strequal(work->work_group, lp_workgroup()) &&
310 ip_equal(d->bcast_ip, bcast_ip))
312 if (win_election(work, version,criterion,timeup,name))
314 if (!work->RunningElection)
316 work->needelection = True;
317 work->ElectionCount=0;
322 work->needelection = False;
324 if (work->RunningElection)
326 work->RunningElection = False;
327 DEBUG(3,(">>> Lost election on %s <<<\n",work->work_group));
329 /* if we are the master then remove our masterly names */
332 become_nonmaster(d, work);
341 /****************************************************************************
342 checks whether a browser election is to be run on any workgroup
343 ***************************************************************************/
344 BOOL check_elections(void)
346 struct domain_record *d;
347 BOOL run_any_election = False;
349 for (d = domainlist; d; d = d->next)
351 struct work_record *work;
352 for (work = d->workgrouplist; work; work = work->next)
354 run_any_election |= work->RunningElection;
356 if (work->needelection && !work->RunningElection)
358 DEBUG(3,(">>> Starting election on %s <<<\n",work->work_group));
359 work->ElectionCount = 0;
360 work->RunningElection = True;
361 work->needelection = False;
365 return run_any_election;