r6369: update release notes
[Samba.git] / source / nmbd / nmbd_subnetdb.c
blobb53a6d7328fd037206c41032c34abe62e2e6271d
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
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.
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.
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.
22 Revision History:
26 #include "includes.h"
28 extern struct in_addr loopback_ip;
29 extern int ClientNMB;
30 extern int ClientDGRAM;
31 extern int global_nmb_port;
33 /* This is the broadcast subnets database. */
34 struct subnet_record *subnetlist = NULL;
36 /* Extra subnets - keep these separate so enumeration code doesn't
37 run onto it by mistake. */
39 struct subnet_record *unicast_subnet = NULL;
40 struct subnet_record *remote_broadcast_subnet = NULL;
41 struct subnet_record *wins_server_subnet = NULL;
43 extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
45 /****************************************************************************
46 Add a subnet into the list.
47 **************************************************************************/
49 static void add_subnet(struct subnet_record *subrec)
51 DLIST_ADD(subnetlist, subrec);
54 /* ************************************************************************** **
55 * Comparison routine for ordering the splay-tree based namelists assoicated
56 * with each subnet record.
58 * Input: Item - Pointer to the comparison key.
59 * Node - Pointer to a node the splay tree.
61 * Output: The return value will be <0 , ==0, or >0 depending upon the
62 * ordinal relationship of the two keys.
64 * ************************************************************************** **
66 static int namelist_entry_compare( ubi_trItemPtr Item, ubi_trNodePtr Node )
68 struct name_record *NR = (struct name_record *)Node;
70 if( DEBUGLVL( 10 ) ) {
71 struct nmb_name *Iname = (struct nmb_name *)Item;
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) );
79 return( memcmp( Item, &(NR->name), sizeof(struct nmb_name) ) );
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 ****************************************************************************/
88 void close_subnet(struct subnet_record *subrec)
90 DLIST_REMOVE(subnetlist, subrec);
92 if (subrec->dgram_sock != -1) {
93 close(subrec->dgram_sock);
94 subrec->dgram_sock = -1;
96 if (subrec->nmb_sock != -1) {
97 close(subrec->nmb_sock);
98 subrec->nmb_sock = -1;
102 /****************************************************************************
103 Create a subnet entry.
104 ****************************************************************************/
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)
110 struct subnet_record *subrec = NULL;
111 int nmb_sock, dgram_sock;
113 /* Check if we are creating a non broadcast subnet - if so don't create
114 sockets. */
116 if(type != NORMAL_SUBNET) {
117 nmb_sock = -1;
118 dgram_sock = -1;
119 } else {
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.
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) );
133 return NULL;
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) );
143 return NULL;
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");
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);
159 memset( (char *)subrec, '\0', sizeof(*subrec) );
160 (void)ubi_trInitTree( subrec->namelist,
161 namelist_entry_compare,
162 ubi_trOVERWRITE );
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);
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)));
177 subrec->namelist_changed = False;
178 subrec->work_changed = False;
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;
187 return subrec;
190 /****************************************************************************
191 Create a normal subnet
192 **************************************************************************/
194 struct subnet_record *make_normal_subnet(struct interface *iface)
196 struct subnet_record *subrec;
198 subrec = make_subnet(inet_ntoa(iface->ip), NORMAL_SUBNET,
199 iface->ip, iface->bcast, iface->nmask);
200 if (subrec) {
201 add_subnet(subrec);
203 return subrec;
206 /****************************************************************************
207 Create subnet entries.
208 **************************************************************************/
210 BOOL create_subnets(void)
212 int num_interfaces = iface_count();
213 int i;
214 struct in_addr unicast_ip, ipzero;
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();
225 num_interfaces = iface_count();
228 * Create subnets from all the local interfaces and thread them onto
229 * the linked list.
232 for (i = 0 ; i < num_interfaces; i++) {
233 struct interface *iface = get_interface(i);
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.
241 if (ip_equal(iface->ip, loopback_ip)) {
242 DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
243 continue;
246 if (!make_normal_subnet(iface))
247 return False;
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);
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.
267 unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET,
268 unicast_ip, unicast_ip, unicast_ip);
270 zero_ip(&ipzero);
272 remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
273 REMOTE_BROADCAST_SUBNET,
274 ipzero, ipzero, ipzero);
276 if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
277 return False;
280 * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
281 * the linked list.
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;
291 return True;
294 /*******************************************************************
295 Function to tell us if we can use the unicast subnet.
296 ******************************************************************/
298 BOOL we_are_a_wins_client(void)
300 if (wins_srv_count() > 0) {
301 return True;
304 return False;
307 /*******************************************************************
308 Access function used by NEXT_SUBNET_INCLUDING_UNICAST
309 ******************************************************************/
311 struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
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;
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 ******************************************************************/
328 struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
330 if(subrec == unicast_subnet) {
331 if(wins_server_subnet)
332 return wins_server_subnet;
333 else
334 return NULL;
337 if(wins_server_subnet && subrec == wins_server_subnet)
338 return NULL;
340 if((subrec->next == NULL) && we_are_a_wins_client())
341 return unicast_subnet;
342 else
343 return subrec->next;