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 ClientDGRAM;
34 extern int DEBUGLEVEL;
37 extern pstring myname;
39 /* machine comment for host announcements */
40 extern pstring ServerComment;
42 /* here are my election parameters */
44 extern time_t StartupTime;
46 #define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
48 #define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
50 extern struct subnet_record *subnetlist;
53 /*******************************************************************
54 occasionally check to see if the master browser is around
55 ******************************************************************/
56 void check_master_browser(void)
58 static time_t lastrun=0;
59 time_t t = time(NULL);
60 struct subnet_record *d;
62 if (!lastrun) lastrun = t;
63 if (t < lastrun + CHECK_TIME_MST_BROWSE * 60)
70 for (d = subnetlist; d; d = d->next)
72 struct work_record *work;
74 for (work = d->workgrouplist; work; work = work->next)
76 /* if we are not the browse master of a workgroup, and we can't
77 find a browser on the subnet, do something about it. */
81 queue_netbios_packet(ClientNMB,NMB_QUERY,CHECK_MASTER,
82 work->work_group,0x1d,0,
83 True,False,d->bcast_ip);
90 /*******************************************************************
91 what to do if a master browser DOESN't exist
92 ******************************************************************/
93 void browser_gone(char *work_name, struct in_addr ip)
95 struct subnet_record *d = find_domain(ip);
96 struct work_record *work = find_workgroupstruct(d, work_name, False);
98 if (!work || !d) return;
100 if (strequal(work->work_group, lp_workgroup()) &&
104 DEBUG(2,("Forcing election on %s %s\n",
105 work->work_group,inet_ntoa(d->bcast_ip)));
107 /* we can attempt to become master browser */
108 work->needelection = True;
112 /* XXXX note: this will delete entries that have been added in by
113 lmhosts as well. a flag to ensure that these are not deleted may
116 /* workgroup with no master browser is not the default workgroup:
117 it's also not on our subnet. therefore delete it: it can be
118 recreated dynamically */
120 send_election(d, work->work_group, 0, 0, myname);
121 remove_workgroup(d, work);
125 /****************************************************************************
126 send an election packet
127 **************************************************************************/
128 void send_election(struct subnet_record *d, char *group,uint32 criterion,
129 int timeup,char *name)
136 DEBUG(2,("Sending election to %s for workgroup %s\n",
137 inet_ntoa(d->bcast_ip),group));
139 bzero(outbuf,sizeof(outbuf));
141 CVAL(p,0) = 8; /* election */
144 CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
145 SIVAL(p,1,criterion);
146 SIVAL(p,5,timeup*1000); /* ms - despite the spec */
150 p = skip_string(p,1);
152 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
153 name,group,0,0x1e,d->bcast_ip,*iface_ip(d->bcast_ip));
157 /*******************************************************************
158 become the master browser
159 ******************************************************************/
160 static void become_master(struct subnet_record *d, struct work_record *work)
162 uint32 domain_type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_SERVER_UNIX | 0x00400000;
166 DEBUG(2,("Becoming master for %s\n",work->work_group));
168 work->ServerType |= SV_TYPE_MASTER_BROWSER;
169 work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
170 work->ElectionCriterion |= 0x5;
172 /* add browse, master and general names to database or register with WINS */
173 add_name_entry(MSBROWSE ,0x01,NB_ACTIVE|NB_GROUP);
174 add_name_entry(work->work_group,0x1d,NB_ACTIVE );
176 if (lp_domain_master())
178 DEBUG(4,("Domain master: adding names...\n"));
180 /* add domain master and domain member names or register with WINS */
181 add_name_entry(work->work_group,0x1b,NB_ACTIVE);
182 work->ServerType |= SV_TYPE_DOMAIN_MASTER;
184 if (lp_domain_logons())
186 work->ServerType |= SV_TYPE_DOMAIN_CTRL;
187 work->ServerType |= SV_TYPE_DOMAIN_MEMBER;
191 /* update our server status */
192 add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
193 add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
197 /* ask all servers on our local net to announce to us */
198 announce_request(work, d->bcast_ip);
203 /*******************************************************************
204 unbecome the master browser
205 ******************************************************************/
206 void become_nonmaster(struct subnet_record *d, struct work_record *work)
208 DEBUG(2,("Becoming non-master for %s\n",work->work_group));
210 work->ServerType &= ~SV_TYPE_MASTER_BROWSER;
211 work->ServerType &= ~SV_TYPE_DOMAIN_MASTER;
212 work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
214 work->ElectionCriterion &= ~0x4;
216 remove_name_entry(work->work_group,0x1b);
217 remove_name_entry(work->work_group,0x1d);
218 remove_name_entry(MSBROWSE ,0x01);
222 /*******************************************************************
224 ******************************************************************/
225 void run_elections(void)
227 time_t t = time(NULL);
228 static time_t lastime = 0;
230 struct subnet_record *d;
232 /* send election packets once a second */
233 if (lastime && t-lastime <= 0) return;
237 for (d = subnetlist; d; d = d->next)
239 struct work_record *work;
240 for (work = d->workgrouplist; work; work = work->next)
242 if (work->RunningElection)
244 send_election(d,work->work_group, work->ElectionCriterion,
245 t-StartupTime,myname);
247 if (work->ElectionCount++ >= 4)
249 /* I won! now what :-) */
250 DEBUG(2,(">>> Won election on %s %s <<<\n",
251 work->work_group,inet_ntoa(d->bcast_ip)));
253 work->RunningElection = False;
254 become_master(d, work);
262 /*******************************************************************
263 work out if I win an election
264 ******************************************************************/
265 static BOOL win_election(struct work_record *work,int version,uint32 criterion,
266 int timeup,char *name)
268 time_t t = time(NULL);
270 if (version > ELECTION_VERSION) return(False);
271 if (version < ELECTION_VERSION) return(True);
273 mycriterion = work->ElectionCriterion;
275 if (criterion > mycriterion) return(False);
276 if (criterion < mycriterion) return(True);
278 if (timeup > (t - StartupTime)) return(False);
279 if (timeup < (t - StartupTime)) return(True);
281 if (strcasecmp(myname,name) > 0) return(False);
287 /*******************************************************************
288 process a election packet
290 An election dynamically decides who will be the master.
291 ******************************************************************/
292 void process_election(struct packet_struct *p,char *buf)
294 struct dgram_packet *dgram = &p->packet.dgram;
295 struct in_addr ip = dgram->header.source_ip;
296 struct subnet_record *d = find_domain(ip);
297 int version = CVAL(buf,0);
298 uint32 criterion = IVAL(buf,1);
299 int timeup = IVAL(buf,5)/1000;
301 struct work_record *work;
307 DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n",
308 name,version,criterion,timeup));
310 if (same_context(dgram)) return;
312 for (work = d->workgrouplist; work; work = work->next)
314 if (listening_name(work, &dgram->dest_name) &&
315 strequal(work->work_group, lp_workgroup()) &&
318 if (win_election(work, version,criterion,timeup,name))
320 if (!work->RunningElection)
322 work->needelection = True;
323 work->ElectionCount=0;
328 work->needelection = False;
330 if (work->RunningElection)
332 work->RunningElection = False;
333 DEBUG(3,(">>> Lost election on %s %s <<<\n",
334 work->work_group,inet_ntoa(d->bcast_ip)));
336 /* if we are the master then remove our masterly names */
339 become_nonmaster(d, work);
348 /****************************************************************************
349 checks whether a browser election is to be run on any workgroup
350 ***************************************************************************/
351 BOOL check_elections(void)
353 struct subnet_record *d;
354 BOOL run_any_election = False;
356 for (d = subnetlist; d; d = d->next)
358 struct work_record *work;
359 for (work = d->workgrouplist; work; work = work->next)
361 run_any_election |= work->RunningElection;
363 if (work->needelection && !work->RunningElection)
365 DEBUG(3,(">>> Starting election on %s %s <<<\n",
366 work->work_group,inet_ntoa(d->bcast_ip)));
367 work->ElectionCount = 0;
368 work->RunningElection = True;
369 work->needelection = False;
373 return run_any_election;