source: branches/samba-3.0/source/nmbd/nmbd_become_lmb.c@ 105

Last change on this file since 105 was 1, checked in by Paul Smedley, 19 years ago

Initial code import

File size: 21.2 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 NBT netbios routines and daemon - version 2
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Luke Kenneth Casson Leighton 1994-1998
6 Copyright (C) Jeremy Allison 1994-2003
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22*/
23
24#include "includes.h"
25
26extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
27
28/*******************************************************************
29 Utility function to add a name to the unicast subnet, or add in
30 our IP address if it already exists.
31******************************************************************/
32
33void insert_permanent_name_into_unicast( struct subnet_record *subrec,
34 struct nmb_name *nmbname, uint16 nb_type )
35{
36 unstring name;
37 struct name_record *namerec;
38
39 if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL) {
40 pull_ascii_nstring(name, sizeof(name), nmbname->name);
41 /* The name needs to be created on the unicast subnet. */
42 (void)add_name_to_subnet( unicast_subnet, name,
43 nmbname->name_type, nb_type,
44 PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
45 } else {
46 /* The name already exists on the unicast subnet. Add our local
47 IP for the given broadcast subnet to the name. */
48 add_ip_to_name_record( namerec, subrec->myip);
49 }
50}
51
52/*******************************************************************
53 Utility function to remove a name from the unicast subnet.
54******************************************************************/
55
56static void remove_permanent_name_from_unicast( struct subnet_record *subrec,
57 struct nmb_name *nmbname )
58{
59 struct name_record *namerec;
60
61 if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) != NULL) {
62 /* Remove this broadcast subnet IP address from the name. */
63 remove_ip_from_name_record( namerec, subrec->myip);
64 if(namerec->data.num_ips == 0)
65 remove_name_from_namelist( unicast_subnet, namerec);
66 }
67}
68
69/*******************************************************************
70 Utility function always called to set our workgroup and server
71 state back to potential browser, or none.
72******************************************************************/
73
74static void reset_workgroup_state( struct subnet_record *subrec, const char *workgroup_name,
75 BOOL force_new_election )
76{
77 struct work_record *work;
78 struct server_record *servrec;
79 struct nmb_name nmbname;
80
81 if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL) {
82 DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
83subnet %s.\n", workgroup_name, subrec->subnet_name ));
84 return;
85 }
86
87 if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
88 DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
89in workgroup %s on subnet %s\n",
90 global_myname(), work->work_group, subrec->subnet_name));
91 work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
92 return;
93 }
94
95 /* Update our server status - remove any master flag and replace
96 it with the potential browser flag. */
97 servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
98 servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
99
100 /* Tell the namelist writer to write out a change. */
101 subrec->work_changed = True;
102
103 /* Reset our election flags. */
104 work->ElectionCriterion &= ~0x4;
105
106 work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
107
108 /* Forget who the local master browser was for
109 this workgroup. */
110
111 set_workgroup_local_master_browser_name( work, "");
112
113 /*
114 * Ensure the IP address of this subnet is not registered as one
115 * of the IP addresses of the WORKGROUP<1d> name on the unicast
116 * subnet. This undoes what we did below when we became a local
117 * master browser.
118 */
119
120 make_nmb_name(&nmbname, work->work_group, 0x1d);
121
122 remove_permanent_name_from_unicast( subrec, &nmbname);
123
124 if(force_new_election)
125 work->needelection = True;
126}
127
128/*******************************************************************
129 Unbecome the local master browser name release success function.
130******************************************************************/
131
132static void unbecome_local_master_success(struct subnet_record *subrec,
133 struct userdata_struct *userdata,
134 struct nmb_name *released_name,
135 struct in_addr released_ip)
136{
137 BOOL force_new_election = False;
138 unstring relname;
139
140 memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
141
142 DEBUG(3,("unbecome_local_master_success: released name %s.\n",
143 nmb_namestr(released_name)));
144
145 /* Now reset the workgroup and server state. */
146 pull_ascii_nstring(relname, sizeof(relname), released_name->name);
147 reset_workgroup_state( subrec, relname, force_new_election );
148
149 if( DEBUGLVL( 0 ) ) {
150 dbgtext( "*****\n\n" );
151 dbgtext( "Samba name server %s ", global_myname() );
152 dbgtext( "has stopped being a local master browser " );
153 dbgtext( "for workgroup %s ", relname );
154 dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
155 }
156
157}
158
159/*******************************************************************
160 Unbecome the local master browser name release fail function.
161******************************************************************/
162
163static void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec,
164 struct nmb_name *fail_name)
165{
166 struct name_record *namerec;
167 struct userdata_struct *userdata = rrec->userdata;
168 BOOL force_new_election = False;
169 unstring failname;
170
171 memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
172
173 DEBUG(0,("unbecome_local_master_fail: failed to release name %s. \
174Removing from namelist anyway.\n", nmb_namestr(fail_name)));
175
176 /* Do it anyway. */
177 namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
178 if(namerec)
179 remove_name_from_namelist(subrec, namerec);
180
181 /* Now reset the workgroup and server state. */
182 pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
183 reset_workgroup_state( subrec, failname, force_new_election );
184
185 if( DEBUGLVL( 0 ) ) {
186 dbgtext( "*****\n\n" );
187 dbgtext( "Samba name server %s ", global_myname() );
188 dbgtext( "has stopped being a local master browser " );
189 dbgtext( "for workgroup %s ", failname );
190 dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
191 }
192}
193
194/*******************************************************************
195 Utility function to remove the WORKGROUP<1d> name.
196******************************************************************/
197
198static void release_1d_name( struct subnet_record *subrec, const char *workgroup_name,
199 BOOL force_new_election)
200{
201 struct nmb_name nmbname;
202 struct name_record *namerec;
203
204 make_nmb_name(&nmbname, workgroup_name, 0x1d);
205 if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) {
206 struct userdata_struct *userdata;
207 size_t size = sizeof(struct userdata_struct) + sizeof(BOOL);
208
209 if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {
210 DEBUG(0,("release_1d_name: malloc fail.\n"));
211 return;
212 }
213
214 userdata->copy_fn = NULL;
215 userdata->free_fn = NULL;
216 userdata->userdata_len = sizeof(BOOL);
217 memcpy((char *)userdata->data, &force_new_election, sizeof(BOOL));
218
219 release_name(subrec, namerec,
220 unbecome_local_master_success,
221 unbecome_local_master_fail,
222 userdata);
223
224 zero_free(userdata, size);
225 }
226}
227
228/*******************************************************************
229 Unbecome the local master browser MSBROWSE name release success function.
230******************************************************************/
231
232static void release_msbrowse_name_success(struct subnet_record *subrec,
233 struct userdata_struct *userdata,
234 struct nmb_name *released_name,
235 struct in_addr released_ip)
236{
237 DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
238 nmb_namestr(released_name), subrec->subnet_name ));
239
240 /* Remove the permanent MSBROWSE name added into the unicast subnet. */
241 remove_permanent_name_from_unicast( subrec, released_name);
242}
243
244/*******************************************************************
245 Unbecome the local master browser MSBROWSE name release fail function.
246******************************************************************/
247
248static void release_msbrowse_name_fail( struct subnet_record *subrec,
249 struct response_record *rrec,
250 struct nmb_name *fail_name)
251{
252 struct name_record *namerec;
253
254 DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
255 nmb_namestr(fail_name), subrec->subnet_name ));
256
257 /* Release the name anyway. */
258 namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
259 if(namerec)
260 remove_name_from_namelist(subrec, namerec);
261
262 /* Remove the permanent MSBROWSE name added into the unicast subnet. */
263 remove_permanent_name_from_unicast( subrec, fail_name);
264}
265
266/*******************************************************************
267 Unbecome the local master browser. If force_new_election is true, restart
268 the election process after we've unbecome the local master.
269******************************************************************/
270
271void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work,
272 BOOL force_new_election)
273{
274 struct name_record *namerec;
275 struct nmb_name nmbname;
276
277 /* Sanity check. */
278
279 DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \
280on subnet %s\n",work->work_group, subrec->subnet_name));
281
282 if(find_server_in_workgroup( work, global_myname()) == NULL) {
283 DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
284in workgroup %s on subnet %s\n",
285 global_myname(), work->work_group, subrec->subnet_name));
286 work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
287 return;
288 }
289
290 /* Set the state to unbecoming. */
291 work->mst_state = MST_UNBECOMING_MASTER;
292
293 /*
294 * Release the WORKGROUP<1d> name asap to allow another machine to
295 * claim it.
296 */
297
298 release_1d_name( subrec, work->work_group, force_new_election);
299
300 /* Deregister any browser names we may have. */
301 make_nmb_name(&nmbname, MSBROWSE, 0x1);
302 if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) {
303 release_name(subrec, namerec,
304 release_msbrowse_name_success,
305 release_msbrowse_name_fail,
306 NULL);
307 }
308
309 /*
310 * Ensure we have sent and processed these release packets
311 * before returning - we don't want to process any election
312 * packets before dealing with the 1d release.
313 */
314
315 retransmit_or_expire_response_records(time(NULL));
316}
317
318/****************************************************************************
319 Success in registering the WORKGROUP<1d> name.
320 We are now *really* a local master browser.
321 ****************************************************************************/
322
323static void become_local_master_stage2(struct subnet_record *subrec,
324 struct userdata_struct *userdata,
325 struct nmb_name *registered_name,
326 uint16 nb_flags,
327 int ttl, struct in_addr registered_ip)
328{
329 int i = 0;
330 struct server_record *sl;
331 struct work_record *work;
332 struct server_record *servrec;
333 unstring regname;
334
335 pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
336 work = find_workgroup_on_subnet( subrec, regname);
337
338 if(!work) {
339 DEBUG(0,("become_local_master_stage2: Error - cannot find \
340workgroup %s on subnet %s\n", regname, subrec->subnet_name));
341 return;
342 }
343
344 if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
345 DEBUG(0,("become_local_master_stage2: Error - cannot find server %s \
346in workgroup %s on subnet %s\n",
347 global_myname(), regname, subrec->subnet_name));
348 work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
349 return;
350 }
351
352 DEBUG(3,("become_local_master_stage2: registered as master browser for workgroup %s \
353on subnet %s\n", work->work_group, subrec->subnet_name));
354
355 work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
356
357 /* update our server status */
358 servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
359 servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
360
361 /* Tell the namelist writer to write out a change. */
362 subrec->work_changed = True;
363
364 /* Add this name to the workgroup as local master browser. */
365 set_workgroup_local_master_browser_name( work, global_myname());
366
367 /* Count the number of servers we have on our list. If it's
368 less than 10 (just a heuristic) request the servers
369 to announce themselves.
370 */
371 for( sl = work->serverlist; sl != NULL; sl = sl->next)
372 i++;
373
374 if (i < 10) {
375 /* Ask all servers on our local net to announce to us. */
376 broadcast_announce_request(subrec, work);
377 }
378
379 /*
380 * Now we are a local master on a broadcast subnet, we need to add
381 * the WORKGROUP<1d> name to the unicast subnet so that we can answer
382 * unicast requests sent to this name. We can create this name directly on
383 * the unicast subnet as a WINS server always returns true when registering
384 * this name, and discards the registration. We use the number of IP