source: trunk/samba/source/nmbd/nmbd_subnetdb.c @ 30

Last change on this file since 30 was 30, checked in by Paul Smedley, 14 years ago

Code updated to Samba 3.0.25rc2 level

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