summaryrefslogtreecommitdiff
path: root/source3/libsmb/unexpected.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libsmb/unexpected.c')
-rw-r--r--source3/libsmb/unexpected.c133
1 files changed, 131 insertions, 2 deletions
diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c
index 7f864957a7..0f4227de16 100644
--- a/source3/libsmb/unexpected.c
+++ b/source3/libsmb/unexpected.c
@@ -29,6 +29,117 @@ struct unexpected_key {
int count;
};
+struct pending_unexpected {
+ struct pending_unexpected *prev, *next;
+ enum packet_type packet_type;
+ int id;
+ time_t timeout;
+};
+
+static struct pending_unexpected *pu_list;
+
+/****************************************************************************
+ This function is called when nmbd has received an unexpected packet.
+ It checks against the list of outstanding packet transaction id's
+ to see if it should be stored in the unexpected.tdb.
+**************************************************************************/
+
+static struct pending_unexpected *find_unexpected_packet(struct packet_struct *p)
+{
+ struct pending_unexpected *pu;
+
+ if (!p) {
+ return NULL;
+ }
+
+ for (pu = pu_list; pu; pu = pu->next) {
+ if (pu->packet_type == p->packet_type) {
+ int id = (p->packet_type == DGRAM_PACKET) ?
+ p->packet.dgram.header.dgm_id :
+ p->packet.nmb.header.name_trn_id;
+ if (id == pu->id) {
+ DEBUG(10,("find_unexpected_packet: found packet "
+ "with id = %d\n", pu->id ));
+ return pu;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/****************************************************************************
+ This function is called when nmbd has been given a packet to send out.
+ It stores a list of outstanding packet transaction id's and the timeout
+ when they should be removed.
+**************************************************************************/
+
+bool store_outstanding_send_packet(struct packet_struct *p)
+{
+ struct pending_unexpected *pu = NULL;
+
+ if (!p) {
+ return false;
+ }
+
+ pu = find_unexpected_packet(p);
+ if (pu) {
+ /* This is a resend, and we haven't received a
+ reply yet ! Ignore it. */
+ return false;
+ }
+
+ pu = SMB_MALLOC_P(struct pending_unexpected);
+ if (!pu || !p) {
+ return false;
+ }
+
+ ZERO_STRUCTP(pu);
+ pu->packet_type = p->packet_type;
+ pu->id = (p->packet_type == DGRAM_PACKET) ?
+ p->packet.dgram.header.dgm_id :
+ p->packet.nmb.header.name_trn_id;
+ pu->timeout = time(NULL) + 15;
+
+ DLIST_ADD_END(pu_list, pu, struct pending_unexpected *);
+
+ DEBUG(10,("store_outstanding_unexpected_packet: storing packet "
+ "with id = %d\n", pu->id ));
+
+ return true;
+}
+
+/****************************************************************************
+ Return true if this is a reply to a packet we were requested to send.
+**************************************************************************/
+
+bool is_requested_send_packet(struct packet_struct *p)
+{
+ return (find_unexpected_packet(p) != NULL);
+}
+
+/****************************************************************************
+ This function is called when nmbd has received an unexpected packet.
+ It checks against the list of outstanding packet transaction id's
+ to see if it should be stored in the unexpected.tdb. Don't store if
+ not found.
+**************************************************************************/
+
+static bool should_store_unexpected_packet(struct packet_struct *p)
+{
+ struct pending_unexpected *pu = find_unexpected_packet(p);
+
+ if (!pu) {
+ return false;
+ }
+
+ /* Remove the outstanding entry. */
+ DLIST_REMOVE(pu_list, pu);
+ SAFE_FREE(pu);
+ return true;
+}
+
/****************************************************************************
All unexpected packets are passed in here, to be stored in a unexpected
packet database. This allows nmblookup and other tools to receive packets
@@ -44,6 +155,13 @@ void unexpected_packet(struct packet_struct *p)
int len=0;
uint32_t enc_ip;
+ if (!should_store_unexpected_packet(p)) {
+ DEBUG(10,("Not storing unexpected packet\n"));
+ return;
+ }
+
+ DEBUG(10,("unexpected_packet: storing packet\n"));
+
if (!tdbd) {
tdbd = tdb_wrap_open(NULL, lock_path("unexpected.tdb"), 0,
TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_INCOMPATIBLE_HASH,
@@ -108,6 +226,15 @@ static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *st
void clear_unexpected(time_t t)
{
+ struct pending_unexpected *pu, *pu_next;
+
+ for (pu = pu_list; pu; pu = pu_next) {
+ pu_next = pu->next;
+ if (pu->timeout < t) {
+ DLIST_REMOVE(pu_list, pu);
+ }
+ }
+
if (!tdbd) return;
if ((lastt != 0) && (t < lastt + NMBD_UNEXPECTED_TIMEOUT))
@@ -168,8 +295,10 @@ static int traverse_match(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf,
if ((state->match_type == NMB_PACKET &&
p->packet.nmb.header.name_trn_id == state->match_id) ||
(state->match_type == DGRAM_PACKET &&
- match_mailslot_name(p, state->match_name))) {
+ match_mailslot_name(p, state->match_name) &&
+ p->packet.dgram.header.dgm_id == state->match_id)) {
state->matched_packet = p;
+ tdb_delete(ttdb, kbuf);
return -1;
}
@@ -189,7 +318,7 @@ struct packet_struct *receive_unexpected(enum packet_type packet_type, int id,
struct receive_unexpected_state state;
tdb2 = tdb_wrap_open(talloc_tos(), lock_path("unexpected.tdb"), 0, 0,
- O_RDONLY, 0);
+ O_RDWR, 0);
if (!tdb2) return NULL;
state.matched_packet = NULL;