From 939fabd80993dfea82da06824703ac73b3ea40b8 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Mon, 6 Oct 2008 14:46:22 +0000 Subject: [PATCH] 0x20 fallback code. git-svn-id: file:///svn/unbound/trunk@1285 be551aaa-1e26-0410-a405-d3ace91eadb9 --- daemon/worker.c | 14 ++++--- doc/Changelog | 2 + iterator/iter_utils.c | 57 ++++++++++++++++++++++++++ iterator/iter_utils.h | 10 +++++ iterator/iterator.c | 66 +++++++++++++++++++++++++++++- iterator/iterator.h | 7 ++++ libunbound/libworker.c | 14 ++++--- services/mesh.c | 11 +++-- services/mesh.h | 4 +- services/outside_network.c | 19 +++++---- testdata/fwd_capsid.tpkg | Bin 0 -> 1650 bytes testdata/fwd_capsid_fallback.tpkg | Bin 0 -> 1755 bytes util/module.c | 1 + util/module.h | 2 + util/netevent.h | 2 + 15 files changed, 181 insertions(+), 28 deletions(-) create mode 100644 testdata/fwd_capsid.tpkg create mode 100644 testdata/fwd_capsid_fallback.tpkg diff --git a/daemon/worker.c b/daemon/worker.c index 3c06c552b..19a1271dd 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -211,7 +211,7 @@ worker_handle_reply(struct comm_point* c, void* arg, int error, e.qsent = NULL; if(error != 0) { - mesh_report_reply(worker->env.mesh, &e, 0, reply_info); + mesh_report_reply(worker->env.mesh, &e, reply_info, error); worker_mem_report(worker, NULL); return 0; } @@ -222,11 +222,12 @@ worker_handle_reply(struct comm_point* c, void* arg, int error, || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { /* error becomes timeout for the module as if this reply * never arrived. */ - mesh_report_reply(worker->env.mesh, &e, 0, reply_info); + mesh_report_reply(worker->env.mesh, &e, reply_info, + NETEVENT_TIMEOUT); worker_mem_report(worker, NULL); return 0; } - mesh_report_reply(worker->env.mesh, &e, 1, reply_info); + mesh_report_reply(worker->env.mesh, &e, reply_info, NETEVENT_NOERROR); worker_mem_report(worker, NULL); return 0; } @@ -241,7 +242,7 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error, verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate); if(error != 0) { - mesh_report_reply(worker->env.mesh, e, 0, reply_info); + mesh_report_reply(worker->env.mesh, e, reply_info, error); worker_mem_report(worker, sq); return 0; } @@ -253,11 +254,12 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error, /* error becomes timeout for the module as if this reply * never arrived. */ verbose(VERB_ALGO, "worker: bad reply handled as timeout"); - mesh_report_reply(worker->env.mesh, e, 0, reply_info); + mesh_report_reply(worker->env.mesh, e, reply_info, + NETEVENT_TIMEOUT); worker_mem_report(worker, sq); return 0; } - mesh_report_reply(worker->env.mesh, e, 1, reply_info); + mesh_report_reply(worker->env.mesh, e, reply_info, NETEVENT_NOERROR); worker_mem_report(worker, sq); return 0; } diff --git a/doc/Changelog b/doc/Changelog index 069adddfb..6606ad501 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,5 +1,7 @@ 6 October 2008: Wouter - jostle-timeout option, so you can config for slow links. + - 0x20 fallback code. Tries 3xnumber of nameserver addresses + queries that must all be the same. Sent to random nameservers. 2 October 2008: Wouter - fixup unlink of pidfile. diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index d9ea574b1..4c8942199 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -484,3 +484,60 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp, return 1; return 0; } + +/** + * check equality of two rrsets + * @param k1: rrset + * @param k2: rrset + * @return true if equal + */ +static int +rrset_equal(struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2) +{ + struct packed_rrset_data* d1 = (struct packed_rrset_data*) + k1->entry.data; + struct packed_rrset_data* d2 = (struct packed_rrset_data*) + k2->entry.data; + size_t i, t; + if(k1->rk.dname_len != k2->rk.dname_len || + k1->rk.flags != k2->rk.flags || + k1->rk.type != k2->rk.type || + k1->rk.rrset_class != k2->rk.rrset_class || + query_dname_compare(k1->rk.dname, k2->rk.dname) != 0) + return 0; + if(d1->ttl != d2->ttl || + d1->count != d2->count || + d1->rrsig_count != d2->rrsig_count || + d1->trust != d2->trust || + d1->security != d2->security) + return 0; + t = d1->count + d1->rrsig_count; + for(i=0; irr_len[i] != d2->rr_len[i] || + d1->rr_ttl[i] != d2->rr_ttl[i] || + memcmp(d1->rr_data[i], d2->rr_data[i], + d1->rr_len[i]) != 0) + return 0; + } + return 1; +} + +int +reply_equal(struct reply_info* p, struct reply_info* q) +{ + size_t i; + if(p->flags != q->flags || + p->qdcount != q->qdcount || + p->ttl != q->ttl || + p->security != q->security || + p->an_numrrsets != q->an_numrrsets || + p->ns_numrrsets != q->ns_numrrsets || + p->ar_numrrsets != q->ar_numrrsets || + p->rrset_count != q->rrset_count) + return 0; + for(i=0; irrset_count; i++) { + if(!rrset_equal(p->rrsets[i], q->rrsets[i])) + return 0; + } + return 1; +} diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index 7055fbaa6..1d3872294 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -180,4 +180,14 @@ int iter_msg_has_dnssec(struct dns_msg* msg); int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp, enum response_type type, uint16_t dclass); +/** + * Check if two replies are equal + * For fallback procedures + * @param p: reply one. The reply has rrset data pointers in region. + * Does not check rrset-IDs + * @param q: reply two + * @return if one and two are equal. + */ +int reply_equal(struct reply_info* p, struct reply_info* q); + #endif /* ITERATOR_ITER_UTILS_H */ diff --git a/iterator/iterator.c b/iterator/iterator.c index 0decd27be..4f2a25f5b 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1153,11 +1153,41 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, tf_policy = ie->target_fetch_policy[iq->depth]; } + /* if in 0x20 fallback get as many targets as possible */ + if(iq->caps_fallback) { + int extra = 0; + size_t naddr, nres, navail; + if(!query_for_targets(qstate, iq, ie, id, -1, &extra)) { + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } + iq->num_target_queries += extra; + if(iq->num_target_queries > 0) { + /* wait to get all targets, we want to try em */ + verbose(VERB_ALGO, "wait for all targets for fallback"); + return 0; + } + /* did we do enough fallback queries already? */ + delegpt_count_addr(iq->dp, &naddr, &nres, &navail); + /* the current caps_server is the number of fallbacks sent. + * the original query is one that matched too, so we have + * caps_server+1 number of matching queries now */ + if(iq->caps_server+1 >= naddr*3) { + /* we're done, process the response */ + verbose(VERB_ALGO, "0x20 fallback had %d responses " + "match for %d wanted, done.", + (int)iq->caps_server+1, (int)naddr*3); + iq->caps_fallback = 0; + iq->state = QUERY_RESP_STATE; + return 1; + } + verbose(VERB_ALGO, "0x20 fallback number %d", + (int)iq->caps_server); + /* if there is a policy to fetch missing targets * opportunistically, do it. we rely on the fact that once a * query (or queries) for a missing name have been issued, * they will not be show up again. */ - if(tf_policy != 0) { + } else if(tf_policy != 0) { int extra = 0; verbose(VERB_ALGO, "attempt to get extra %d targets", tf_policy); @@ -1760,7 +1790,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, if(event == module_event_noreply || event == module_event_error) { goto handle_it; } - if(event != module_event_reply || !qstate->reply) { + if( (event != module_event_reply && event != module_event_capsfail) + || !qstate->reply) { log_err("Bad event combined with response"); outbound_list_remove(&iq->outlist, outbound); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); @@ -1804,6 +1835,37 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, if(verbosity >= VERB_ALGO) log_dns_msg("incoming scrubbed packet:", &iq->response->qinfo, iq->response->rep); + + if(event == module_event_capsfail) { + if(!iq->caps_fallback) { + /* start fallback */ + iq->caps_fallback = 1; + iq->caps_server = 0; + iq->caps_reply = iq->response->rep; + iq->state = QUERYTARGETS_STATE; + iq->num_current_queries--; + verbose(VERB_DETAIL, "Capsforid: starting fallback"); + goto handle_it; + } else { + /* check if reply is the same, otherwise, fail */ + if(!reply_equal(iq->response->rep, iq->caps_reply)) { + verbose(VERB_DETAIL, "Capsforid fallback: " + "getting different replies, failed"); + outbound_list_remove(&iq->outlist, outbound); + (void)error_response(qstate, id, + LDNS_RCODE_SERVFAIL); + return; + } + /* continue the fallback procedure at next server */ + iq->caps_server++; + iq->state = QUERYTARGETS_STATE; + iq->num_current_queries--; + verbose(VERB_DETAIL, "Capsforid: reply is equal. " + "go to next fallback"); + goto handle_it; + } + } + iq->caps_fallback = 0; /* if we were in fallback, 0x20 is OK now */ handle_it: outbound_list_remove(&iq->outlist, outbound); diff --git a/iterator/iterator.h b/iterator/iterator.h index 775e50d3c..f8b1b2ca0 100644 --- a/iterator/iterator.h +++ b/iterator/iterator.h @@ -218,6 +218,13 @@ struct iter_qstate { */ struct delegpt* dp; + /** state for 0x20 fallback when capsfail happens, 0 not a fallback */ + int caps_fallback; + /** state for capsfail: current server number to try */ + size_t caps_server; + /** state for capsfail: stored query for comparisons */ + struct reply_info* caps_reply; + /** Current delegation message - returned for non-RD queries */ struct dns_msg* deleg_msg; diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 846d90b86..47e1b378f 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -695,7 +695,7 @@ libworker_handle_reply(struct comm_point* c, void* arg, int error, e.qsent = NULL; if(error != 0) { - mesh_report_reply(lw->env->mesh, &e, 0, reply_info); + mesh_report_reply(lw->env->mesh, &e, reply_info, error); return 0; } /* sanity check. */ @@ -705,10 +705,11 @@ libworker_handle_reply(struct comm_point* c, void* arg, int error, || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { /* error becomes timeout for the module as if this reply * never arrived. */ - mesh_report_reply(lw->env->mesh, &e, 0, reply_info); + mesh_report_reply(lw->env->mesh, &e, reply_info, + NETEVENT_TIMEOUT); return 0; } - mesh_report_reply(lw->env->mesh, &e, 1, reply_info); + mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR); return 0; } @@ -720,7 +721,7 @@ libworker_handle_service_reply(struct comm_point* c, void* arg, int error, struct libworker* lw = (struct libworker*)e->qstate->env->worker; if(error != 0) { - mesh_report_reply(lw->env->mesh, e, 0, reply_info); + mesh_report_reply(lw->env->mesh, e, reply_info, error); return 0; } /* sanity check. */ @@ -730,10 +731,11 @@ libworker_handle_service_reply(struct comm_point* c, void* arg, int error, || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { /* error becomes timeout for the module as if this reply * never arrived. */ - mesh_report_reply(lw->env->mesh, e, 0, reply_info); + mesh_report_reply(lw->env->mesh, e, reply_info, + NETEVENT_TIMEOUT); return 0; } - mesh_report_reply(lw->env->mesh, e, 1, reply_info); + mesh_report_reply(lw->env->mesh, e, reply_info, NETEVENT_NOERROR); return 0; } diff --git a/services/mesh.c b/services/mesh.c index 3b0f3b8d9..b3ad7f2a2 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -363,11 +363,16 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, } void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e, - int is_ok, struct comm_reply* reply) + struct comm_reply* reply, int what) { + enum module_ev event = module_event_reply; e->qstate->reply = reply; - mesh_run(mesh, e->qstate->mesh_info, - is_ok?module_event_reply:module_event_noreply, e); + if(what != NETEVENT_NOERROR) { + event = module_event_noreply; + if(what == NETEVENT_CAPSFAIL) + event = module_event_capsfail; + } + mesh_run(mesh, e->qstate->mesh_info, event, e); } struct mesh_state* diff --git a/services/mesh.h b/services/mesh.h index 259002127..61c5bd111 100644 --- a/services/mesh.h +++ b/services/mesh.h @@ -289,11 +289,11 @@ int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, * * @param mesh: the query mesh. * @param e: outbound entry, with query state to run and reply pointer. - * @param is_ok: if true, reply is OK, otherwise a timeout happened. * @param reply: the comm point reply info. + * @param what: NETEVENT_* error code (if not 0, what is wrong, TIMEOUT). */ void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e, - int is_ok, struct comm_reply* reply); + struct comm_reply* reply, int what); /* ------------------- Functions for module environment --------------- */ diff --git a/services/outside_network.c b/services/outside_network.c index 2e6a185ff..003dfb902 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -1284,22 +1284,23 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c, == LDNS_RCODE_NOERROR || LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer)) == LDNS_RCODE_NXDOMAIN)) { - verbose(VERB_OPS, "no qname in reply to check 0x20ID"); - log_addr(VERB_OPS, "from server", + verbose(VERB_DETAIL, "no qname in reply to check 0x20ID"); + log_addr(VERB_DETAIL, "from server", &sq->addr, sq->addrlen); - log_buf(VERB_OPS, "for packet", c->buffer); + log_buf(VERB_DETAIL, "for packet", c->buffer); error = NETEVENT_CLOSED; c = NULL; } else if(ldns_buffer_read_u16_at(c->buffer, 4) > 0 && !serviced_check_qname(c->buffer, sq->qbuf, sq->qbuflen)) { - verbose(VERB_OPS, "wrong 0x20-ID in reply qname, " - "answer dropped"); - log_addr(VERB_OPS, "from server", + verbose(VERB_DETAIL, "wrong 0x20-ID in reply qname"); + log_addr(VERB_DETAIL, "from server", &sq->addr, sq->addrlen); - log_buf(VERB_OPS, "for packet", c->buffer); - error = NETEVENT_CLOSED; - c = NULL; + log_buf(VERB_DETAIL, "for packet", c->buffer); + error = NETEVENT_CAPSFAIL; + /* and cleanup too */ + pkt_dname_tolower(c->buffer, + ldns_buffer_at(c->buffer, 12)); } else { verbose(VERB_ALGO, "good 0x20-ID in reply qname"); /* cleanup caps, prettier cache contents. */ diff --git a/testdata/fwd_capsid.tpkg b/testdata/fwd_capsid.tpkg new file mode 100644 index 0000000000000000000000000000000000000000..da16f4316d9a88604d08fa436c7ac87eab25f8ea GIT binary patch literal 1650 zcmV-&295b2iwFSBAnHf}1MOLRbJ|7__rKhy*vO2XOe!IXS4#|I0=RJ-gM)G1OxvMC zIzTn(6rB`IAK$%uCjAIX%lSPhev;8_P{czk0N9(cD5Syta*y@@M`^e||EXJ> zdBdmiAtt!AG4JX5&zH&@^IysrasKtEasM#=&*z`h;3EwxB!j;L#@%pUfda|wgBMNJ za2!y};T14Q#%DoTf#dT|w|7i35vMAj^9dVOz+)tXxkK%c1*okkDC{~zcS7+d@&+vO z91S_hx5oivVJw3t0?(S#_|9Rf$3pc(M1#3HVYW3HGakmqg)@W~Gh>r`M)Il=bK z3LN!U=20B}!jgujk{-)(0%RFxS<~^KaeUnC$l)u5{L^9o*U>9;ZO}gKt17HdyQ=P!ec&t#YzpC+!qnpU?C=o-C14G+G4;R=54q?K zDER@@A!u4o3;pYnhGN=6<0m*cNDST4k6sYluwsXlhk*D6*8|x`rfUt*rEhWWdZUG_ zb%ixAYh8qN+s(cJeKq_1Ib^%_cC&K^FQJ$(7U0DTa@l^}xm=1Q!sO&?rM2Xunt>|R z9y3tZ71MVL)M}f$0lh$3bBJ`M&G7e%L!!V(Et6QBo9#@5k$B8?P*dmRhAxS1-2hRZ#ewF3hV z;s~8KtJ!DihZBrNR?et?C{m6g*0)8Wzv-}tsPka5|n{Ml(n%Cvt2?&%h zm{)apC9ZH(h3rZzX1;uh;K8PYyK^SVMa;ykA)q)M1=I&6Ybt_K%Q^I8&Wk3KBrh|W zI8+X9-GJj1Ub6V3h^_&a9M`X~g{ir+ExIucKBR}TY3?G97EUpGbzBE)hcFJ@Gig}_ zJ8MY!8w{{?$fNCwxNjsf>k^7(4l6ZMK$p6?0)D=+LuFKsi5$Z(UsSJki8Q z7S+_D7%I-CM%E_^5~wM+RFpM`Nv7WE?n3508_FbdZF;Y_bYd%fLu*$medct3{TDC% zPvPUy^Pibt)qiDK|CLL-`fn@r3dA;&Y&5d`61#G?(>?wAv<>ven)(xpd*DI3B{COXjXnB=~K624&^iDf%cz4;l5DhY$%`&I$Onuo?Z(m%sx=Vh>&^1%n^14>g z7Xxawo4W<;Z_&f}e;OZ;;U5ouo9DlRsqgT=4Z3yyi%YrB=meN9@b|G|mCutpmDR9T z904vWT6(clh~OSC-$cptQTkkRO9OsKt60xQpV z`x-2d&uE~Cqh4H3rSQ(h9lKjh;t1Ajk8`y4ybFdod<%mZl%JFeZyL_9T)KsJ-N z7Reh59--V?PwE^i&;Ls+3j{BuQz!mAY^8c{+1mi-mgs)`JKTOEACKX`P)y;!Sdj03 zja~h}6?$!P+Lqr=R#Q*DqXBoBR{=xQNt1FraQ#p+PU3eQxH&nCZA!l}br`rI*GMCv zmJn-NA=*1*9(3#wpae##ViqgTlAKwt7vdicD&PbfTxkuhju-bAZ)Bkd zP8w)sB)=$;2AlfKqh44cjj7Y5KJ~;`DY9z4p%cGC&V#k*5bv_dx%`Z@vA~fY-Qdb4 wqaNLyh}JXRkl8x~AbV+v@g>(Wqyb*NSEP zshw{~D$?O$E_&v(E6*A2XqtMM&ZgD8igH>momO`s_bmspi9!|_KETez4Fl?LmV1c* zgHnIP`mbyEToydV24CR(y>(w+|9mDrU;j-0a7V?}&mHc7`mHCsj{fKCzXyA=44YOP zWOf7MDr(e?v2<_d)Hiux56;WMyYm?9Gu8@}aE91x0-acz%AeEK*7@tQpCRJ*Nu z6Kbs{|xk%`1k2^Mt{ie2QKtoA8coy3~Zx^COv~O+ZjAI z2@st}TT^crlP_LCQZF~E%?o%1xlAq#FJF>*Knjsqn24C4^_sV0Hx0W`bLfJ!+Hv_y zf>P=JFrq#St?}DBS?+q=o5BwhOk3zC6tC&Uk>xO%i#Uwf{m4JN+#S-#$)3*m=QxQfjkSQFn)G;5!@5iZw6~7*&4q|@0IhTls%(<`Ej+@(n z5`;bRHuvrJ^3)zFICxB;wtPdo!u=;Oq~4>VcF@OT1xm^2Iwfk%(Mnxef&!C%2Ns zABnSiJ~gh7@C`TXLN{mQez;j4%6)a0k+*P((W+%z;J88LxLu){J3FZfd4Bk68;lGn zBo|&;7-1udv(jdr_}IzcE2}k+V7?Y6h9O!O8&Isz!MTk|(BZE*WzY4413pw-ONFd1 z6vQznebGf)F&OXEwdO9xzIXd#6WJ!+Xl;38OYB}RH2A#_uPyy+dJO)vnE50d57mD; zEkDP9*>qOmzf69M|DJWKj@peW>UV*gy^)uqAmb9?4 z-M~c-Y12(?aSE5iyHh-3xvdtSxzs9R>~3H!|0h7?GJ|br|Z$!alIR#1>x=FZu8oIsTkMcP0tw z9|Jw{v4q1GU53=W#`Mc3)R%Y}7$Iv-Rnn@GQI)JJ#b#ol8g*^HlL#F#8hlE7Rovnj)bRKQvqYhK%@W*{({gsH@{EuMJrBTik|g6-ze zcikY8K^49ukSG7LTp4R}`6i_PRGuf>NI5sg_o9r)foxj^m{LY&CAIt+;UErwrU}z^ zBIX#Dg^*Ix(uazQ|Fq-TbzS@a;U<`R_{)_N zz1BMa0Pl4um!Z+D>3UNqdb0uVudp7(7jguhT3xR~rQEvQ zg(L8Mw}+^2DsJpJU=tZ)mvknb&7cdJO6{(E(K@dw7574cM7@zH&yAHEmz|nUCY?$7 xq*AS&zB#MEeRqD*_?il#A+dz6W-h2Ts@rU`r7dk~OI!Nk=pQ>J*8l)0001h1YL@^2 literal 0 HcmV?d00001 diff --git a/util/module.c b/util/module.c index 60c9489ec..2079eecfe 100644 --- a/util/module.c +++ b/util/module.c @@ -62,6 +62,7 @@ strmodulevent(enum module_ev e) case module_event_pass: return "module_event_pass"; case module_event_reply: return "module_event_reply"; case module_event_noreply: return "module_event_noreply"; + case module_event_capsfail: return "module_event_capsfail"; case module_event_moddone: return "module_event_moddone"; case module_event_error: return "module_event_error"; } diff --git a/util/module.h b/util/module.h index 43551ef20..831212b1f 100644 --- a/util/module.h +++ b/util/module.h @@ -239,6 +239,8 @@ enum module_ev { module_event_reply, /** no reply, timeout or other error */ module_event_noreply, + /** reply is there, but capitalisation check failed */ + module_event_capsfail, /** next module is done, and its reply is awaiting you */ module_event_moddone, /** error */ diff --git a/util/netevent.h b/util/netevent.h index bc2b72d38..9cbe38886 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -80,6 +80,8 @@ typedef int comm_point_callback_t(struct comm_point*, void*, int, #define NETEVENT_CLOSED -1 /** to pass timeout happened to callback function */ #define NETEVENT_TIMEOUT -2 +/** to pass fallback from capsforID to callback function; 0x20 failed */ +#define NETEVENT_CAPSFAIL -3 /** * A communication point dispatcher. Thread specific.