ldb: use #include <ldb.h> for ldb
[samba.git] / source4 / wrepl_server / wrepl_in_call.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    WINS Replication server
5    
6    Copyright (C) Stefan Metzmacher      2005
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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "lib/events/events.h"
24 #include "lib/tsocket/tsocket.h"
25 #include "smbd/service_task.h"
26 #include "smbd/service_stream.h"
27 #include "libcli/wrepl/winsrepl.h"
28 #include "wrepl_server/wrepl_server.h"
29 #include "libcli/composite/composite.h"
30 #include "nbt_server/wins/winsdb.h"
31 #include <ldb.h>
32 #include <ldb_errors.h>
33 #include "system/time.h"
34 #include "lib/util/tsort.h"
35 #include "param/param.h"
36
37 static NTSTATUS wreplsrv_in_start_association(struct wreplsrv_in_call *call)
38 {
39         struct wrepl_start *start       = &call->req_packet.message.start;
40         struct wrepl_start *start_reply = &call->rep_packet.message.start_reply;
41
42         if (call->req_packet.opcode & WREPL_OPCODE_BITS) {
43                 /*
44                  *if the assoc_ctx doesn't match ignore the packet
45                  */
46                 if ((call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx)
47                    && (call->req_packet.assoc_ctx != 0)) {
48                         return ERROR_INVALID_PARAMETER;
49                 }
50         } else {
51                 call->wreplconn->assoc_ctx.our_ctx = WREPLSRV_INVALID_ASSOC_CTX;
52                 return NT_STATUS_OK;
53         }
54
55 /*
56  * it seems that we don't know all details about the start_association
57  * to support replication with NT4 (it sends 1.1 instead of 5.2)
58  * we ignore the version numbers until we know all details
59  */
60 #if 0
61         if (start->minor_version != 2 || start->major_version != 5) {
62                 /* w2k terminate the connection if the versions doesn't match */
63                 return NT_STATUS_UNKNOWN_REVISION;
64         }
65 #endif
66
67         call->wreplconn->assoc_ctx.stopped      = false;
68         call->wreplconn->assoc_ctx.our_ctx      = WREPLSRV_VALID_ASSOC_CTX;
69         call->wreplconn->assoc_ctx.peer_ctx     = start->assoc_ctx;
70
71         call->rep_packet.mess_type              = WREPL_START_ASSOCIATION_REPLY;
72         start_reply->assoc_ctx                  = call->wreplconn->assoc_ctx.our_ctx;
73         start_reply->minor_version              = 2;
74         start_reply->major_version              = 5;
75
76         /*
77          * nt4 uses 41 bytes for the start_association call
78          * so do it the same and as we don't know the meanings of this bytes
79          * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
80          *
81          * if we don't do this nt4 uses an old version of the wins replication protocol
82          * and that would break nt4 <-> samba replication
83          */
84         call->rep_packet.padding                = data_blob_talloc(call, NULL, 21);
85         NT_STATUS_HAVE_NO_MEMORY(call->rep_packet.padding.data);
86
87         memset(call->rep_packet.padding.data, 0, call->rep_packet.padding.length);
88
89         return NT_STATUS_OK;
90 }
91
92 static NTSTATUS wreplsrv_in_stop_assoc_ctx(struct wreplsrv_in_call *call)
93 {
94         struct wrepl_stop *stop_out             = &call->rep_packet.message.stop;
95
96         call->wreplconn->assoc_ctx.stopped      = true;
97
98         call->rep_packet.mess_type              = WREPL_STOP_ASSOCIATION;
99         stop_out->reason                        = 4;
100
101         return NT_STATUS_OK;
102 }
103
104 static NTSTATUS wreplsrv_in_stop_association(struct wreplsrv_in_call *call)
105 {
106         /*
107          * w2k only check the assoc_ctx if the opcode has the 0x00007800 bits are set
108          */
109         if (call->req_packet.opcode & WREPL_OPCODE_BITS) {
110                 /*
111                  *if the assoc_ctx doesn't match ignore the packet
112                  */
113                 if (call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx) {
114                         return ERROR_INVALID_PARAMETER;
115                 }
116                 /* when the opcode bits are set the connection should be directly terminated */
117                 return NT_STATUS_CONNECTION_RESET;
118         }
119
120         if (call->wreplconn->assoc_ctx.stopped) {
121                 /* this causes the connection to be directly terminated */
122                 return NT_STATUS_CONNECTION_RESET;
123         }
124
125         /* this will cause to not receive packets anymore and terminate the connection if the reply is send */
126         call->terminate_after_send = true;
127         return wreplsrv_in_stop_assoc_ctx(call);
128 }
129
130 static NTSTATUS wreplsrv_in_table_query(struct wreplsrv_in_call *call)
131 {
132         struct wreplsrv_service *service = call->wreplconn->service;
133         struct wrepl_replication *repl_out = &call->rep_packet.message.replication;
134         struct wrepl_table *table_out = &call->rep_packet.message.replication.info.table;
135
136         repl_out->command = WREPL_REPL_TABLE_REPLY;
137
138         return wreplsrv_fill_wrepl_table(service, call, table_out,
139                                          service->wins_db->local_owner, true);
140 }
141
142 static int wreplsrv_in_sort_wins_name(struct wrepl_wins_name *n1,
143                                       struct wrepl_wins_name *n2)
144 {
145         if (n1->id < n2->id) return -1;
146         if (n1->id > n2->id) return 1;
147         return 0;
148 }
149
150 static NTSTATUS wreplsrv_record2wins_name(TALLOC_CTX *mem_ctx,
151                                           struct wrepl_wins_name *name,
152                                           struct winsdb_record *rec)
153 {
154         uint32_t num_ips, i;
155         struct wrepl_ip *ips;
156
157         name->name              = rec->name;
158         talloc_steal(mem_ctx, rec->name);
159
160         name->id                = rec->version;
161         name->unknown           = "255.255.255.255";
162
163         name->flags             = WREPL_NAME_FLAGS(rec->type, rec->state, rec->node, rec->is_static);
164
165         switch (name->flags & 2) {
166         case 0:
167                 name->addresses.ip                      = rec->addresses[0]->address;
168                 talloc_steal(mem_ctx, rec->addresses[0]->address);
169                 break;
170         case 2:
171                 num_ips = winsdb_addr_list_length(rec->addresses);
172                 ips     = talloc_array(mem_ctx, struct wrepl_ip, num_ips);
173                 NT_STATUS_HAVE_NO_MEMORY(ips);
174
175                 for (i = 0; i < num_ips; i++) {
176                         ips[i].owner    = rec->addresses[i]->wins_owner;
177                         talloc_steal(ips, rec->addresses[i]->wins_owner);
178                         ips[i].ip       = rec->addresses[i]->address;
179                         talloc_steal(ips, rec->addresses[i]->address);
180                 }
181
182                 name->addresses.addresses.num_ips       = num_ips;
183                 name->addresses.addresses.ips           = ips;
184                 break;
185         }
186
187         return NT_STATUS_OK;
188 }
189
190 static NTSTATUS wreplsrv_in_send_request(struct wreplsrv_in_call *call)
191 {
192         struct wreplsrv_service *service = call->wreplconn->service;
193         struct wrepl_wins_owner *owner_in = &call->req_packet.message.replication.info.owner;
194         struct wrepl_replication *repl_out = &call->rep_packet.message.replication;
195         struct wrepl_send_reply *reply_out = &call->rep_packet.message.replication.info.reply;
196         struct wreplsrv_owner *owner;
197         const char *owner_filter;
198         const char *filter;
199         struct ldb_result *res = NULL;
200         int ret;
201         struct wrepl_wins_name *names;
202         struct winsdb_record *rec;
203         NTSTATUS status;
204         unsigned int i, j;
205         time_t now = time(NULL);
206
207         owner = wreplsrv_find_owner(service, service->table, owner_in->address);
208
209         repl_out->command       = WREPL_REPL_SEND_REPLY;
210         reply_out->num_names    = 0;
211         reply_out->names        = NULL;
212
213         /*
214          * if we didn't know this owner, must be a bug in the partners client code...
215          * return an empty list.
216          */
217         if (!owner) {
218                 DEBUG(2,("WINSREPL:reply [0] records unknown owner[%s] to partner[%s]\n",
219                         owner_in->address, call->wreplconn->partner->address));
220                 return NT_STATUS_OK;
221         }
222
223         /*
224          * the client sends a max_version of 0, interpret it as
225          * (uint64_t)-1
226          */
227         if (owner_in->max_version == 0) {
228                 owner_in->max_version = (uint64_t)-1;
229         }
230
231         /*
232          * if the partner ask for nothing, or give invalid ranges,
233          * return an empty list.
234          */
235         if (owner_in->min_version > owner_in->max_version) {
236                 DEBUG(2,("WINSREPL:reply [0] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",
237                         owner_in->address, 
238                         (long long)owner_in->min_version, 
239                         (long long)owner_in->max_version,
240                         call->wreplconn->partner->address));
241                 return NT_STATUS_OK;
242         }
243
244         /*
245          * if the partner has already all records for nothing, or give invalid ranges,
246          * return an empty list.
247          */
248         if (owner_in->min_version > owner->owner.max_version) {
249                 DEBUG(2,("WINSREPL:reply [0] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",
250                         owner_in->address, 
251                         (long long)owner_in->min_version, 
252                         (long long)owner_in->max_version,
253                         call->wreplconn->partner->address));
254                 return NT_STATUS_OK;
255         }
256
257         owner_filter = wreplsrv_owner_filter(service, call, owner->owner.address);
258         NT_STATUS_HAVE_NO_MEMORY(owner_filter);
259         filter = talloc_asprintf(call,
260                                  "(&%s(objectClass=winsRecord)"
261                                  "(|(recordState=%u)(recordState=%u))"
262                                  "(versionID>=%llu)(versionID<=%llu))",
263                                  owner_filter,
264                                  WREPL_STATE_ACTIVE, WREPL_STATE_TOMBSTONE,
265                                  (long long)owner_in->min_version, 
266                                  (long long)owner_in->max_version);
267         NT_STATUS_HAVE_NO_MEMORY(filter);
268         ret = ldb_search(service->wins_db->ldb, call, &res, NULL, LDB_SCOPE_SUBTREE, NULL, "%s", filter);
269         if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
270         DEBUG(10,("WINSREPL: filter '%s' count %d\n", filter, res->count));
271
272         if (res->count == 0) {
273                 DEBUG(2,("WINSREPL:reply [%u] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",
274                         res->count, owner_in->address, 
275                         (long long)owner_in->min_version, 
276                         (long long)owner_in->max_version,
277                         call->wreplconn->partner->address));
278                 return NT_STATUS_OK;
279         }
280
281         names = talloc_array(call, struct wrepl_wins_name, res->count);
282         NT_STATUS_HAVE_NO_MEMORY(names);
283
284         for (i=0, j=0; i < res->count; i++) {
285                 status = winsdb_record(service->wins_db, res->msgs[i], call, now, &rec);
286                 NT_STATUS_NOT_OK_RETURN(status);
287
288                 /*
289                  * it's possible that winsdb_record() made the record RELEASED
290                  * because it's expired, but in the database it's still stored
291                  * as ACTIVE...
292                  *
293                  * make sure we really only replicate ACTIVE and TOMBSTONE records
294                  */
295                 if (rec->state == WREPL_STATE_ACTIVE || rec->state == WREPL_STATE_TOMBSTONE) {
296                         status = wreplsrv_record2wins_name(names, &names[j], rec);
297                         NT_STATUS_NOT_OK_RETURN(status);
298                         j++;
299                 }
300
301                 talloc_free(rec);
302                 talloc_free(res->msgs[i]);
303         }
304
305         /* sort the names before we send them */
306         TYPESAFE_QSORT(names, j, wreplsrv_in_sort_wins_name);
307
308         DEBUG(2,("WINSREPL:reply [%u] records owner[%s] min[%llu] max[%llu] to partner[%s]\n",
309                 j, owner_in->address, 
310                 (long long)owner_in->min_version, 
311                 (long long)owner_in->max_version,
312                 call->wreplconn->partner->address));
313
314         reply_out->num_names    = j;
315         reply_out->names        = names;
316
317         return NT_STATUS_OK;
318 }
319
320 struct wreplsrv_in_update_state {
321         struct wreplsrv_in_connection *wrepl_in;
322         struct wreplsrv_out_connection *wrepl_out;
323         struct composite_context *creq;
324         struct wreplsrv_pull_cycle_io cycle_io;
325 };
326
327 static void wreplsrv_in_update_handler(struct composite_context *creq)
328 {
329         struct wreplsrv_in_update_state *update_state = talloc_get_type(creq->async.private_data,
330                                                         struct wreplsrv_in_update_state);
331         NTSTATUS status;
332
333         status = wreplsrv_pull_cycle_recv(creq);
334
335         talloc_free(update_state->wrepl_out);
336
337         wreplsrv_terminate_in_connection(update_state->wrepl_in, nt_errstr(status));
338 }
339
340 static NTSTATUS wreplsrv_in_update(struct wreplsrv_in_call *call)
341 {
342         struct wreplsrv_in_connection *wrepl_in = call->wreplconn;
343         struct wreplsrv_out_connection *wrepl_out;
344         struct wrepl_table *update_in = &call->req_packet.message.replication.info.table;
345         struct wreplsrv_in_update_state *update_state;
346         NTSTATUS status;
347
348         DEBUG(2,("WREPL_REPL_UPDATE: partner[%s] initiator[%s] num_owners[%u]\n",
349                 call->wreplconn->partner->address,
350                 update_in->initiator, update_in->partner_count));
351
352         update_state = talloc(wrepl_in, struct wreplsrv_in_update_state);
353         NT_STATUS_HAVE_NO_MEMORY(update_state);
354
355         wrepl_out = talloc(update_state, struct wreplsrv_out_connection);
356         NT_STATUS_HAVE_NO_MEMORY(wrepl_out);
357         wrepl_out->service              = wrepl_in->service;
358         wrepl_out->partner              = wrepl_in->partner;
359         wrepl_out->assoc_ctx.our_ctx    = wrepl_in->assoc_ctx.our_ctx;
360         wrepl_out->assoc_ctx.peer_ctx   = wrepl_in->assoc_ctx.peer_ctx;
361         wrepl_out->sock                 = wrepl_socket_init(wrepl_out,
362                                                             wrepl_in->conn->event.ctx);
363                                                             
364         NT_STATUS_HAVE_NO_MEMORY_AND_FREE(wrepl_out->sock, update_state);
365
366         TALLOC_FREE(wrepl_in->send_queue);
367
368         status = wrepl_socket_donate_stream(wrepl_out->sock, &wrepl_in->tstream);
369         NT_STATUS_NOT_OK_RETURN_AND_FREE(status, update_state);
370
371         update_state->wrepl_in                  = wrepl_in;
372         update_state->wrepl_out                 = wrepl_out;
373         update_state->cycle_io.in.partner       = wrepl_out->partner;
374         update_state->cycle_io.in.num_owners    = update_in->partner_count;
375         update_state->cycle_io.in.owners        = update_in->partners;
376         talloc_steal(update_state, update_in->partners);
377         update_state->cycle_io.in.wreplconn     = wrepl_out;
378         update_state->creq = wreplsrv_pull_cycle_send(update_state, &update_state->cycle_io);
379         if (!update_state->creq) {
380                 talloc_free(update_state);
381                 return NT_STATUS_INTERNAL_ERROR;
382         }
383
384         update_state->creq->async.fn            = wreplsrv_in_update_handler;
385         update_state->creq->async.private_data  = update_state;
386
387         return ERROR_INVALID_PARAMETER;
388 }
389
390 static NTSTATUS wreplsrv_in_update2(struct wreplsrv_in_call *call)
391 {
392         return wreplsrv_in_update(call);
393 }
394
395 static NTSTATUS wreplsrv_in_inform(struct wreplsrv_in_call *call)
396 {
397         struct wrepl_table *inform_in = &call->req_packet.message.replication.info.table;
398
399         DEBUG(2,("WREPL_REPL_INFORM: partner[%s] initiator[%s] num_owners[%u]\n",
400                 call->wreplconn->partner->address,
401                 inform_in->initiator, inform_in->partner_count));
402
403         wreplsrv_out_partner_pull(call->wreplconn->partner, inform_in);
404
405         /* we don't reply to WREPL_REPL_INFORM messages */
406         return ERROR_INVALID_PARAMETER;
407 }
408
409 static NTSTATUS wreplsrv_in_inform2(struct wreplsrv_in_call *call)
410 {
411         return wreplsrv_in_inform(call);
412 }
413
414 static NTSTATUS wreplsrv_in_replication(struct wreplsrv_in_call *call)
415 {
416         struct wrepl_replication *repl_in = &call->req_packet.message.replication;
417         NTSTATUS status;
418
419         /*
420          * w2k only check the assoc_ctx if the opcode has the 0x00007800 bits are set
421          */
422         if (call->req_packet.opcode & WREPL_OPCODE_BITS) {
423                 /*
424                  *if the assoc_ctx doesn't match ignore the packet
425                  */
426                 if (call->req_packet.assoc_ctx != call->wreplconn->assoc_ctx.our_ctx) {
427                         return ERROR_INVALID_PARAMETER;
428                 }
429         }
430
431         if (!call->wreplconn->partner) {
432                 struct tsocket_address *peer_addr = call->wreplconn->conn->remote_address;
433                 char *peer_ip;
434
435                 if (!tsocket_address_is_inet(peer_addr, "ipv4")) {
436                         DEBUG(0,("wreplsrv_in_replication: non ipv4 peer addr '%s'\n",
437                                 tsocket_address_string(peer_addr, call)));
438                         return NT_STATUS_INTERNAL_ERROR;
439                 }
440
441                 peer_ip = tsocket_address_inet_addr_string(peer_addr, call);
442                 if (peer_ip == NULL) {
443                         return NT_STATUS_NO_MEMORY;
444                 }
445
446                 call->wreplconn->partner = wreplsrv_find_partner(call->wreplconn->service, peer_ip);
447                 if (!call->wreplconn->partner) {
448                         DEBUG(1,("Failing WINS replication from non-partner %s\n", peer_ip));
449                         return wreplsrv_in_stop_assoc_ctx(call);
450                 }
451         }
452
453         switch (repl_in->command) {
454                 case WREPL_REPL_TABLE_QUERY:
455                         if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PUSH)) {
456                                 DEBUG(0,("Failing WINS replication TABLE_QUERY from non-push-partner %s\n",
457                                          call->wreplconn->partner->address));
458                                 return wreplsrv_in_stop_assoc_ctx(call);
459                         }
460                         status = wreplsrv_in_table_query(call);
461                         break;
462
463                 case WREPL_REPL_TABLE_REPLY:
464                         return ERROR_INVALID_PARAMETER;
465
466                 case WREPL_REPL_SEND_REQUEST:
467                         if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PUSH)) {
468                                 DEBUG(0,("Failing WINS replication SEND_REQUESET from non-push-partner %s\n",
469                                          call->wreplconn->partner->address));
470                                 return wreplsrv_in_stop_assoc_ctx(call);
471                         }
472                         status = wreplsrv_in_send_request(call);
473                         break;
474
475                 case WREPL_REPL_SEND_REPLY:
476                         return ERROR_INVALID_PARAMETER;
477         
478                 case WREPL_REPL_UPDATE:
479                         if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
480                                 DEBUG(0,("Failing WINS replication UPDATE from non-pull-partner %s\n",
481                                          call->wreplconn->partner->address));
482                                 return wreplsrv_in_stop_assoc_ctx(call);
483                         }
484                         status = wreplsrv_in_update(call);
485                         break;
486
487                 case WREPL_REPL_UPDATE2:
488                         if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
489                                 DEBUG(0,("Failing WINS replication UPDATE2 from non-pull-partner %s\n",
490                                          call->wreplconn->partner->address));
491                                 return wreplsrv_in_stop_assoc_ctx(call);
492                         }
493                         status = wreplsrv_in_update2(call);
494                         break;
495
496                 case WREPL_REPL_INFORM:
497                         if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
498                                 DEBUG(0,("Failing WINS replication INFORM from non-pull-partner %s\n",
499                                          call->wreplconn->partner->address));
500                                 return wreplsrv_in_stop_assoc_ctx(call);
501                         }
502                         status = wreplsrv_in_inform(call);
503                         break;
504
505                 case WREPL_REPL_INFORM2:
506                         if (!(call->wreplconn->partner->type & WINSREPL_PARTNER_PULL)) {
507                                 DEBUG(0,("Failing WINS replication INFORM2 from non-pull-partner %s\n",
508                                          call->wreplconn->partner->address));
509                                 return wreplsrv_in_stop_assoc_ctx(call);
510                         }
511                         status = wreplsrv_in_inform2(call);
512                         break;
513
514                 default:
515                         return ERROR_INVALID_PARAMETER;
516         }
517
518         if (NT_STATUS_IS_OK(status)) {
519                 call->rep_packet.mess_type = WREPL_REPLICATION;
520         }
521
522         return status;
523 }
524
525 static NTSTATUS wreplsrv_in_invalid_assoc_ctx(struct wreplsrv_in_call *call)
526 {
527         struct wrepl_start *start       = &call->rep_packet.message.start;
528
529         call->rep_packet.opcode         = 0x00008583;
530         call->rep_packet.assoc_ctx      = 0;
531         call->rep_packet.mess_type      = WREPL_START_ASSOCIATION;
532
533         start->assoc_ctx                = 0x0000000a;
534         start->minor_version            = 0x0001;
535         start->major_version            = 0x0000;
536
537         call->rep_packet.padding        = data_blob_talloc(call, NULL, 4);
538         memset(call->rep_packet.padding.data, '\0', call->rep_packet.padding.length);
539
540         return NT_STATUS_OK;
541 }
542
543 NTSTATUS wreplsrv_in_call(struct wreplsrv_in_call *call)
544 {
545         NTSTATUS status;
546
547         if (!(call->req_packet.opcode & WREPL_OPCODE_BITS)
548             && (call->wreplconn->assoc_ctx.our_ctx == WREPLSRV_INVALID_ASSOC_CTX)) {
549                 return wreplsrv_in_invalid_assoc_ctx(call);
550         }
551
552         switch (call->req_packet.mess_type) {
553                 case WREPL_START_ASSOCIATION:
554                         status = wreplsrv_in_start_association(call);
555                         break;
556                 case WREPL_START_ASSOCIATION_REPLY:
557                         /* this is not valid here, so we ignore it */
558                         return ERROR_INVALID_PARAMETER;
559
560                 case WREPL_STOP_ASSOCIATION:
561                         status = wreplsrv_in_stop_association(call);
562                         break;
563
564                 case WREPL_REPLICATION:
565                         status = wreplsrv_in_replication(call);
566                         break;
567                 default:
568                         /* everythingelse is also not valid here, so we ignore it */
569                         return ERROR_INVALID_PARAMETER;
570         }
571
572         if (call->wreplconn->assoc_ctx.our_ctx == WREPLSRV_INVALID_ASSOC_CTX) {
573                 return wreplsrv_in_invalid_assoc_ctx(call);
574         }
575
576         if (NT_STATUS_IS_OK(status)) {
577                 /* let the backend to set some of the opcode bits, but always add the standards */
578                 call->rep_packet.opcode         |= WREPL_OPCODE_BITS;
579                 call->rep_packet.assoc_ctx      = call->wreplconn->assoc_ctx.peer_ctx;
580         }
581
582         return status;
583 }