summaryrefslogtreecommitdiff
path: root/source3/nmbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/nmbd')
-rw-r--r--source3/nmbd/nmbd.c13
-rw-r--r--source3/nmbd/nmbd_incomingrequests.c316
-rw-r--r--source3/nmbd/nmbd_mynames.c93
-rw-r--r--source3/nmbd/nmbd_namelistdb.c2
-rw-r--r--source3/nmbd/nmbd_nameregister.c539
-rw-r--r--source3/nmbd/nmbd_namerelease.c366
-rw-r--r--source3/nmbd/nmbd_packets.c232
-rw-r--r--source3/nmbd/nmbd_responserecordsdb.c12
-rw-r--r--source3/nmbd/nmbd_subnetdb.c58
9 files changed, 802 insertions, 829 deletions
diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c
index f698b396b2..06d6bc3bb3 100644
--- a/source3/nmbd/nmbd.c
+++ b/source3/nmbd/nmbd.c
@@ -53,8 +53,8 @@ static void terminate(void)
/* Write out wins.dat file if samba is a WINS server */
wins_write_database(False);
- /* Remove all SELF registered names. */
- release_my_names();
+ /* Remove all SELF registered names from WINS */
+ release_wins_names();
/* Announce all server entries as 0 time-to-live, 0 type. */
announce_my_servers_removed();
@@ -293,15 +293,6 @@ static BOOL reload_nmbd_services(BOOL test)
reload_nmbd_services( True );
}
- /* Do a sanity check for a misconfigured nmbd */
- if( lp_wins_support() && wins_srv_count() ) {
- if( DEBUGLVL(0) ) {
- dbgtext( "ERROR: 'wins support = true' and 'wins server = <server>'\n" );
- dbgtext( "are conflicting settings. nmbd aborting.\n" );
- }
- exit(10);
- }
-
return(ret);
}
diff --git a/source3/nmbd/nmbd_incomingrequests.c b/source3/nmbd/nmbd_incomingrequests.c
index 3f2b921074..834f237a2c 100644
--- a/source3/nmbd/nmbd_incomingrequests.c
+++ b/source3/nmbd/nmbd_incomingrequests.c
@@ -449,175 +449,151 @@ For broadcast name queries:
void process_name_query_request(struct subnet_record *subrec, struct packet_struct *p)
{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct nmb_name *question = &nmb->question.question_name;
- int name_type = question->name_type;
- BOOL bcast = nmb->header.nm_flags.bcast;
- int ttl=0;
- int rcode = 0;
- char *prdata = NULL;
- char rdata[6];
- BOOL success = False;
- struct name_record *namerec = NULL;
- int reply_data_len = 0;
- int i;
-
- DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n",
- inet_ntoa(p->ip), subrec->subnet_name, nmb_namestr(question)));
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ int name_type = question->name_type;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ int ttl=0;
+ int rcode = 0;
+ char *prdata = NULL;
+ char rdata[6];
+ BOOL success = False;
+ struct name_record *namerec = NULL;
+ int reply_data_len = 0;
+ int i;
+
+ DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n",
+ inet_ntoa(p->ip), subrec->subnet_name, nmb_namestr(question)));
- /* Look up the name in the cache - if the request is a broadcast request that
- came from a subnet we don't know about then search all the broadcast subnets
- for a match (as we don't know what interface the request came in on). */
-
- if(subrec == remote_broadcast_subnet)
- namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME);
- else
- namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
-
-
- /* Check if it is a name that expired */
- if( namerec
- && ( (namerec->data.death_time != PERMANENT_TTL)
- && (namerec->data.death_time < p->timestamp) ) )
- {
- DEBUG(5,("process_name_query_request: expired name %s\n", nmb_namestr(&namerec->name)));
- namerec = NULL;
- }
-
- if (namerec)
- {
-
- /*
- * Always respond to unicast queries.
- * Don't respond to broadcast queries unless the query is for
- * a name we own, a Primary Domain Controller name, or a WINS_PROXY
- * name with type 0 or 0x20. WINS_PROXY names are only ever added
- * into the namelist if we were configured as a WINS proxy.
- */
-
- if( !bcast
- || ( bcast
- && ( (name_type == 0x1b)
- || (namerec->data.source == SELF_NAME)
- || (namerec->data.source == PERMANENT_NAME)
- || ( (namerec->data.source == WINS_PROXY_NAME)
- && ( (name_type == 0) || (name_type == 0x20) )
- )
- )
- )
- )
- {
-
- /* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY,
- or it's a Domain Master type. */
-
- /*
- * If this is a WINS_PROXY_NAME, then ceck that none of the IP
- * addresses we are returning is on the same broadcast subnet
- * as the requesting packet. If it is then don't reply as the
- * actual machine will be replying also and we don't want two
- * replies to a broadcast query.
- */
-
- if( namerec->data.source == WINS_PROXY_NAME )
- {
- for( i = 0; i < namerec->data.num_ips; i++)
- {
- if(same_net( namerec->data.ip[i], subrec->myip, subrec->mask_ip ))
- {
- DEBUG(5,("process_name_query_request: name %s is a WINS proxy name and is also \
-on the same subnet (%s) as the requestor. Not replying.\n",
- nmb_namestr(&namerec->name), subrec->subnet_name ));
- return;
- }
- }
- }
-
- ttl = (namerec->data.death_time != PERMANENT_TTL) ?
- namerec->data.death_time - p->timestamp : lp_max_ttl();
-
- /* Copy all known ip addresses into the return data. */
- /* Optimise for the common case of one IP address so
- we don't need a malloc. */
-
- if( namerec->data.num_ips == 1 )
- prdata = rdata;
- else
- {
- if((prdata = (char *)malloc( namerec->data.num_ips * 6 )) == NULL)
- {
- DEBUG(0,("process_name_query_request: malloc fail !\n"));
- return;
- }
- }
-
- for( i = 0; i < namerec->data.num_ips; i++ )
- {
- set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
- putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
- }
-
- sort_query_replies(prdata, i, p->ip);
-
- reply_data_len = namerec->data.num_ips * 6;
- success = True;
- }
- }
-
- /*
- * If a machine is broadcasting a name lookup request and we have lp_wins_proxy()
- * set we should initiate a WINS query here. On success we add the resolved name
- * into our namelist with a type of WINS_PROXY_NAME and then reply to the query.
- */
-
- if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() &&
- bcast && (subrec != remote_broadcast_subnet))
- {
- make_wins_proxy_name_query_request( subrec, p, question );
- return;
- }
-
- if (!success && bcast)
- {
- if(prdata != rdata)
- SAFE_FREE(prdata);
- return; /* Never reply with a negative response to broadcasts. */
- }
-
- /*
- * Final check. From observation, if a unicast packet is sent
- * to a non-WINS server with the recursion desired bit set
- * then never send a negative response.
- */
-
- if(!success && !bcast && nmb->header.nm_flags.recursion_desired)
- {
- if(prdata != rdata)
- SAFE_FREE(prdata);
- return;
- }
-
- if (success)
- {
- rcode = 0;
- DEBUG(3,("OK\n"));
- }
- else
- {
- rcode = NAM_ERR;
- DEBUG(3,("UNKNOWN\n"));
- }
-
- /* See rfc1002.txt 4.2.13. */
-
- reply_netbios_packet(p, /* Packet to reply to. */
- rcode, /* Result code. */
- NMB_QUERY, /* nmbd type code. */
- NMB_NAME_QUERY_OPCODE, /* opcode. */
- ttl, /* ttl. */
- prdata, /* data to send. */
- reply_data_len); /* data length. */
-
- if(prdata != rdata)
- SAFE_FREE(prdata);
+ /* Look up the name in the cache - if the request is a broadcast request that
+ came from a subnet we don't know about then search all the broadcast subnets
+ for a match (as we don't know what interface the request came in on). */
+
+ if(subrec == remote_broadcast_subnet)
+ namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME);
+ else
+ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
+
+ /* Check if it is a name that expired */
+ if (namerec &&
+ ((namerec->data.death_time != PERMANENT_TTL) &&
+ (namerec->data.death_time < p->timestamp))) {
+ DEBUG(5,("process_name_query_request: expired name %s\n", nmb_namestr(&namerec->name)));
+ namerec = NULL;
+ }
+
+ if (namerec) {
+ /*
+ * Always respond to unicast queries.
+ * Don't respond to broadcast queries unless the query is for
+ * a name we own, a Primary Domain Controller name, or a WINS_PROXY
+ * name with type 0 or 0x20. WINS_PROXY names are only ever added
+ * into the namelist if we were configured as a WINS proxy.
+ */
+
+ if (!bcast ||
+ (bcast && ((name_type == 0x1b) ||
+ (namerec->data.source == SELF_NAME) ||
+ (namerec->data.source == PERMANENT_NAME) ||
+ ((namerec->data.source == WINS_PROXY_NAME) &&
+ ((name_type == 0) || (name_type == 0x20)))))) {
+ /* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY,
+ or it's a Domain Master type. */
+
+ /*
+ * If this is a WINS_PROXY_NAME, then ceck that none of the IP
+ * addresses we are returning is on the same broadcast subnet
+ * as the requesting packet. If it is then don't reply as the
+ * actual machine will be replying also and we don't want two
+ * replies to a broadcast query.
+ */
+
+ if (namerec->data.source == WINS_PROXY_NAME) {
+ for( i = 0; i < namerec->data.num_ips; i++) {
+ if (same_net(namerec->data.ip[i], subrec->myip, subrec->mask_ip)) {
+ DEBUG(5,("process_name_query_request: name %s is a WINS proxy name and is also on the same subnet (%s) as the requestor. Not replying.\n",
+ nmb_namestr(&namerec->name), subrec->subnet_name ));
+ return;
+ }
+ }
+ }
+
+ ttl = (namerec->data.death_time != PERMANENT_TTL) ?
+ namerec->data.death_time - p->timestamp : lp_max_ttl();
+
+ /* Copy all known ip addresses into the return data. */
+ /* Optimise for the common case of one IP address so
+ we don't need a malloc. */
+
+ if (namerec->data.num_ips == 1) {
+ prdata = rdata;
+ } else {
+ if ((prdata = (char *)malloc( namerec->data.num_ips * 6 )) == NULL) {
+ DEBUG(0,("process_name_query_request: malloc fail !\n"));
+ return;
+ }
+ }
+
+ for (i = 0; i < namerec->data.num_ips; i++) {
+ set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
+ putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
+ }
+
+ sort_query_replies(prdata, i, p->ip);
+
+ reply_data_len = namerec->data.num_ips * 6;
+ success = True;
+ }
+ }
+
+ /*
+ * If a machine is broadcasting a name lookup request and we have lp_wins_proxy()
+ * set we should initiate a WINS query here. On success we add the resolved name
+ * into our namelist with a type of WINS_PROXY_NAME and then reply to the query.
+ */
+
+ if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() &&
+ bcast && (subrec != remote_broadcast_subnet)) {
+ make_wins_proxy_name_query_request( subrec, p, question );
+ return;
+ }
+
+ if (!success && bcast) {
+ if(prdata != rdata)
+ SAFE_FREE(prdata);
+ return; /* Never reply with a negative response to broadcasts. */
+ }
+
+ /*
+ * Final check. From observation, if a unicast packet is sent
+ * to a non-WINS server with the recursion desired bit set
+ * then never send a negative response.
+ */
+
+ if(!success && !bcast && nmb->header.nm_flags.recursion_desired) {
+ if(prdata != rdata)
+ SAFE_FREE(prdata);
+ return;
+ }
+
+ if (success) {
+ rcode = 0;
+ DEBUG(3,("OK\n"));
+ } else {
+ rcode = NAM_ERR;
+ DEBUG(3,("UNKNOWN\n"));
+ }
+
+ /* See rfc1002.txt 4.2.13. */
+
+ reply_netbios_packet(p, /* Packet to reply to. */
+ rcode, /* Result code. */
+ NMB_QUERY, /* nmbd type code. */
+ NMB_NAME_QUERY_OPCODE, /* opcode. */
+ ttl, /* ttl. */
+ prdata, /* data to send. */
+ reply_data_len); /* data length. */
+
+ if(prdata != rdata)
+ SAFE_FREE(prdata);
}
diff --git a/source3/nmbd/nmbd_mynames.c b/source3/nmbd/nmbd_mynames.c
index aac188db2b..345245c57d 100644
--- a/source3/nmbd/nmbd_mynames.c
+++ b/source3/nmbd/nmbd_mynames.c
@@ -184,67 +184,48 @@ BOOL register_my_workgroup_and_names(void)
/****************************************************************************
Remove all the names we registered.
**************************************************************************/
-
-void release_my_names(void)
+void release_wins_names(void)
{
-#if 0 /*JRR: do WINS server only, otherwise clients ignore us when we come back up*/
- struct subnet_record *subrec;
-
- for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
-#else
- struct subnet_record *subrec = unicast_subnet;
-#endif
- {
- struct name_record *namerec, *nextnamerec;
-
- for (namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
- namerec;
- namerec = nextnamerec)
- {
- nextnamerec = (struct name_record *)ubi_trNext( namerec );
- if( (namerec->data.source == SELF_NAME)
- && !NAME_IS_DEREGISTERING(namerec) )
- release_name( subrec, namerec, standard_success_release,
- NULL, NULL);
- }
- }
+ struct subnet_record *subrec = unicast_subnet;
+ struct name_record *namerec, *nextnamerec;
+
+ for (namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
+ namerec;
+ namerec = nextnamerec) {
+ nextnamerec = (struct name_record *)ubi_trNext( namerec );
+ if( (namerec->data.source == SELF_NAME)
+ && !NAME_IS_DEREGISTERING(namerec) )
+ release_name( subrec, namerec, standard_success_release,
+ NULL, NULL);
+ }
}
/*******************************************************************
- Refresh our registered names.
+ Refresh our registered names with WINS
******************************************************************/
-
void refresh_my_names(time_t t)
{
- struct subnet_record *subrec;
-
- for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec))
- {
- struct name_record *namerec;
-
- /* B nodes don't send out name refresh requests, see RFC 1001, 15.5.1 */
- if (subrec != unicast_subnet)
- continue;
-
- for( namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
- namerec;
- namerec = (struct name_record *)ubi_trNext( namerec ) )
- {
- /* Each SELF name has an individual time to be refreshed. */
- if( (namerec->data.source == SELF_NAME)
- && (namerec->data.refresh_time < t)
- && ( namerec->data.death_time != PERMANENT_TTL) )
- {
- /* We cheat here and pretend the refresh is going to be
- successful & update the refresh times. This stops
- multiple refresh calls being done. We actually
- deal with refresh failure in the fail_fn.
- */
- if( !is_refresh_already_queued( subrec, namerec) )
- refresh_name( subrec, namerec, NULL, NULL, NULL );
- namerec->data.death_time = t + lp_max_ttl();
- namerec->data.refresh_time = t + MIN(lp_max_ttl(), MAX_REFRESH_TIME);
- }
- }
- }
+ struct name_record *namerec;
+
+ if (wins_srv_count() < 1) return;
+
+ for (namerec = (struct name_record *)ubi_trFirst(unicast_subnet->namelist);
+ namerec;
+ namerec = (struct name_record *)ubi_trNext(namerec)) {
+ /* Each SELF name has an individual time to be refreshed. */
+ if ((namerec->data.source == SELF_NAME) &&
+ (namerec->data.refresh_time < t) &&
+ (namerec->data.death_time != PERMANENT_TTL)) {
+ /* We cheat here and pretend the refresh is going to be
+ successful & update the refresh times. This stops
+ multiple refresh calls being done. We actually
+ deal with refresh failure in the fail_fn.
+ */
+ if (!is_refresh_already_queued(unicast_subnet, namerec)) {
+ wins_refresh_name(namerec);
+ }
+ namerec->data.death_time = t + lp_max_ttl();
+ namerec->data.refresh_time = t + MIN(lp_max_ttl(), MAX_REFRESH_TIME);
+ }
+ }
}
diff --git a/source3/nmbd/nmbd_namelistdb.c b/source3/nmbd/nmbd_namelistdb.c
index 68b44d618f..bca79ef0c8 100644
--- a/source3/nmbd/nmbd_namelistdb.c
+++ b/source3/nmbd/nmbd_namelistdb.c
@@ -35,7 +35,7 @@ uint16 samba_nb_type = 0; /* samba's NetBIOS name type */
void set_samba_nb_type(void)
{
if( lp_wins_support() || wins_srv_count() )
- samba_nb_type = NB_MFLAG; /* samba is a 'hybrid' node type. */
+ samba_nb_type = NB_HFLAG; /* samba is a 'hybrid' node type. */
else
samba_nb_type = NB_BFLAG; /* samba is broadcast-only node type. */
} /* set_samba_nb_type */
diff --git a/source3/nmbd/nmbd_nameregister.c b/source3/nmbd/nmbd_nameregister.c
index 91b6f8b190..4ac5473d4a 100644
--- a/source3/nmbd/nmbd_nameregister.c
+++ b/source3/nmbd/nmbd_nameregister.c
@@ -25,6 +25,10 @@
extern fstring global_myworkgroup;
+/* forward declarations */
+static void wins_next_registration(struct response_record *rrec);
+
+
/****************************************************************************
Deal with a response packet when registering one of our names.
****************************************************************************/
@@ -32,127 +36,131 @@ extern fstring global_myworkgroup;
static void register_name_response(struct subnet_record *subrec,
struct response_record *rrec, struct packet_struct *p)
{
- /*
- * If we are registering broadcast, then getting a response is an
- * error - we do not have the name. If we are registering unicast,
- * then we expect to get a response.
- */
-
- struct nmb_packet *nmb = &p->packet.nmb;
- BOOL bcast = nmb->header.nm_flags.bcast;
- BOOL success = True;
- struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
- struct nmb_name *answer_name = &nmb->answers->rr_name;
- int ttl = 0;
- uint16 nb_flags = 0;
- struct in_addr registered_ip;
-
- /* Sanity check. Ensure that the answer name in the incoming packet is the
- same as the requested name in the outgoing packet. */
-
- if(!question_name || !answer_name)
- {
- DEBUG(0,("register_name_response: malformed response (%s is NULL).\n",
- question_name ? "question_name" : "answer_name" ));
- return;
- }
-
- if(!nmb_name_equal(question_name, answer_name))
- {
- DEBUG(0,("register_name_response: Answer name %s differs from question \
-name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name)));
- return;
- }
-
- if(bcast)
- {
- /*
- * Special hack to cope with old Samba nmbd's.
- * Earlier versions of Samba (up to 1.9.16p11) respond
- * to a broadcast name registration of WORKGROUP<1b> when
- * they should not. Hence, until these versions are gone,
- * we should treat such errors as success for this particular
- * case only. jallison@whistle.com.
- */
+ /*
+ * If we are registering broadcast, then getting a response is an
+ * error - we do not have the name. If we are registering unicast,
+ * then we expect to get a response.
+ */
+
+ struct nmb_packet *nmb = &p->packet.nmb;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ BOOL success = True;
+ struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
+ struct nmb_name *answer_name = &nmb->answers->rr_name;
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ int ttl = 0;
+ uint16 nb_flags = 0;
+ struct in_addr register_ip;
+ fstring reg_name;
+
+ putip(&register_ip,&sent_nmb->additional->rdata[2]);
+ fstrcpy(reg_name, inet_ntoa(register_ip));
+
+ if (subrec == unicast_subnet) {
+ /* we know that this wins server is definately alive - for the moment! */
+ wins_srv_alive(rrec->packet->ip, register_ip);
+ }
+
+ /* Sanity check. Ensure that the answer name in the incoming packet is the
+ same as the requested name in the outgoing packet. */
+
+ if(!question_name || !answer_name) {
+ DEBUG(0,("register_name_response: malformed response (%s is NULL).\n",
+ question_name ? "question_name" : "answer_name" ));
+ return;
+ }
+
+ if(!nmb_name_equal(question_name, answer_name)) {
+ DEBUG(0,("register_name_response: Answer name %s differs from question name %s.\n",
+ nmb_namestr(answer_name), nmb_namestr(question_name)));
+ return;
+ }
+ if(bcast) {
+ /*
+ * Special hack to cope with old Samba nmbd's.
+ * Earlier versions of Samba (up to 1.9.16p11) respond
+ * to a broadcast name registration of WORKGROUP<1b> when
+ * they should not. Hence, until these versions are gone,
+ * we should treat such errors as success for this particular
+ * case only. jallison@whistle.com.
+ */
+
#if 1 /* OLD_SAMBA_SERVER_HACK */
- if((nmb->header.rcode == ACT_ERR) && strequal(global_myworkgroup, answer_name->name) &&
- (answer_name->name_type == 0x1b))
- {
- /* Pretend we did not get this. */
- rrec->num_msgs--;
-
- DEBUG(5,("register_name_response: Ignoring broadcast response to \
-registration of name %s due to old Samba server bug.\n", nmb_namestr(answer_name)));
- return;
- }
+ if((nmb->header.rcode == ACT_ERR) && strequal(global_myworkgroup, answer_name->name) &&
+ (answer_name->name_type == 0x1b)) {
+ /* Pretend we did not get this. */
+ rrec->num_msgs--;
+
+ DEBUG(5,("register_name_response: Ignoring broadcast response to registration of name %s due to old Samba server bug.\n",
+ nmb_namestr(answer_name)));
+ return;
+ }
#endif /* OLD_SAMBA_SERVER_HACK */
- /* Someone else has the name. Log the problem. */
- DEBUG(1,("register_name_response: Failed to register \
-name %s on subnet %s via broadcast. Error code was %d. Reject came from IP %s\n",
- nmb_namestr(answer_name),
- subrec->subnet_name, nmb->header.rcode, inet_ntoa(p->ip)));
- success = False;
- }
- else
- {
- /* Unicast - check to see if the response allows us to have the name. */
- if(nmb->header.rcode != 0)
- {
- /* Error code - we didn't get the name. */
- success = False;
-
- DEBUG(0,("register_name_response: server at IP %s rejected our \
-name registration of %s with error code %d.\n", inet_ntoa(p->ip),
- nmb_namestr(answer_name), nmb->header.rcode));
-
- }
- else if(nmb->header.opcode == NMB_WACK_OPCODE)
- {
- /* WINS server is telling us to wait. Pretend we didn't get
- the response but don't send out any more register requests. */
-
- DEBUG(5,("register_name_response: WACK from WINS server %s in registering \
-name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name));
-
- rrec->repeat_count = 0;
- /* How long we should wait for. */
- rrec->repeat_time = p->timestamp + nmb->answers->ttl;
- rrec->num_msgs--;
- return;
- }
- else
- {
- success = True;
- /* Get the data we need to pass to the success function. */
- nb_flags = get_nb_flags(nmb->answers->rdata);
- putip((char*)&registered_ip,&nmb->answers->rdata[2]);
- ttl = nmb->answers->ttl;
- }
- }
-
- DEBUG(5,("register_name_response: %s in registering name %s on subnet %s.\n",
- success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name));
-
- if(success)
- {
- /* Enter the registered name into the subnet name database before calling
- the success function. */
- standard_success_register(subrec, rrec->userdata, answer_name, nb_flags, ttl, registered_ip);
- if( rrec->success_fn)
- (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, nb_flags, ttl, registered_ip);
- }
- else
- {
- if( rrec->fail_fn)
- (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
- /* Remove the name. */
- standard_fail_register( subrec, rrec, question_name);
- }
-
- /* Ensure we don't retry. */
- remove_response_record(subrec, rrec);
+ /* Someone else has the name. Log the problem. */
+ DEBUG(1,("register_name_response: Failed to register name %s IP %s on subnet %s via broadcast. Error code was %d. Reject came from IP %s\n",
+ nmb_namestr(answer_name),
+ reg_name,
+ subrec->subnet_name, nmb->header.rcode, inet_ntoa(p->ip)));
+ success = False;
+ } else {
+ /* Unicast - check to see if the response allows us to have the name. */
+ if(nmb->header.rcode != 0) {
+ /* Error code - we didn't get the name. */
+ success = False;
+
+ DEBUG(0,("register_name_response: %sserver at IP %s rejected our name registration of %s IP %s with error code %d.\n",
+ subrec==unicast_subnet?"WINS ":"",
+ inet_ntoa(p->ip),
+ nmb_namestr(answer_name),
+ reg_name,
+ nmb->header.rcode));
+ } else if (nmb->header.opcode == NMB_WACK_OPCODE) {
+ /* WINS server is telling us to wait. Pretend we didn't get
+ the response but don't send out any more register requests. */
+
+ DEBUG(5,("register_name_response: WACK from WINS server %s in registering name %s IP %s\n",
+ inet_ntoa(p->ip), nmb_namestr(answer_name), reg_name));
+
+ rrec->repeat_count = 0;
+ /* How long we should wait for. */
+ rrec->repeat_time = p->timestamp + nmb->answers->ttl;
+ rrec->num_msgs--;
+ return;
+ } else {
+ success = True;
+ /* Get the data we need to pass to the success function. */
+ nb_flags = get_nb_flags(nmb->answers->rdata);
+ ttl = nmb->answers->ttl;
+
+ /* send off a registration for the next IP, if any */
+ wins_next_registration(rrec);
+ }
+ }
+
+ DEBUG(5,("register_name_response: %s in registering %sname %s IP %s with %s.\n",
+ success ? "success" : "failure",
+ subrec==unicast_subnet?"WINS ":"",
+ nmb_namestr(answer_name),
+ reg_name,
+ inet_ntoa(rrec->packet->ip)));
+
+ if(success) {
+ /* Enter the registered name into the subnet name database before calling
+ the success function. */
+ standard_success_register(subrec, rrec->userdata, answer_name, nb_flags, ttl, register_ip);
+ if( rrec->success_fn)
+ (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, nb_flags, ttl, register_ip);
+ } else {
+ if( rrec->fail_fn)
+ (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
+ /* Remove the name. */
+ standard_fail_register( subrec, rrec, question_name);
+ }
+
+ /* Ensure we don't retry. */
+ remove_response_record(subrec, rrec);
}
@@ -163,49 +171,68 @@ static void wins_registration_timeout(struct subnet_record *subrec,
struct response_record *rrec)
{
struct userdata_struct *userdata = rrec->userdata;
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ struct nmb_name *nmbname = &sent_nmb->question.question_name;
+ struct in_addr register_ip;
+ fstring src_addr;
- DEBUG(2,("register_name_timeout_response: WINS server at address %s is not responding.\n",
- inet_ntoa(rrec->packet->ip)));
+ putip(&register_ip,&sent_nmb->additional->rdata[2]);
+
+ fstrcpy(src_addr, inet_ntoa(register_ip));
+
+ DEBUG(2,("wins_registration_timeout: WINS server %s timed out registering IP %s\n",
+ inet_ntoa(rrec->packet->ip), src_addr));
- /* mark it temporarily dead */
- wins_srv_died(rrec->packet->ip);
+ /* mark it temporarily dead for this source address */
+ wins_srv_died(rrec->packet->ip, register_ip);
/* if we have some userdata then use that to work out what
wins server to try next */
if (userdata) {
const char *tag = (const char *)userdata->data;
- struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
- struct nmb_name *nmbname = &sent_nmb->question.question_name;
- /* and try the next wins server in our failover list */
- rrec->packet->ip = wins_srv_ip_tag(tag);
+ /* try the next wins server in our failover list for
+ this tag */
+ rrec->packet->ip = wins_srv_ip_tag(tag, register_ip);
+ }
- /* also update the UNICODE subnet IPs */
- subrec->bcast_ip = subrec->mask_ip = subrec->myip = rrec->packet->ip;
+ /* if we have run out of wins servers for this tag then they
+ must all have timed out. We treat this as *success*, not
+ failure, and go into our standard name refresh mode. This
+ copes with all the wins servers being down */
+ if (wins_srv_is_dead(rrec->packet->ip, register_ip)) {
+ uint16 nb_flags = get_nb_flags(sent_nmb->additional->rdata);
+ int ttl = sent_nmb->additional->ttl;
+
+ standard_success_register(subrec, userdata, nmbname, nb_flags, ttl, register_ip);
+ if(rrec->success_fn) {
+ (*(register_name_success_function)rrec->success_fn)(subrec,
+ rrec->userdata,
+ nmbname,
+ nb_flags,
+ ttl,
+ register_ip);
+ }
- DEBUG(6,("Retrying register of name %s with WINS server %s using tag '%s'\n",
- nmb_namestr(nmbname), inet_ntoa(rrec->packet->ip), tag));
- }
+ /* send off a registration for the next IP, if any */
+ wins_next_registration(rrec);
- /* Keep trying to contact the WINS server periodically. This allows
- us to work correctly if the WINS server is down temporarily when
- we come up. */
+ /* don't need to send this packet any more */
+ remove_response_record(subrec, rrec);
+ return;
+ }
- /* Reset the number of attempts to zero and double the interval between
- retries. Max out at 5 minutes. */
- rrec->repeat_count = 3;
- rrec->repeat_interval *= 2;
- if(rrec->repeat_interval > (5 * 60))
- rrec->repeat_interval = (5 * 60);
- rrec->repeat_time = time(NULL) + rrec->repeat_interval;
+ /* we will be moving to the next WINS server for this group,
+ send it immediately */
+ rrec->repeat_count = 2;
+ rrec->repeat_time = time(NULL) + 1;
rrec->in_expiration_processing = False;
-
- DEBUG(5,("register_name_timeout_response: increasing WINS timeout to %d seconds.\n",
- (int)rrec->repeat_interval));
+
+ DEBUG(6,("Retrying register of name %s IP %s with WINS server %s\n",
+ nmb_namestr(nmbname), src_addr, inet_ntoa(rrec->packet->ip)));
/* notice that we don't remove the response record. This keeps
- us trying to register with each of our failover wins
- servers until we succeed */
+ us trying to register with each of our failover wins servers */
}
@@ -241,13 +268,9 @@ static void register_name_timeout_response(struct subnet_record *subrec,
putip(&registered_ip,&sent_nmb->additional->rdata[2]);
}
} else {
- /* Unicast - if no responses then it's an error. */
- if(rrec->num_msgs == 0) {
- wins_registration_timeout(subrec, rrec);
- return;
- }
-
- /* we got responses, but timed out?? bizarre. Treat it as failure. */
+ /* wins timeouts are special */
+ wins_registration_timeout(subrec, rrec);
+ return;
}
DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n",
@@ -281,7 +304,8 @@ static void multihomed_register_one(struct nmb_name *nmbname,
const char *tag)
{
struct userdata_struct *userdata;
- struct in_addr wins_ip = wins_srv_ip_tag(tag);
+ struct in_addr wins_ip = wins_srv_ip_tag(tag, ip);
+ fstring ip_str;
userdata = (struct userdata_struct *)malloc(sizeof(*userdata) + strlen(tag) + 1);
if (!userdata) {
@@ -292,8 +316,10 @@ static void multihomed_register_one(struct nmb_name *nmbname,
userdata->userdata_len = strlen(tag) + 1;
strlcpy(userdata->data, tag, userdata->userdata_len);
- DEBUG(6,("Registering name %s with WINS server %s using tag '%s'\n",
- nmb_namestr(nmbname), inet_ntoa(wins_ip), tag));
+ fstrcpy(ip_str, inet_ntoa(ip));
+
+ DEBUG(6,("Registering name %s IP %s with WINS server %s using tag '%s'\n",
+ nmb_namestr(nmbname), ip_str, inet_ntoa(wins_ip), tag));
if (queue_register_multihomed_name(unicast_subnet,
register_name_response,
@@ -308,14 +334,65 @@ static void multihomed_register_one(struct nmb_name *nmbname,
DEBUG(0,("multihomed_register_one: Failed to send packet trying to register name %s IP %s\n",
nmb_namestr(nmbname), inet_ntoa(ip)));
}
+
+ free(userdata);
+}
+
+
+/****************************************************************************
+we have finished the registration of one IP and need to see if we have
+any more IPs left to register with this group of wins server for this name
+****************************************************************************/
+static void wins_next_registration(struct response_record *rrec)
+{
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ struct nmb_name *nmbname = &sent_nmb->question.question_name;
+ uint16 nb_flags = get_nb_flags(sent_nmb->additional->rdata);
+ struct userdata_struct *userdata = rrec->userdata;
+ const char *tag;
+ struct in_addr last_ip;
+ struct subnet_record *subrec;
+
+ putip(&last_ip,&sent_nmb->additional->rdata[2]);
+
+ if (!userdata) {
+ /* it wasn't multi-homed */
+ return;
+ }
+
+ tag = (const char *)userdata->data;
+
+ for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+ if (ip_equal(last_ip, subrec->myip)) {
+ subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec);
+ break;
+ }
+ }
+
+ if (!subrec) {
+ /* no more to do! */
+ return;
+ }
+
+ switch (sent_nmb->header.opcode) {
+ case NMB_NAME_MULTIHOMED_REG_OPCODE:
+ multihomed_register_one(nmbname, nb_flags, NULL, NULL, subrec->myip, tag);
+ break;
+ case NMB_NAME_REFRESH_OPCODE_8:
+ queue_wins_refresh(nmbname,
+ register_name_response,
+ register_name_timeout_response,
+ nb_flags, subrec->myip, tag);
+ break;
+ }
}
/****************************************************************************
Try and register one of our names on the unicast subnet - multihomed.
****************************************************************************/
-static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags,
- register_name_success_function success_fn,
- register_name_fail_function fail_fn)
+static void multihomed_register_name(struct nmb_name *nmbname, uint16 nb_flags,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn)
{
/*
If we are adding a group name, we just send multiple
@@ -338,16 +415,16 @@ static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags,
*/
int num_ips=0;
int i, t;
- struct in_addr *ip_list = NULL;
struct subnet_record *subrec;
char **wins_tags;
+ struct in_addr *ip_list;
for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
num_ips++;
if((ip_list = (struct in_addr *)malloc(num_ips * sizeof(struct in_addr)))==NULL) {
DEBUG(0,("multihomed_register_name: malloc fail !\n"));
- return True;
+ return;
}
for (subrec = FIRST_SUBNET, i = 0;
@@ -356,106 +433,92 @@ static BOOL multihomed_register_name( struct nmb_name *nmbname, uint16 nb_flags,
ip_list[i] = subrec->myip;
}
- (void)add_name_to_subnet( unicast_subnet, nmbname->name, nmbname->name_type,
- nb_flags, lp_max_ttl(), SELF_NAME,
- num_ips, ip_list);
+ add_name_to_subnet(unicast_subnet, nmbname->name, nmbname->name_type,
+ nb_flags, lp_max_ttl(), SELF_NAME,
+ num_ips, ip_list);
/* get the list of wins tags - we try to register for each of them */
wins_tags = wins_srv_tags();
- /* Now try and register the name, num_ips times for each wins tag. */
- for (t=0; wins_tags[t]; t++) {
- for (i = 0; i < num_ips; i++) {
- multihomed_register_one(nmbname, nb_flags,
- success_fn, fail_fn,
- ip_list[i],
- wins_tags[t]);
- }
+ /* Now try and register the name for each wins tag. Note that
+ at this point we only register our first IP with each wins
+ group. We will register the rest from
+ wins_next_registration() when we get the reply for this
+ one. That follows the way W2K does things (tridge)
+ */
+ for (t=0; wins_tags && wins_tags[t]; t++) {
+ multihomed_register_one(nmbname, nb_flags,
+ success_fn, fail_fn,
+ ip_list[0],
+ wins_tags[t]);
}
wins_srv_tags_free(wins_tags);
SAFE_FREE(ip_list);
-
- return False;
}
+
/****************************************************************************
Try and register one of our names.
****************************************************************************/
-
-BOOL register_name(struct subnet_record *subrec,
+void register_name(struct subnet_record *subrec,
char *name, int type, uint16 nb_flags,
register_name_success_function success_fn,
register_name_fail_function fail_fn,
struct userdata_struct *userdata)
{
- struct nmb_name nmbname;
-
- make_nmb_name(&nmbname, name, type);
-
- /* Always set the NB_ACTIVE flag on the name we are
- registering. Doesn't make sense without it.
- */
-
- nb_flags |= NB_ACTIVE;
-
- /* If this is the unicast subnet, and we are a multi-homed
- host, then register a multi-homed name. */
-
- if( (subrec == unicast_subnet) && we_are_multihomed()) {
- return multihomed_register_name(&nmbname, nb_flags,
- success_fn, fail_fn);
- }
-
- if(queue_register_name( subrec,
- register_name_response,
- register_name_timeout_response,
- success_fn,
- fail_fn,
- userdata,
- &nmbname,
- nb_flags) == NULL)
- {
- DEBUG(0,("register_name: Failed to send packet trying to register name %s\n",
- nmb_namestr(&nmbname)));
- return True;
- }
- return False;
+ struct nmb_name nmbname;
+
+ make_nmb_name(&nmbname, name, type);
+
+ /* Always set the NB_ACTIVE flag on the name we are
+ registering. Doesn't make sense without it.
+ */
+
+ nb_flags |= NB_ACTIVE;
+
+ if (subrec == unicast_subnet) {
+ /* we now always do multi-homed registration if we are
+ registering to a WINS server. This copes much
+ better with complex WINS setups */
+ multihomed_register_name(&nmbname, nb_flags,
+ success_fn, fail_fn);
+ return;
+ }
+
+ if (queue_register_name(subrec,
+ register_name_response,
+ register_name_timeout_response,
+ success_fn,
+ fail_fn,
+ userdata,
+ &nmbname,
+ nb_flags) == NULL) {
+ DEBUG(0,("register_name: Failed to send packet trying to register name %s\n",
+ nmb_namestr(&nmbname)));
+ }
}
+
/****************************************************************************
- Try and refresh one of our names.
+ Try and refresh one of our names. This is *only* called for WINS refresh
****************************************************************************/
-
-BOOL refresh_name(struct subnet_record *subrec, struct name_record *namerec,
- refresh_name_success_function success_fn,
- refresh_name_fail_function fail_fn,
- struct userdata_struct *userdata)
+void wins_refresh_name(struct name_record *namerec)
{
- int i;
-
- /*
- * Go through and refresh the name for all known ip addresses.
- * Only call the success/fail function on the last one (it should
- * only be done once).
- */
-
- for( i = 0; i < namerec->data.num_ips; i++)
- {
- if(queue_refresh_name( subrec,
- register_name_response,
- register_name_timeout_response,
- (i == (namerec->data.num_ips - 1)) ? success_fn : NULL,
- (i == (namerec->data.num_ips - 1)) ? fail_fn : NULL,
- (i == (namerec->data.num_ips - 1)) ? userdata : NULL,
- namerec,
- namerec->data.ip[i]) == NULL)
- {
- DEBUG(0,("refresh_name: Failed to send packet trying to refresh name %s\n",
- nmb_namestr(&namerec->name)));
- return True;
- }
- }
- return False;
+ int t;
+ char **wins_tags;
+
+ /* get the list of wins tags - we try to refresh for each of them */
+ wins_tags = wins_srv_tags();
+
+ for (t=0; wins_tags && wins_tags[t]; t++) {
+ queue_wins_refresh(&namerec->name,
+ register_name_response,
+ register_name_timeout_response,
+ namerec->data.nb_flags,
+ namerec->data.ip[0], wins_tags[t]);
+ }
+
+ wins_srv_tags_free(wins_tags);
}
diff --git a/source3/nmbd/nmbd_namerelease.c b/source3/nmbd/nmbd_namerelease.c
index cefab44a08..0611ca9323 100644
--- a/source3/nmbd/nmbd_namerelease.c
+++ b/source3/nmbd/nmbd_namerelease.c
@@ -28,85 +28,72 @@
****************************************************************************/
static void release_name_response(struct subnet_record *subrec,
- struct response_record *rrec, struct packet_struct *p)
+ struct response_record *rrec, struct packet_struct *p)
{
- /*
- * If we are releasing broadcast, then getting a response is an
- * error. If we are releasing unicast, then we expect to get a response.
- */
-
- struct nmb_packet *nmb = &p->packet.nmb;
- BOOL bcast = nmb->header.nm_flags.bcast;
- BOOL success = True;
- struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
- struct nmb_name *answer_name = &nmb->answers->rr_name;
- struct in_addr released_ip;
-
- /* Sanity check. Ensure that the answer name in the incoming packet is the
- same as the requested name in the outgoing packet. */
-
- if(!nmb_name_equal(question_name, answer_name))
- {
- DEBUG(0,("release_name_response: Answer name %s differs from question \
-name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name)));
- return;
- }
-
- if(bcast)
- {
- /* Someone sent a response. This shouldn't happen/ */
- DEBUG(1,("release_name_response: A response for releasing name %s was received on a \
-broadcast subnet %s. This should not happen !\n", nmb_namestr(answer_name), subrec->subnet_name));
- return;
- }
- else
- {
- /* Unicast - check to see if the response allows us to release the name. */
- if(nmb->header.rcode != 0)
- {
- /* Error code - we were told not to release the name ! What now ! */
- success = False;
-
- DEBUG(0,("release_name_response: WINS server at IP %s rejected our \
-name release of name %s with error code %d.\n", inet_ntoa(p->ip),
- nmb_namestr(answer_name), nmb->header.rcode));
-
- }
- else if(nmb->header.opcode == NMB_WACK_OPCODE)
- {
- /* WINS server is telling us to wait. Pretend we didn't get
- the response but don't send out any more release requests. */
-
- DEBUG(5,("release_name_response: WACK from WINS server %s in releasing \
-name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name));
-
- rrec->repeat_count = 0;
- /* How long we should wait for. */
- rrec->repeat_time = p->timestamp + nmb->answers->ttl;
- rrec->num_msgs--;
- return;
- }
- }
-
- DEBUG(5,("release_name_response: %s in releasing name %s on subnet %s.\n",
- success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name));
-
- if(success)
- {
- putip((char*)&released_ip ,&nmb->answers->rdata[2]);
-
- if(rrec->success_fn)
- (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, released_ip);
- standard_success_release( subrec, rrec->userdata, answer_name, released_ip);
- }
- else
- {
- /* We have no standard_fail_release - maybe we should add one ? */
- if(rrec->fail_fn)
- (*(release_name_fail_function)rrec->fail_fn)(subrec, rrec, answer_name);
- }
-
- remove_response_record(subrec, rrec);
+ /*
+ * If we are releasing broadcast, then getting a response is an
+ * error. If we are releasing unicast, then we expect to get a response.
+ */
+ struct nmb_packet *nmb = &p->packet.nmb;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ BOOL success = True;
+ struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
+ struct nmb_name *answer_name = &nmb->answers->rr_name;
+ struct in_addr released_ip;
+
+ /* Sanity check. Ensure that the answer name in the incoming packet is the
+ same as the requested name in the outgoing packet. */
+ if (!nmb_name_equal(question_name, answer_name)) {
+ DEBUG(0,("release_name_response: Answer name %s differs from question name %s.\n",
+ nmb_namestr(answer_name), nmb_namestr(question_name)));
+ return;
+ }
+
+ if (bcast) {
+ /* Someone sent a response to a bcast release? ignore it. */
+ return;
+ }
+
+ /* Unicast - check to see if the response allows us to release the name. */
+ if (nmb->header.rcode != 0) {
+ /* Error code - we were told not to release the name ! What now ! */
+ success = False;
+
+ DEBUG(0,("release_name_response: WINS server at IP %s rejected our \
+name release of name %s with error code %d.\n",
+ inet_ntoa(p->ip),
+ nmb_namestr(answer_name), nmb->header.rcode));
+ } else if (nmb->header.opcode == NMB_WACK_OPCODE) {
+ /* WINS server is telling us to wait. Pretend we didn't get
+ the response but don't send out any more release requests. */
+
+ DEBUG(5,("release_name_response: WACK from WINS server %s in releasing \
+name %s on subnet %s.\n",
+ inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name));
+
+ rrec->repeat_count = 0;
+ /* How long we should wait for. */
+ rrec->repeat_time = p->timestamp + nmb->answers->ttl;
+ rrec->num_msgs--;
+ return;
+ }
+
+ DEBUG(5,("release_name_response: %s in releasing name %s on subnet %s.\n",
+ success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name));
+ if (success) {
+ putip((char*)&released_ip ,&nmb->answers->rdata[2]);
+
+ if(rrec->success_fn)
+ (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, released_ip);
+ standard_success_release( subrec, rrec->userdata, answer_name, released_ip);
+ } else {
+ /* We have no standard_fail_release - maybe we should add one ? */
+ if (rrec->fail_fn) {
+ (*(release_name_fail_function)rrec->fail_fn)(subrec, rrec, answer_name);
+ }
+ }
+
+ remove_response_record(subrec, rrec);
}
/****************************************************************************
@@ -114,125 +101,122 @@ name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->su
****************************************************************************/
static void release_name_timeout_response(struct subnet_record *subrec,
- struct response_record *rrec)
+ struct response_record *rrec)
{
- /*
- * If we are releasing unicast, then NOT getting a response is an
- * error - we could not release the name. If we are releasing broadcast,
- * then we don't expect to get a response.
- */
-
- struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
- BOOL bcast = sent_nmb->header.nm_flags.bcast;
- BOOL success = False;
- struct nmb_name *question_name = &sent_nmb->question.question_name;
- struct in_addr released_ip;
-
- if(bcast)
- {
- if(rrec->num_msgs == 0)
- {
- /* Not receiving a message is success for broadcast release. */
- success = True;
-
- /* Get the ip address we were trying to release. */
- putip((char*)&released_ip ,&sent_nmb->additional->rdata[2]);
- }
- }
- else
- {
- /* Unicast - if no responses then it's an error. */
- if(rrec->num_msgs == 0)
- {
- DEBUG(2,("release_name_timeout_response: WINS server at address %s is not \
-responding.\n", inet_ntoa(rrec->packet->ip)));
-
- /* mark it temporarily dead */
- wins_srv_died(rrec->packet->ip);
-
- /* and try the next wins server */
- rrec->packet->ip = wins_srv_ip();
-
- /* also update the UNICODE subnet IPs */
- subrec->bcast_ip = subrec->mask_ip = subrec->myip = rrec->packet->ip;
-
- /* Reset the number of attempts to zero and double the interval between
- retries. Max out at 5 minutes. */
- rrec->repeat_count = 3;
- rrec->repeat_interval *= 2;
- if(rrec->repeat_interval > (5 * 60))
- rrec->repeat_interval = (5 * 60);
- rrec->repeat_time = time(NULL) + rrec->repeat_interval;
-
- DEBUG(5,("release_name_timeout_response: increasing WINS timeout to %d seconds.\n",
- (int)rrec->repeat_interval));
- return; /* Don't remove the response record. */
- }
- }
-
- DEBUG(5,("release_name_timeout_response: %s in releasing name %s on subnet %s.\n",
- success ? "success" : "failure", nmb_namestr(question_name), subrec->subnet_name));
-
- if(success && rrec->success_fn)
- {
- if(rrec->success_fn)
- (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, released_ip);
- standard_success_release( subrec, rrec->userdata, question_name, released_ip);
- }
- else
- {
- /* We have no standard_fail_release - maybe we should add one ? */
- if( rrec->fail_fn)
- (*(release_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
- }
-
- remove_response_record(subrec, rrec);
+ /* a release is *always* considered to be successful when it
+ times out. This doesn't cause problems as if a WINS server
+ doesn't respond and someone else wants the name then the
+ normal WACK/name query from the WINS server will cope */
+ struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
+ BOOL bcast = sent_nmb->header.nm_flags.bcast;
+ struct nmb_name *question_name = &sent_nmb->question.question_name;
+ struct in_addr released_ip;
+
+ /* Get the ip address we were trying to release. */
+ putip((char*)&released_ip ,&sent_nmb->additional->rdata[2]);
+
+ if (!bcast) {
+ /* mark the WINS server temporarily dead */
+ wins_srv_died(rrec->packet->ip, released_ip);
+ }
+
+ DEBUG(5,("release_name_timeout_response: success in releasing name %s on subnet %s.\n",
+ nmb_namestr(question_name), subrec->subnet_name));
+
+ if (rrec->success_fn) {
+ (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, released_ip);
+ }
+
+ standard_success_release( subrec, rrec->userdata, question_name, released_ip);
+ remove_response_record(subrec, rrec);
}
+
+/*
+ when releasing a name with WINS we need to send the release to each of
+ the WINS groups
+*/
+static void wins_release_name(struct name_record *namerec,
+ release_name_success_function success_fn,
+ release_name_fail_function fail_fn,
+ struct userdata_struct *userdata)
+{
+ int t, i;
+ char **wins_tags;
+
+ /* get the list of wins tags - we try to release for each of them */
+ wins_tags = wins_srv_tags();
+
+ for (t=0;wins_tags && wins_tags[t]; t++) {
+ for (i = 0; i < namerec->data.num_ips; i++) {
+ struct in_addr wins_ip = wins_srv_ip_tag(wins_tags[t], namerec->data.ip[i]);
+
+ BOOL last_one = ((i==namerec->data.num_ips - 1) && !wins_tags[t+1]);
+ if (queue_release_name(unicast_subnet,
+ release_name_response,
+ release_name_timeout_response,
+ last_one?success_fn : NULL,
+ last_one? fail_fn : NULL,
+ last_one? userdata : NULL,
+ &namerec->name,
+ namerec->data.nb_flags,
+ namerec->data.ip[i],
+ wins_ip) == NULL) {
+ DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n",
+ nmb_namestr(&namerec->name), inet_ntoa(namerec->data.ip[i]) ));
+ }
+ }
+ }
+
+ wins_srv_tags_free(wins_tags);
+}
+
+
/****************************************************************************
Try and release one of our names.
****************************************************************************/
-BOOL release_name(struct subnet_record *subrec, struct name_record *namerec,
- release_name_success_function success_fn,
- release_name_fail_function fail_fn,
- struct userdata_struct *userdata)
+void release_name(struct subnet_record *subrec, struct name_record *namerec,
+ release_name_success_function success_fn,
+ release_name_fail_function fail_fn,
+ struct userdata_struct *userdata)
{
- int i;
-
- /* Ensure it's a SELF name, and in the ACTIVE state. */
- if((namerec->data.source != SELF_NAME) || !NAME_IS_ACTIVE(namerec))
- {
- DEBUG(0,("release_name: Cannot release name %s from subnet %s. Source was %d \n",
- nmb_namestr(&namerec->name), subrec->subnet_name, namerec->data.source));
- return True;
- }
-
- /* Set the name into the deregistering state. */
- namerec->data.nb_flags |= NB_DEREG;
-
- /*
- * Go through and release the name for all known ip addresses.
- * Only call the success/fail function on the last one (it should
- * only be done once).
- */
-
- for( i = 0; i < namerec->data.num_ips; i++)
- {
- if(queue_release_name( subrec,
- release_name_response,
- release_name_timeout_response,
- (i == (namerec->data.num_ips - 1)) ? success_fn : NULL,
- (i == (namerec->data.num_ips - 1)) ? fail_fn : NULL,
- (i == (namerec->data.num_ips - 1)) ? userdata : NULL,
- &namerec->name,
- namerec->data.nb_flags,
- namerec->data.ip[i]) == NULL)
- {
- DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n",
- nmb_namestr(&namerec->name), inet_ntoa(namerec->data.ip[i]) ));
- return True;
- }
- }
- return False;
+ int i;
+
+ /* Ensure it's a SELF name, and in the ACTIVE state. */
+ if ((namerec->data.source != SELF_NAME) || !NAME_IS_ACTIVE(namerec)) {
+ DEBUG(0,("release_name: Cannot release name %s from subnet %s. Source was %d \n",
+ nmb_namestr(&namerec->name), subrec->subnet_name, namerec->data.source));
+ return;
+ }
+
+ /* Set the name into the deregistering state. */
+ namerec->data.nb_flags |= NB_DEREG;
+
+ /* wins releases are a bit different */
+ if (subrec == unicast_subnet) {
+ wins_release_name(namerec, success_fn, fail_fn, userdata);
+ return;
+ }
+
+ /*
+ * Go through and release the name for all known ip addresses.
+ * Only call the success/fail function on the last one (it should
+ * only be done once).
+ */
+ for (i = 0; i < namerec->data.num_ips; i++) {
+ if (queue_release_name(subrec,
+ release_name_response,
+ release_name_timeout_response,
+ (i == (namerec->data.num_ips - 1)) ? success_fn : NULL,
+ (i == (namerec->data.num_ips - 1)) ? fail_fn : NULL,
+ (i == (namerec->data.num_ips - 1)) ? userdata : NULL,
+ &namerec->name,
+ namerec->data.nb_flags,
+ namerec->data.ip[i],
+ subrec->bcast_ip) == NULL) {
+ DEBUG(0,("release_name: Failed to send packet trying to release name %s IP %s\n",
+ nmb_namestr(&namerec->name), inet_ntoa(namerec->data.ip[i]) ));
+ }
+ }
}
diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c
index f0c8b755c9..64b63627d7 100644
--- a/source3/nmbd/nmbd_packets.c
+++ b/source3/nmbd/nmbd_packets.c
@@ -237,48 +237,44 @@ static BOOL create_and_init_additional_record(struct packet_struct *packet,
uint16 nb_flags,
struct in_addr *register_ip)
{
- struct nmb_packet *nmb = &packet->packet.nmb;
-
- if((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL)
- {
- DEBUG(0,("initiate_name_register_packet: malloc fail for additional record.\n"));
- return False;
- }
-
- memset((char *)nmb->additional,'\0',sizeof(struct res_rec));
-
- nmb->additional->rr_name = nmb->question.question_name;
- nmb->additional->rr_type = RR_TYPE_NB;
- nmb->additional->rr_class = RR_CLASS_IN;
-
- /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */
- if (nmb->header.nm_flags.bcast)
- nmb->additional->ttl = PERMANENT_TTL;
- else
- nmb->additional->ttl = lp_max_ttl();
-
- nmb->additional->rdlength = 6;
-
- set_nb_flags(nmb->additional->rdata,nb_flags);
-
- /* Set the address for the name we are registering. */
- putip(&nmb->additional->rdata[2], register_ip);
+ struct nmb_packet *nmb = &packet->packet.nmb;
-#if 0
- /* I removed this forced source IP as it breaks wins failover. The
- problem is that our 2nd interface IP may not be routable to the
- wins server, in which case all these nice packets we are senidng
- out will never get a response and we end up marking a perfectly good wins server dead.
+ if((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL) {
+ DEBUG(0,("initiate_name_register_packet: malloc fail for additional record.\n"));
+ return False;
+ }
- In general I can't see any reason why we should force the source
- ip on a packet anyway. We should just let the kernels routin
- table take care of it, as that is the only place which really
- knows what is routable and what isn't. (tridge)
- */
- packet->fd = find_subnet_fd_for_address( *register_ip );
-#endif
+ memset((char *)nmb->additional,'\0',sizeof(struct res_rec));
- return True;
+ nmb->additional->rr_name = nmb->question.question_name;
+ nmb->additional->rr_type = RR_TYPE_NB;
+ nmb->additional->rr_class = RR_CLASS_IN;
+
+ /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */
+ if (nmb->header.nm_flags.bcast)
+ nmb->additional->ttl = PERMANENT_TTL;
+ else
+ nmb->additional->ttl = lp_max_ttl();
+
+ nmb->additional->rdlength = 6;
+
+ set_nb_flags(nmb->additional->rdata,nb_flags);
+
+ /* Set the address for the name we are registering. */
+ putip(&nmb->additional->rdata[2], register_ip);
+
+ /*
+ it turns out that Jeremys code was correct, we are supposed
+ to send registrations from the IP we are registering. The
+ trick is what to do on timeouts! When we send on a
+ non-routable IP then the reply will timeout, and we should
+ treat this as success, not failure. That means we go into
+ our standard refresh cycle for that name which copes nicely
+ with disconnected networks.
+ */
+ packet->fd = find_subnet_fd_for_address(*register_ip);
+
+ return True;
}
/***************************************************************************
@@ -353,28 +349,28 @@ static BOOL initiate_name_register_packet( struct packet_struct *packet,
Sends out a multihomed name register.
**************************************************************************/
-static BOOL initiate_multihomed_name_register_packet( struct packet_struct *packet,
- uint16 nb_flags, struct in_addr *register_ip)
+static BOOL initiate_multihomed_name_register_packet(struct packet_struct *packet,
+ uint16 nb_flags, struct in_addr *register_ip)
{
- struct nmb_packet *nmb = &packet->packet.nmb;
- fstring second_ip_buf;
+ struct nmb_packet *nmb = &packet->packet.nmb;
+ fstring second_ip_buf;
- fstrcpy(second_ip_buf, inet_ntoa(packet->ip));
+ fstrcpy(second_ip_buf, inet_ntoa(packet->ip));
- nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE;
- nmb->header.arcount = 1;
+ nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE;
+ nmb->header.arcount = 1;
- nmb->header.nm_flags.recursion_desired = True;
-
- if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
- return False;
-
- DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \
+ nmb->header.nm_flags.recursion_desired = True;
+
+ if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
+ return False;
+
+ DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \
for name %s IP %s (bcast=%s) to IP %s\n",
- nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip),
- BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf ));
+ nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip),
+ BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf ));
- return send_netbios_packet( packet );
+ return send_netbios_packet( packet );
}
/***************************************************************************
@@ -518,6 +514,67 @@ struct response_record *queue_register_name( struct subnet_record *subrec,
return rrec;
}
+
+/****************************************************************************
+ Queue a refresh name packet to the broadcast address of a subnet.
+****************************************************************************/
+void queue_wins_refresh(struct nmb_name *nmbname,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ uint16 nb_flags,
+ struct in_addr refresh_ip,
+ const char *tag)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+ struct in_addr wins_ip;
+ struct userdata_struct *userdata;
+ fstring ip_str;
+
+ wins_ip = wins_srv_ip_tag(tag, refresh_ip);
+
+ if ((p = create_and_init_netbios_packet(nmbname, False, False, wins_ip)) == NULL) {
+ return;
+ }
+
+ if (!initiate_name_refresh_packet(p, nb_flags, &refresh_ip)) {
+ p->locked = False;
+ free_packet(p);
+ return;
+ }
+
+ fstrcpy(ip_str, inet_ntoa(refresh_ip));
+
+ DEBUG(6,("Refreshing name %s IP %s with WINS server %s using tag '%s'\n",
+ nmb_namestr(nmbname), ip_str, inet_ntoa(wins_ip), tag));
+
+ userdata = (struct userdata_struct *)malloc(sizeof(*userdata) + strlen(tag) + 1);
+ if (!userdata) {
+ DEBUG(0,("Failed to allocate userdata structure!\n"));
+ return;
+ }
+ ZERO_STRUCTP(userdata);
+ userdata->userdata_len = strlen(tag) + 1;
+ strlcpy(userdata->data, tag, userdata->userdata_len);
+
+ if ((rrec = make_response_record(unicast_subnet,
+ p,
+ resp_fn, timeout_fn,
+ NULL,
+ NULL,
+ userdata)) == NULL) {
+ p->locked = False;
+ free_packet(p);
+ return;
+ }
+
+ free(userdata);
+
+ /* we don't want to repeat refresh packets */
+ rrec->repeat_count = 0;
+}
+
+
/****************************************************************************
Queue a multihomed register name packet to a given WINS server IP
****************************************************************************/
@@ -581,14 +638,15 @@ unicast subnet. subnet is %s\n.", subrec->subnet_name ));
****************************************************************************/
struct response_record *queue_release_name( struct subnet_record *subrec,
- response_function resp_fn,
- timeout_response_function timeout_fn,
- release_name_success_function success_fn,
- release_name_fail_function fail_fn,
- struct userdata_struct *userdata,
- struct nmb_name *nmbname,
- uint16 nb_flags,
- struct in_addr release_ip)
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ release_name_success_function success_fn,
+ release_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ uint16 nb_flags,
+ struct in_addr release_ip,
+ struct in_addr dest_ip)
{
struct packet_struct *p;
struct response_record *rrec;
@@ -597,7 +655,7 @@ struct response_record *queue_release_name( struct subnet_record *subrec,
return NULL;
if ((p = create_and_init_netbios_packet(nmbname, (subrec != unicast_subnet), False,
- subrec->bcast_ip)) == NULL)
+ dest_ip)) == NULL)
return NULL;
if(initiate_name_release_packet( p, nb_flags, &release_ip) == False)
@@ -634,52 +692,6 @@ struct response_record *queue_release_name( struct subnet_record *subrec,
}
/****************************************************************************
- Queue a refresh name packet to the broadcast address of a subnet.
-****************************************************************************/
-
-struct response_record *queue_refresh_name( struct subnet_record *subrec,
- response_function resp_fn,
- timeout_response_function timeout_fn,
- refresh_name_success_function success_fn,
- refresh_name_fail_function fail_fn,
- struct userdata_struct *userdata,
- struct name_record *namerec,
- struct in_addr refresh_ip)
-{
- struct packet_struct *p;
- struct response_record *rrec;
-
- if(assert_check_subnet(subrec))
- return NULL;
-
- if(( p = create_and_init_netbios_packet(&namerec->name, (subrec != unicast_subnet), False,
- subrec->bcast_ip)) == NULL)
- return NULL;
-
- if( !initiate_name_refresh_packet( p, namerec->data.nb_flags, &refresh_ip ) )
- {
- p->locked = False;
- free_packet(p);
- return NULL;
- }
-
- if((rrec = make_response_record(subrec, /* subnet record. */
- p, /* packet we sent. */
- resp_fn, /* function to call on response. */
- timeout_fn, /* function to call on timeout. */
- (success_function)success_fn, /* function to call on operation success. */
- (fail_function)fail_fn, /* function to call on operation fail. */
- userdata)) == NULL)
- {
- p->locked = False;
- free_packet(p);
- return NULL;
- }
-
- return rrec;
-}
-
-/****************************************************************************
Queue a query name packet to the broadcast address of a subnet.
****************************************************************************/
diff --git a/source3/nmbd/nmbd_responserecordsdb.c b/source3/nmbd/nmbd_responserecordsdb.c
index a2da5ddf4a..7e8c8025ae 100644
--- a/source3/nmbd/nmbd_responserecordsdb.c
+++ b/source3/nmbd/nmbd_responserecordsdb.c
@@ -97,12 +97,12 @@ void remove_response_record(struct subnet_record *subrec,
**************************************************************************/
struct response_record *make_response_record( struct subnet_record *subrec,
- struct packet_struct *p,
- response_function resp_fn,
- timeout_response_function timeout_fn,
- success_function success_fn,
- fail_function fail_fn,
- struct userdata_struct *userdata)
+ struct packet_struct *p,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ success_function success_fn,
+ fail_function fail_fn,
+ struct userdata_struct *userdata)
{
struct response_record *rrec;
struct nmb_packet *nmb = &p->packet.nmb;
diff --git a/source3/nmbd/nmbd_subnetdb.c b/source3/nmbd/nmbd_subnetdb.c
index 146b6cbdfe..e68fc1589c 100644
--- a/source3/nmbd/nmbd_subnetdb.c
+++ b/source3/nmbd/nmbd_subnetdb.c
@@ -267,45 +267,14 @@ BOOL create_subnets(void)
if (!make_normal_subnet(iface)) return False;
}
- /*
- * If we have been configured to use a WINS server, then try and
- * get the ip address of it here. If we are the WINS server then
- * set the unicast subnet address to be the first of our own real
- * addresses.
- *
- * NOTE: I'm not sure of the implications of WINS server failover
- * on this bit of code. Because of failover, the WINS
- * server address can change. crh
- */
-
- if( wins_srv_count() )
- {
- struct in_addr real_wins_ip;
- real_wins_ip = wins_srv_ip();
-
- if (!is_zero_ip(real_wins_ip))
- {
- unicast_ip = real_wins_ip;
- }
- else
- {
- /* wins_srv_ip() can return a zero IP if all servers are
- * either down or incorrectly entered in smb.conf. crh
- */
- DEBUG(0,("No 'live' WINS servers found. Check 'wins server' parameter.\n"));
- return False;
- }
- }
- else if(lp_we_are_a_wins_server())
- {
- /* Pick the first interface ip address as the WINS server ip. */
- unicast_ip = *iface_n_ip(0);
- }
- else
- {
- /* We should not be using a WINS server at all. Set the
- ip address of the subnet to be zero. */
- zero_ip(&unicast_ip);
+ if (lp_we_are_a_wins_server()) {
+ /* Pick the first interface ip address as the WINS server ip. */
+ unicast_ip = *iface_n_ip(0);
+ } else {
+ /* note that we do not set the wins server IP here. We just
+ set it at zero and let the wins registration code cope
+ with getting the IPs right for each packet */
+ zero_ip(&unicast_ip);
}
/*
@@ -346,16 +315,13 @@ BOOL create_subnets(void)
/*******************************************************************
Function to tell us if we can use the unicast subnet.
******************************************************************/
-
BOOL we_are_a_wins_client(void)
{
- static int cache_we_are_a_wins_client = -1;
-
- if(cache_we_are_a_wins_client == -1)
- cache_we_are_a_wins_client = (is_zero_ip(unicast_subnet->myip) ?
- False : True);
+ if (wins_srv_count() > 0) {
+ return True;
+ }
- return cache_we_are_a_wins_client;
+ return False;
}
/*******************************************************************