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
31 extern int ClientDGRAM
;
33 extern int DEBUGLEVEL
;
36 extern pstring myname
;
38 /* machine comment for host announcements */
39 extern pstring ServerComment
;
41 /* here are my election parameters */
43 extern time_t StartupTime
;
45 #define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
47 extern struct subnet_record
*subnetlist
;
50 /*******************************************************************
51 occasionally check to see if the master browser is around
52 ******************************************************************/
53 void check_master_browser(void)
55 static time_t lastrun
=0;
56 time_t t
= time(NULL
);
57 struct subnet_record
*d
;
59 if (!lastrun
) lastrun
= t
;
60 if (t
< lastrun
+ CHECK_TIME_MST_BROWSE
* 60)
66 for (d
= subnetlist
; d
; d
= d
->next
)
68 struct work_record
*work
;
70 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
72 /* if we are not the browse master of a workgroup, and we can't
73 find a browser on the subnet, do something about it. */
77 queue_netbios_packet(d
,ClientNMB
,NMB_QUERY
,NAME_QUERY_MST_CHK
,
78 work
->work_group
,0x1d,0,0,
79 True
,False
,d
->bcast_ip
);
86 /*******************************************************************
87 what to do if a master browser DOESN't exist
88 ******************************************************************/
89 void browser_gone(char *work_name
, struct in_addr ip
)
91 struct subnet_record
*d
= find_subnet(ip
);
92 struct work_record
*work
= find_workgroupstruct(d
, work_name
, False
);
94 if (!work
|| !d
) return;
96 if (strequal(work
->work_group
, lp_workgroup()) &&
97 ismybcast(d
->bcast_ip
))
100 DEBUG(2,("Forcing election on %s %s\n",
101 work
->work_group
,inet_ntoa(d
->bcast_ip
)));
103 /* we can attempt to become master browser */
104 work
->needelection
= True
;
108 /* XXXX note: this will delete entries that have been added in by
109 lmhosts as well. a flag to ensure that these are not deleted may
112 /* workgroup with no master browser is not the default workgroup:
113 it's also not on our subnet. therefore delete it: it can be
114 recreated dynamically */
116 send_election(d
, work
->work_group
, 0, 0, myname
);
117 remove_workgroup(d
, work
);
122 /****************************************************************************
123 send an election packet
124 **************************************************************************/
125 void send_election(struct subnet_record
*d
, char *group
,uint32 criterion
,
126 int timeup
,char *name
)
133 DEBUG(2,("Sending election to %s for workgroup %s\n",
134 inet_ntoa(d
->bcast_ip
),group
));
136 bzero(outbuf
,sizeof(outbuf
));
138 CVAL(p
,0) = 8; /* election */
141 CVAL(p
,0) = (criterion
== 0 && timeup
== 0) ? 0 : ELECTION_VERSION
;
142 SIVAL(p
,1,criterion
);
143 SIVAL(p
,5,timeup
*1000); /* ms - despite the spec */
147 p
= skip_string(p
,1);
149 send_mailslot_reply(BROWSE_MAILSLOT
,ClientDGRAM
,outbuf
,PTR_DIFF(p
,outbuf
),
150 name
,group
,0,0x1e,d
->bcast_ip
,*iface_ip(d
->bcast_ip
));
154 /*******************************************************************
155 become the master browser
156 ******************************************************************/
157 static void become_master(struct subnet_record
*d
, struct work_record
*work
)
159 uint32 domain_type
= SV_TYPE_DOMAIN_ENUM
| SV_TYPE_SERVER_UNIX
| 0x00400000;
163 DEBUG(2,("Becoming master for %s\n",work
->work_group
));
165 work
->ServerType
|= SV_TYPE_MASTER_BROWSER
;
166 work
->ServerType
&= ~SV_TYPE_POTENTIAL_BROWSER
;
167 work
->ElectionCriterion
|= 0x5;
169 /* add browse, master and general names to database or register with WINS */
170 add_my_name_entry(d
,MSBROWSE
,0x01,NB_ACTIVE
|NB_GROUP
);
171 add_my_name_entry(d
,work
->work_group
,0x1d,NB_ACTIVE
);
173 if (lp_domain_master())
175 DEBUG(4,("Domain master: adding names...\n"));
177 /* add domain master and domain member names or register with WINS */
178 add_my_name_entry(d
,work
->work_group
,0x1b,NB_ACTIVE
);
180 work
->ServerType
|= SV_TYPE_DOMAIN_MASTER
;
182 if (lp_domain_logons())
184 work
->ServerType
|= SV_TYPE_DOMAIN_CTRL
;
185 work
->ServerType
|= SV_TYPE_DOMAIN_MEMBER
;
189 /* update our server status */
190 add_server_entry(d
,work
,work
->work_group
,domain_type
,0,myname
,True
);
191 add_server_entry(d
,work
,myname
,work
->ServerType
,0,ServerComment
,True
);
195 /* ask all servers on our local net to announce to us */
196 announce_request(work
, d
->bcast_ip
);
201 /*******************************************************************
202 unbecome the master browser. initates removal of necessary netbios
203 names, and tells the world that we are no longer a master browser.
204 ******************************************************************/
205 void become_nonmaster(struct subnet_record
*d
, struct work_record
*work
,
208 int new_server_type
= work
->ServerType
;
210 DEBUG(2,("Becoming non-master for %s\n",work
->work_group
));
212 /* can only remove master or domain types with this function */
213 remove_type
&= ~(SV_TYPE_MASTER_BROWSER
|SV_TYPE_DOMAIN_MASTER
);
215 /* unbecome a master browser; unbecome a domain master, too :-( */
216 if (remove_type
& SV_TYPE_MASTER_BROWSER
)
217 remove_type
|= SV_TYPE_DOMAIN_MASTER
;
219 new_server_type
&= ~remove_type
;
221 if (!(new_server_type
& (SV_TYPE_MASTER_BROWSER
|SV_TYPE_DOMAIN_MASTER
)))
223 /* no longer a master browser of any sort */
225 work
->ServerType
|= SV_TYPE_POTENTIAL_BROWSER
;
226 work
->ElectionCriterion
&= ~0x4;
228 /* announce ourselves as no longer active as a master browser. */
229 announce_server(d
, work
, work
->work_group
, myname
, 0, 0);
230 remove_name_entry(d
,MSBROWSE
,0x01);
233 work
->ServerType
= new_server_type
;
235 if (!(work
->ServerType
& SV_TYPE_DOMAIN_MASTER
))
236 remove_name_entry(d
,work
->work_group
,0x1b);
238 if (!(work
->ServerType
& SV_TYPE_DOMAIN_MASTER
))
239 remove_name_entry(d
,work
->work_group
,0x1d);
243 /*******************************************************************
245 ******************************************************************/
246 void run_elections(void)
248 time_t t
= time(NULL
);
249 static time_t lastime
= 0;
251 struct subnet_record
*d
;
253 /* send election packets once a second */
254 if (lastime
&& t
-lastime
<= 0) return;
258 for (d
= subnetlist
; d
; d
= d
->next
)
260 struct work_record
*work
;
261 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
263 if (work
->RunningElection
)
265 send_election(d
,work
->work_group
, work
->ElectionCriterion
,
266 t
-StartupTime
,myname
);
268 if (work
->ElectionCount
++ >= 4)
270 /* I won! now what :-) */
271 DEBUG(2,(">>> Won election on %s %s <<<\n",
272 work
->work_group
,inet_ntoa(d
->bcast_ip
)));
274 work
->RunningElection
= False
;
275 become_master(d
, work
);
283 /*******************************************************************
284 work out if I win an election
285 ******************************************************************/
286 static BOOL
win_election(struct work_record
*work
,int version
,uint32 criterion
,
287 int timeup
,char *name
)
289 time_t t
= time(NULL
);
291 if (version
> ELECTION_VERSION
) return(False
);
292 if (version
< ELECTION_VERSION
) return(True
);
294 mycriterion
= work
->ElectionCriterion
;
296 if (criterion
> mycriterion
) return(False
);
297 if (criterion
< mycriterion
) return(True
);
299 if (timeup
> (t
- StartupTime
)) return(False
);
300 if (timeup
< (t
- StartupTime
)) return(True
);
302 if (strcasecmp(myname
,name
) > 0) return(False
);
308 /*******************************************************************
309 process a election packet
311 An election dynamically decides who will be the master.
312 ******************************************************************/
313 void process_election(struct packet_struct
*p
,char *buf
)
315 struct dgram_packet
*dgram
= &p
->packet
.dgram
;
316 struct in_addr ip
= dgram
->header
.source_ip
;
317 struct subnet_record
*d
= find_subnet(ip
);
318 int version
= CVAL(buf
,0);
319 uint32 criterion
= IVAL(buf
,1);
320 int timeup
= IVAL(buf
,5)/1000;
322 struct work_record
*work
;
328 DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n",
329 name
,version
,criterion
,timeup
));
331 if (same_context(dgram
)) return;
333 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
335 if (listening_name(work
, &dgram
->dest_name
) &&
336 strequal(work
->work_group
, lp_workgroup()) &&
339 if (win_election(work
, version
,criterion
,timeup
,name
))
341 if (!work
->RunningElection
)
343 work
->needelection
= True
;
344 work
->ElectionCount
=0;
349 work
->needelection
= False
;
351 if (work
->RunningElection
)
353 work
->RunningElection
= False
;
354 DEBUG(3,(">>> Lost election on %s %s <<<\n",
355 work
->work_group
,inet_ntoa(d
->bcast_ip
)));
357 /* if we are the master then remove our masterly names */
360 become_nonmaster(d
, work
,
361 SV_TYPE_MASTER_BROWSER
|SV_TYPE_DOMAIN_MASTER
);
370 /****************************************************************************
371 checks whether a browser election is to be run on any workgroup
372 ***************************************************************************/
373 BOOL
check_elections(void)
375 struct subnet_record
*d
;
376 BOOL run_any_election
= False
;
378 for (d
= subnetlist
; d
; d
= d
->next
)
380 struct work_record
*work
;
381 for (work
= d
->workgrouplist
; work
; work
= work
->next
)
383 run_any_election
|= work
->RunningElection
;
385 if (work
->needelection
&& !work
->RunningElection
)
387 DEBUG(3,(">>> Starting election on %s %s <<<\n",
388 work
->work_group
,inet_ntoa(d
->bcast_ip
)));
389 work
->ElectionCount
= 0;
390 work
->RunningElection
= True
;
391 work
->needelection
= False
;
395 return run_any_election
;