r6225: get rid of warnings from my compiler about nested externs
[nivanova/samba-autobuild/.git] / source3 / nmbd / nmbd_subnetdb.c
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-1998
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    Revision History:
23
24 */
25
26 #include "includes.h"
27
28 extern struct in_addr loopback_ip;
29 extern int ClientNMB;
30 extern int ClientDGRAM;
31 extern int global_nmb_port;
32
33 /* This is the broadcast subnets database. */
34 struct subnet_record *subnetlist = NULL;
35
36 /* Extra subnets - keep these separate so enumeration code doesn't
37    run onto it by mistake. */
38
39 struct subnet_record *unicast_subnet = NULL;
40 struct subnet_record *remote_broadcast_subnet = NULL;
41 struct subnet_record *wins_server_subnet = NULL;
42
43 extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
44
45 /****************************************************************************
46   Add a subnet into the list.
47   **************************************************************************/
48
49 static void add_subnet(struct subnet_record *subrec)
50 {
51         DLIST_ADD(subnetlist, subrec);
52 }
53
54 /* ************************************************************************** **
55  * Comparison routine for ordering the splay-tree based namelists assoicated
56  * with each subnet record.
57  *
58  *  Input:  Item  - Pointer to the comparison key.
59  *          Node  - Pointer to a node the splay tree.
60  *
61  *  Output: The return value will be <0 , ==0, or >0 depending upon the
62  *          ordinal relationship of the two keys.
63  *
64  * ************************************************************************** **
65  */
66 static int namelist_entry_compare( ubi_trItemPtr Item, ubi_trNodePtr Node )
67 {
68         struct name_record *NR = (struct name_record *)Node;
69
70         if( DEBUGLVL( 10 ) ) {
71                 struct nmb_name *Iname = (struct nmb_name *)Item;
72
73                 Debug1( "nmbd_subnetdb:namelist_entry_compare()\n" );
74                 Debug1( "%d == memcmp( \"%s\", \"%s\", %d )\n",
75                         memcmp( Item, &(NR->name), sizeof(struct nmb_name) ),
76                         nmb_namestr(Iname), nmb_namestr(&NR->name), (int)sizeof(struct nmb_name) );
77         }
78
79         return( memcmp( Item, &(NR->name), sizeof(struct nmb_name) ) ); 
80 }
81
82 /****************************************************************************
83 stop listening on a subnet
84 we don't free the record as we don't have proper reference counting for it
85 yet and it may be in use by a response record
86   ****************************************************************************/
87
88 void close_subnet(struct subnet_record *subrec)
89 {
90         DLIST_REMOVE(subnetlist, subrec);
91
92         if (subrec->dgram_sock != -1) {
93                 close(subrec->dgram_sock);
94                 subrec->dgram_sock = -1;
95         }
96         if (subrec->nmb_sock != -1) {
97                 close(subrec->nmb_sock);
98                 subrec->nmb_sock = -1;
99         }
100 }
101
102 /****************************************************************************
103   Create a subnet entry.
104   ****************************************************************************/
105
106 static struct subnet_record *make_subnet(const char *name, enum subnet_type type,
107                                          struct in_addr myip, struct in_addr bcast_ip, 
108                                          struct in_addr mask_ip)
109 {
110         struct subnet_record *subrec = NULL;
111         int nmb_sock, dgram_sock;
112
113         /* Check if we are creating a non broadcast subnet - if so don't create
114                 sockets.  */
115
116         if(type != NORMAL_SUBNET) {
117                 nmb_sock = -1;
118                 dgram_sock = -1;
119         } else {
120                 /*
121                  * Attempt to open the sockets on port 137/138 for this interface
122                  * and bind them.
123                  * Fail the subnet creation if this fails.
124                  */
125
126                 if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr,True)) == -1) {
127                         if( DEBUGLVL( 0 ) ) {
128                                 Debug1( "nmbd_subnetdb:make_subnet()\n" );
129                                 Debug1( "  Failed to open nmb socket on interface %s ", inet_ntoa(myip) );
130                                 Debug1( "for port %d.  ", global_nmb_port );
131                                 Debug1( "Error was %s\n", strerror(errno) );
132                         }
133                         return NULL;
134                 }
135
136                 if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr,True)) == -1) {
137                         if( DEBUGLVL( 0 ) ) {
138                                 Debug1( "nmbd_subnetdb:make_subnet()\n" );
139                                 Debug1( "  Failed to open dgram socket on interface %s ", inet_ntoa(myip) );
140                                 Debug1( "for port %d.  ", DGRAM_PORT );
141                                 Debug1( "Error was %s\n", strerror(errno) );
142                         }
143                         return NULL;
144                 }
145
146                 /* Make sure we can broadcast from these sockets. */
147                 set_socket_options(nmb_sock,"SO_BROADCAST");
148                 set_socket_options(dgram_sock,"SO_BROADCAST");
149         }
150
151         subrec = SMB_MALLOC_P(struct subnet_record);
152         if (!subrec) {
153                 DEBUG(0,("make_subnet: malloc fail !\n"));
154                 close(nmb_sock);
155                 close(dgram_sock);
156                 return(NULL);
157         }
158   
159         memset( (char *)subrec, '\0', sizeof(*subrec) );
160         (void)ubi_trInitTree( subrec->namelist,
161                         namelist_entry_compare,
162                         ubi_trOVERWRITE );
163
164         if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) {
165                 DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
166                 close(nmb_sock);
167                 close(dgram_sock);
168                 ZERO_STRUCTP(subrec);
169                 SAFE_FREE(subrec);
170                 return(NULL);
171         }
172
173         DEBUG(2, ("making subnet name:%s ", name ));
174         DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
175         DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
176  
177         subrec->namelist_changed = False;
178         subrec->work_changed = False;
179  
180         subrec->bcast_ip = bcast_ip;
181         subrec->mask_ip  = mask_ip;
182         subrec->myip = myip;
183         subrec->type = type;
184         subrec->nmb_sock = nmb_sock;
185         subrec->dgram_sock = dgram_sock;
186   
187         return subrec;
188 }
189
190 /****************************************************************************
191   Create a normal subnet
192 **************************************************************************/
193
194 struct subnet_record *make_normal_subnet(struct interface *iface)
195 {
196         struct subnet_record *subrec;
197
198         subrec = make_subnet(inet_ntoa(iface->ip), NORMAL_SUBNET,
199                              iface->ip, iface->bcast, iface->nmask);
200         if (subrec) {
201                 add_subnet(subrec);
202         }
203         return subrec;
204 }
205
206 /****************************************************************************
207   Create subnet entries.
208 **************************************************************************/
209
210 BOOL create_subnets(void)
211 {    
212         int num_interfaces = iface_count();
213         int i;
214         struct in_addr unicast_ip, ipzero;
215
216         if(num_interfaces == 0) {
217                 DEBUG(0,("create_subnets: No local interfaces !\n"));
218                 DEBUG(0,("create_subnets: Waiting for an interface to appear ...\n"));
219                 while (iface_count() == 0) {
220                         sleep(5);
221                         load_interfaces();
222                 }
223         }
224
225         num_interfaces = iface_count();
226
227         /* 
228          * Create subnets from all the local interfaces and thread them onto
229          * the linked list. 
230          */
231
232         for (i = 0 ; i < num_interfaces; i++) {
233                 struct interface *iface = get_interface(i);
234
235                 /*
236                  * We don't want to add a loopback interface, in case
237                  * someone has added 127.0.0.1 for smbd, nmbd needs to
238                  * ignore it here. JRA.
239                  */
240
241                 if (ip_equal(iface->ip, loopback_ip)) {
242                         DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
243                         continue;
244                 }
245
246                 if (!make_normal_subnet(iface))
247                         return False;
248         }
249
250         if (lp_we_are_a_wins_server()) {
251                 /* Pick the first interface ip address as the WINS server ip. */
252                 unicast_ip = *iface_n_ip(0);
253         } else {
254                 /* note that we do not set the wins server IP here. We just
255                         set it at zero and let the wins registration code cope
256                         with getting the IPs right for each packet */
257                 zero_ip(&unicast_ip);
258         }
259
260         /*
261          * Create the unicast and remote broadcast subnets.
262          * Don't put these onto the linked list.
263          * The ip address of the unicast subnet is set to be
264          * the WINS server address, if it exists, or ipzero if not.
265          */
266
267         unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET, 
268                                 unicast_ip, unicast_ip, unicast_ip);
269
270         zero_ip(&ipzero);
271
272         remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
273                                 REMOTE_BROADCAST_SUBNET,
274                                 ipzero, ipzero, ipzero);
275
276         if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
277                 return False;
278
279         /* 
280          * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
281          * the linked list.
282          */
283
284         if (lp_we_are_a_wins_server()) {
285                 if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
286                                                 WINS_SERVER_SUBNET, 
287                                                 ipzero, ipzero, ipzero )) == NULL )
288                         return False;
289         }
290
291         return True;
292 }
293
294 /*******************************************************************
295 Function to tell us if we can use the unicast subnet.
296 ******************************************************************/
297
298 BOOL we_are_a_wins_client(void)
299 {
300         if (wins_srv_count() > 0) {
301                 return True;
302         }
303
304         return False;
305 }
306
307 /*******************************************************************
308 Access function used by NEXT_SUBNET_INCLUDING_UNICAST
309 ******************************************************************/
310
311 struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
312 {
313         if(subrec == unicast_subnet)
314                 return NULL;
315         else if((subrec->next == NULL) && we_are_a_wins_client())
316                 return unicast_subnet;
317         else
318                 return subrec->next;
319 }
320
321 /*******************************************************************
322  Access function used by retransmit_or_expire_response_records() in
323  nmbd_packets.c. Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>
324  Needed when we need to enumerate all the broadcast, unicast and
325  WINS subnets.
326 ******************************************************************/
327
328 struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
329 {
330         if(subrec == unicast_subnet) {
331                 if(wins_server_subnet)
332                         return wins_server_subnet;
333                 else
334                         return NULL;
335         }
336
337         if(wins_server_subnet && subrec == wins_server_subnet)
338                 return NULL;
339
340         if((subrec->next == NULL) && we_are_a_wins_client())
341                 return unicast_subnet;
342         else
343                 return subrec->next;
344 }