mirror of
https://github.com/samba-team/samba.git
synced 2025-03-09 08:58:35 +03:00
r5275: - added support for NBT_OPCODE_MULTI_HOME_REG (opcode 0xf) for WINS name registrations
- fixed a bug in the send queue handling on timeouts - added support for handling unexpected replies (replies to the wrong port) at the nbtsocket layer - added separate layer 2 code for wins refresh and wins registration
This commit is contained in:
parent
4165f21635
commit
2502b02898
@ -159,6 +159,7 @@ struct nbt_name_register;
|
||||
struct nbt_name_refresh;
|
||||
struct nbt_name_register_bcast;
|
||||
struct nbt_name_refresh_wins;
|
||||
struct nbt_name_register_wins;
|
||||
|
||||
struct messaging_context;
|
||||
struct stream_connection;
|
||||
|
@ -113,7 +113,13 @@ struct nbt_name_socket {
|
||||
const char *, int );
|
||||
void *private;
|
||||
} incoming;
|
||||
|
||||
|
||||
/* what to do with unexpected replies */
|
||||
struct {
|
||||
void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
|
||||
const char *, int );
|
||||
void *private;
|
||||
} unexpected;
|
||||
};
|
||||
|
||||
|
||||
@ -161,6 +167,7 @@ struct nbt_name_register {
|
||||
uint16_t nb_flags;
|
||||
BOOL register_demand;
|
||||
BOOL broadcast;
|
||||
BOOL multi_homed;
|
||||
uint32_t ttl;
|
||||
int timeout; /* in seconds */
|
||||
int retries;
|
||||
@ -184,9 +191,10 @@ struct nbt_name_register_bcast {
|
||||
} in;
|
||||
};
|
||||
|
||||
/* wins name refresh with multiple wins servers to try and multiple
|
||||
|
||||
/* wins name register with multiple wins servers to try and multiple
|
||||
addresses to register */
|
||||
struct nbt_name_refresh_wins {
|
||||
struct nbt_name_register_wins {
|
||||
struct {
|
||||
struct nbt_name name;
|
||||
const char **wins_servers;
|
||||
@ -201,6 +209,7 @@ struct nbt_name_refresh_wins {
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* a name refresh request */
|
||||
struct nbt_name_refresh {
|
||||
struct {
|
||||
@ -220,3 +229,21 @@ struct nbt_name_refresh {
|
||||
uint8_t rcode;
|
||||
} out;
|
||||
};
|
||||
|
||||
/* wins name refresh with multiple wins servers to try and multiple
|
||||
addresses to register */
|
||||
struct nbt_name_refresh_wins {
|
||||
struct {
|
||||
struct nbt_name name;
|
||||
const char **wins_servers;
|
||||
const char **addresses;
|
||||
uint16_t nb_flags;
|
||||
uint32_t ttl;
|
||||
} in;
|
||||
struct {
|
||||
const char *wins_server;
|
||||
uint8_t rcode;
|
||||
} out;
|
||||
};
|
||||
|
||||
|
||||
|
@ -141,8 +141,8 @@ NTSTATUS nbt_name_refresh(struct nbt_name_socket *nbtsock,
|
||||
struct refresh_wins_state {
|
||||
struct nbt_name_socket *nbtsock;
|
||||
struct nbt_name_refresh *io;
|
||||
char **wins_servers;
|
||||
char **addresses;
|
||||
const char **wins_servers;
|
||||
const char **addresses;
|
||||
int address_idx;
|
||||
struct nbt_name_request *req;
|
||||
};
|
||||
|
@ -40,7 +40,11 @@ struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
|
||||
|
||||
packet->qdcount = 1;
|
||||
packet->arcount = 1;
|
||||
packet->operation = NBT_OPCODE_REGISTER;
|
||||
if (io->in.multi_homed) {
|
||||
packet->operation = NBT_OPCODE_MULTI_HOME_REG;
|
||||
} else {
|
||||
packet->operation = NBT_OPCODE_REGISTER;
|
||||
}
|
||||
if (io->in.broadcast) {
|
||||
packet->operation |= NBT_FLAG_BROADCAST;
|
||||
}
|
||||
@ -221,6 +225,7 @@ struct composite_context *nbt_name_register_bcast_send(struct nbt_name_socket *n
|
||||
state->io->in.nb_flags = io->in.nb_flags;
|
||||
state->io->in.register_demand = False;
|
||||
state->io->in.broadcast = True;
|
||||
state->io->in.multi_homed = False;
|
||||
state->io->in.ttl = io->in.ttl;
|
||||
state->io->in.timeout = 1;
|
||||
state->io->in.retries = 2;
|
||||
@ -264,3 +269,165 @@ NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock,
|
||||
struct composite_context *c = nbt_name_register_bcast_send(nbtsock, io);
|
||||
return nbt_name_register_bcast_recv(c);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
a wins name register with multiple WINS servers and multiple
|
||||
addresses to register. Try each WINS server in turn, until we get a
|
||||
reply for each address
|
||||
*/
|
||||
struct register_wins_state {
|
||||
struct nbt_name_socket *nbtsock;
|
||||
struct nbt_name_register *io;
|
||||
const char **wins_servers;
|
||||
const char **addresses;
|
||||
int address_idx;
|
||||
struct nbt_name_request *req;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
state handler for WINS multi-homed multi-server name register
|
||||
*/
|
||||
static void name_register_wins_handler(struct nbt_name_request *req)
|
||||
{
|
||||
struct composite_context *c = talloc_get_type(req->async.private,
|
||||
struct composite_context);
|
||||
struct register_wins_state *state = talloc_get_type(c->private,
|
||||
struct register_wins_state);
|
||||
NTSTATUS status;
|
||||
|
||||
status = nbt_name_register_recv(state->req, state, state->io);
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
|
||||
/* the register timed out - try the next WINS server */
|
||||
state->wins_servers++;
|
||||
state->address_idx = 0;
|
||||
if (state->wins_servers[0] == NULL) {
|
||||
c->state = SMBCLI_REQUEST_ERROR;
|
||||
c->status = status;
|
||||
goto done;
|
||||
}
|
||||
state->io->in.dest_addr = state->wins_servers[0];
|
||||
state->io->in.address = state->addresses[0];
|
||||
state->req = nbt_name_register_send(state->nbtsock, state->io);
|
||||
if (state->req == NULL) {
|
||||
c->state = SMBCLI_REQUEST_ERROR;
|
||||
c->status = NT_STATUS_NO_MEMORY;
|
||||
} else {
|
||||
state->req->async.fn = name_register_wins_handler;
|
||||
state->req->async.private = c;
|
||||
}
|
||||
} else if (!NT_STATUS_IS_OK(status)) {
|
||||
c->state = SMBCLI_REQUEST_ERROR;
|
||||
c->status = status;
|
||||
} else {
|
||||
if (state->io->out.rcode == 0 &&
|
||||
state->addresses[state->address_idx+1] != NULL) {
|
||||
/* register our next address */
|
||||
state->io->in.address = state->addresses[++(state->address_idx)];
|
||||
state->req = nbt_name_register_send(state->nbtsock, state->io);
|
||||
if (state->req == NULL) {
|
||||
c->state = SMBCLI_REQUEST_ERROR;
|
||||
c->status = NT_STATUS_NO_MEMORY;
|
||||
} else {
|
||||
state->req->async.fn = name_register_wins_handler;
|
||||
state->req->async.private = c;
|
||||
}
|
||||
} else {
|
||||
c->state = SMBCLI_REQUEST_DONE;
|
||||
c->status = NT_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (c->state >= SMBCLI_REQUEST_DONE &&
|
||||
c->async.fn) {
|
||||
c->async.fn(c);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
the async send call for a multi-server WINS register
|
||||
*/
|
||||
struct composite_context *nbt_name_register_wins_send(struct nbt_name_socket *nbtsock,
|
||||
struct nbt_name_register_wins *io)
|
||||
{
|
||||
struct composite_context *c;
|
||||
struct register_wins_state *state;
|
||||
|
||||
c = talloc_zero(nbtsock, struct composite_context);
|
||||
if (c == NULL) goto failed;
|
||||
|
||||
state = talloc(c, struct register_wins_state);
|
||||
if (state == NULL) goto failed;
|
||||
|
||||
state->io = talloc(state, struct nbt_name_register);
|
||||
if (state->io == NULL) goto failed;
|
||||
|
||||
state->wins_servers = str_list_copy(state, io->in.wins_servers);
|
||||
if (state->wins_servers == NULL ||
|
||||
state->wins_servers[0] == NULL) goto failed;
|
||||
|
||||
state->addresses = str_list_copy(state, io->in.addresses);
|
||||
if (state->addresses == NULL ||
|
||||
state->addresses[0] == NULL) goto failed;
|
||||
|
||||
state->io->in.name = io->in.name;
|
||||
state->io->in.dest_addr = state->wins_servers[0];
|
||||
state->io->in.address = io->in.addresses[0];
|
||||
state->io->in.nb_flags = io->in.nb_flags;
|
||||
state->io->in.broadcast = False;
|
||||
state->io->in.register_demand = False;
|
||||
state->io->in.multi_homed = (io->in.nb_flags & NBT_NM_GROUP)?False:True;
|
||||
state->io->in.ttl = io->in.ttl;
|
||||
state->io->in.timeout = 3;
|
||||
state->io->in.retries = 2;
|
||||
|
||||
state->nbtsock = nbtsock;
|
||||
state->address_idx = 0;
|
||||
|
||||
state->req = nbt_name_register_send(nbtsock, state->io);
|
||||
if (state->req == NULL) goto failed;
|
||||
|
||||
state->req->async.fn = name_register_wins_handler;
|
||||
state->req->async.private = c;
|
||||
|
||||
c->private = state;
|
||||
c->state = SMBCLI_REQUEST_SEND;
|
||||
c->event_ctx = nbtsock->event_ctx;
|
||||
|
||||
return c;
|
||||
|
||||
failed:
|
||||
talloc_free(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
multi-homed WINS name register - recv side
|
||||
*/
|
||||
NTSTATUS nbt_name_register_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
|
||||
struct nbt_name_register_wins *io)
|
||||
{
|
||||
NTSTATUS status;
|
||||
status = composite_wait(c);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
struct register_wins_state *state =
|
||||
talloc_get_type(c->private, struct register_wins_state);
|
||||
io->out.wins_server = talloc_steal(mem_ctx, state->wins_servers[0]);
|
||||
io->out.rcode = state->io->out.rcode;
|
||||
}
|
||||
talloc_free(c);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
multi-homed WINS register - sync interface
|
||||
*/
|
||||
NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct nbt_name_register_wins *io)
|
||||
{
|
||||
struct composite_context *c = nbt_name_register_wins_send(nbtsock, io);
|
||||
return nbt_name_register_wins_recv(c, mem_ctx, io);
|
||||
}
|
||||
|
@ -82,10 +82,10 @@ static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
|
||||
}
|
||||
|
||||
DLIST_REMOVE(nbtsock->send_queue, req);
|
||||
req->state = NBT_REQUEST_WAIT;
|
||||
if (req->is_reply) {
|
||||
talloc_free(req);
|
||||
} else {
|
||||
req->state = NBT_REQUEST_WAIT;
|
||||
EVENT_FD_READABLE(nbtsock->fde);
|
||||
nbtsock->num_pending++;
|
||||
}
|
||||
@ -122,7 +122,11 @@ static void nbt_name_socket_timeout(struct event_context *ev, struct timed_event
|
||||
req->te = event_add_timed(req->nbtsock->event_ctx, req,
|
||||
timeval_add(&t, req->timeout, 0),
|
||||
nbt_name_socket_timeout, req);
|
||||
DLIST_ADD_END(req->nbtsock->send_queue, req, struct nbt_name_request *);
|
||||
if (req->state != NBT_REQUEST_SEND) {
|
||||
req->state = NBT_REQUEST_SEND;
|
||||
DLIST_ADD_END(req->nbtsock->send_queue, req,
|
||||
struct nbt_name_request *);
|
||||
}
|
||||
EVENT_FD_WRITEABLE(req->nbtsock->fde);
|
||||
return;
|
||||
}
|
||||
@ -206,8 +210,12 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
|
||||
/* find the matching request */
|
||||
req = idr_find(nbtsock->idr, packet->name_trn_id);
|
||||
if (req == NULL) {
|
||||
DEBUG(2,("Failed to match request for incoming name packet id 0x%04x\n",
|
||||
packet->name_trn_id));
|
||||
if (nbtsock->unexpected.handler) {
|
||||
nbtsock->unexpected.handler(nbtsock, packet, src_addr, src_port);
|
||||
} else {
|
||||
DEBUG(2,("Failed to match request for incoming name packet id 0x%04x on %p\n",
|
||||
packet->name_trn_id, nbtsock));
|
||||
}
|
||||
talloc_free(tmp_ctx);
|
||||
return;
|
||||
}
|
||||
@ -227,13 +235,11 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
|
||||
req->num_retries = 0;
|
||||
req->received_wack = True;
|
||||
if (packet->answers[0].ttl != 0) {
|
||||
req->timeout = MIN(packet->answers[0].ttl, 20);
|
||||
req->timeout = MIN(packet->answers[0].ttl, 20);
|
||||
}
|
||||
req->te = event_add_timed(req->nbtsock->event_ctx, req,
|
||||
timeval_current_ofs(req->timeout, 0),
|
||||
nbt_name_socket_timeout, req);
|
||||
DLIST_ADD_END(req->nbtsock->send_queue, req, struct nbt_name_request *);
|
||||
EVENT_FD_WRITEABLE(req->nbtsock->fde);
|
||||
req->te = event_add_timed(req->nbtsock->event_ctx, req,
|
||||
timeval_current_ofs(req->timeout, 0),
|
||||
nbt_name_socket_timeout, req);
|
||||
talloc_free(tmp_ctx);
|
||||
return;
|
||||
}
|
||||
@ -319,6 +325,7 @@ struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx,
|
||||
nbtsock->send_queue = NULL;
|
||||
nbtsock->num_pending = 0;
|
||||
nbtsock->incoming.handler = NULL;
|
||||
nbtsock->unexpected.handler = NULL;
|
||||
|
||||
nbtsock->fde = event_add_fd(nbtsock->event_ctx, nbtsock,
|
||||
socket_get_fd(nbtsock->sock), 0,
|
||||
@ -375,6 +382,7 @@ struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
|
||||
UINT16_MAX);
|
||||
}
|
||||
if (id == -1) goto failed;
|
||||
|
||||
request->name_trn_id = id;
|
||||
req->name_trn_id = id;
|
||||
|
||||
|
@ -26,11 +26,15 @@ interface nbt
|
||||
|
||||
/* the opcodes are in the operation field, masked with
|
||||
NBT_OPCODE */
|
||||
const int NBT_OPCODE_QUERY = (0<<11);
|
||||
const int NBT_OPCODE_REGISTER = (5<<11);
|
||||
const int NBT_OPCODE_RELEASE = (6<<11);
|
||||
const int NBT_OPCODE_WACK = (7<<11);
|
||||
const int NBT_OPCODE_REFRESH = (8<<11);
|
||||
typedef enum {
|
||||
NBT_OPCODE_QUERY = (0x0<<11),
|
||||
NBT_OPCODE_REGISTER = (0x5<<11),
|
||||
NBT_OPCODE_RELEASE = (0x6<<11),
|
||||
NBT_OPCODE_WACK = (0x7<<11),
|
||||
NBT_OPCODE_REFRESH = (0x8<<11),
|
||||
NBT_OPCODE_REFRESH2 = (0x9<<11),
|
||||
NBT_OPCODE_MULTI_HOME_REG = (0xf<<11)
|
||||
} nbt_opcode;
|
||||
|
||||
/* rcode values */
|
||||
typedef enum {
|
||||
|
Loading…
x
Reference in New Issue
Block a user