2 * Copyright (c) 2012, 2013, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of JANET(UK) nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
41 #include <tr_filter.h>
42 #include <trp_internal.h>
43 #include <tid_internal.h>
44 #include <tr_inet_util.h>
47 /* Function types for handling filter fields generally. All target values
48 * are represented as strings in a TR_NAME.
51 /* CMP functions return values like strcmp: 0 on match, <0 on target<val, >0 on target>val */
52 typedef int (*TR_FILTER_FIELD_CMP)(TR_FILTER_TARGET *target, TR_NAME *val);
53 /* get functions return TR_NAME format of the field value. Caller must free it. */
54 typedef TR_NAME *(*TR_FILTER_FIELD_GET)(TR_FILTER_TARGET *target);
56 static TR_FILTER_TARGET *tr_filter_target_new(TALLOC_CTX *mem_ctx)
58 TR_FILTER_TARGET *target=talloc(mem_ctx, TR_FILTER_TARGET);
60 target->trp_inforec=NULL;
66 void tr_filter_target_free(TR_FILTER_TARGET *target)
72 * Create a filter target for a TID request. Does not change the context of the request,
73 * so this is only valid until that is freed.
75 * @param mem_ctx talloc context for the object
76 * @param req TID request object
77 * @return pointer to a TR_FILTER_TARGET structure, or null on allocation failure
79 TR_FILTER_TARGET *tr_filter_target_tid_req(TALLOC_CTX *mem_ctx, TID_REQ *req)
81 TR_FILTER_TARGET *target=tr_filter_target_new(mem_ctx);
83 target->tid_req=req; /* borrowed, not adding to our context */
88 * Create a filter target for a TRP inforec. Does not change the context of the inforec or duplicate TR_NAMEs,
89 * so this is only valid until those are freed.
91 * @param mem_ctx talloc context for the object
92 * @param upd Update containing the TRP inforec
93 * @param inforec TRP inforec
94 * @return pointer to a TR_FILTER_TARGET structure, or null on allocation failure
96 TR_FILTER_TARGET *tr_filter_target_trp_inforec(TALLOC_CTX *mem_ctx, TRP_UPD *upd, TRP_INFOREC *inforec)
98 TR_FILTER_TARGET *target=tr_filter_target_new(mem_ctx);
100 target->trp_inforec = inforec; /* borrowed, not adding to our context */
106 /** Handler functions for TID RP_REALM field */
107 static int tr_ff_cmp_tid_rp_realm(TR_FILTER_TARGET *target, TR_NAME *val)
109 return tr_name_cmp(tid_req_get_rp_realm(target->tid_req), val);
112 static TR_NAME *tr_ff_get_tid_rp_realm(TR_FILTER_TARGET *target)
114 return tr_dup_name(tid_req_get_rp_realm(target->tid_req));
117 /** Handler functions for TRP info_type field */
118 static int tr_ff_cmp_trp_info_type(TR_FILTER_TARGET *target, TR_NAME *val)
120 TRP_INFOREC *inforec=target->trp_inforec;
127 /* nothing matches unknown */
128 if (inforec->type==TRP_INFOREC_TYPE_UNKNOWN)
131 valstr = tr_name_strdup(val); /* get this as an official null-terminated string */
132 val_type = trp_inforec_type_from_string(valstr);
135 /* we do not define an ordering of info types */
136 return (val_type==inforec->type);
139 static TR_NAME *tr_ff_get_trp_info_type(TR_FILTER_TARGET *target)
141 TRP_INFOREC *inforec=target->trp_inforec;
142 return tr_new_name(trp_inforec_type_to_string(inforec->type));
145 /** Handlers for TRP realm field */
146 static int tr_ff_cmp_trp_realm(TR_FILTER_TARGET *target, TR_NAME *val)
148 return tr_name_cmp(trp_upd_get_realm(target->trp_upd), val);
151 static TR_NAME *tr_ff_get_trp_realm(TR_FILTER_TARGET *target)
153 return tr_dup_name(trp_upd_get_realm(target->trp_upd));
156 /** Handlers for TID realm field */
157 static int tr_ff_cmp_tid_realm(TR_FILTER_TARGET *target, TR_NAME *val)
159 return tr_name_cmp(tid_req_get_realm(target->tid_req), val);
162 static TR_NAME *tr_ff_get_tid_realm(TR_FILTER_TARGET *target)
164 return tr_dup_name(tid_req_get_realm(target->tid_req));
167 /** Handlers for TRP community field */
168 static int tr_ff_cmp_trp_comm(TR_FILTER_TARGET *target, TR_NAME *val)
170 return tr_name_cmp(trp_upd_get_comm(target->trp_upd), val);
173 static TR_NAME *tr_ff_get_trp_comm(TR_FILTER_TARGET *target)
175 return tr_dup_name(trp_upd_get_comm(target->trp_upd));
178 /** Handlers for TID community field */
179 static int tr_ff_cmp_tid_comm(TR_FILTER_TARGET *target, TR_NAME *val)
181 return tr_name_cmp(tid_req_get_comm(target->tid_req), val);
184 static TR_NAME *tr_ff_get_tid_comm(TR_FILTER_TARGET *target)
186 return tr_dup_name(tid_req_get_comm(target->tid_req));
189 /** Handlers for TRP community_type field */
190 static TR_NAME *tr_ff_get_trp_comm_type(TR_FILTER_TARGET *target)
194 switch(trp_inforec_get_comm_type(target->trp_inforec)) {
196 type=tr_new_name("apc");
199 type=tr_new_name("coi");
203 break; /* unknown types always fail */
209 static int tr_ff_cmp_trp_comm_type(TR_FILTER_TARGET *target, TR_NAME *val)
211 TR_NAME *type=tr_ff_get_trp_comm_type(target);
217 retval = tr_name_cmp(val, type);
223 /** Handlers for TRP realm_role field */
224 static TR_NAME *tr_ff_get_trp_realm_role(TR_FILTER_TARGET *target)
228 switch(trp_inforec_get_role(target->trp_inforec)) {
230 type=tr_new_name("idp");
233 type=tr_new_name("rp");
237 break; /* unknown types always fail */
243 static int tr_ff_cmp_trp_realm_role(TR_FILTER_TARGET *target, TR_NAME *val)
245 TR_NAME *type=tr_ff_get_trp_realm_role(target);
251 retval = tr_name_cmp(val, type);
257 /** Handlers for TRP apc field */
258 /* TODO: Handle multiple APCs, not just the first */
259 static int tr_ff_cmp_trp_apc(TR_FILTER_TARGET *target, TR_NAME *val)
261 return tr_name_cmp(tr_apc_get_id(trp_inforec_get_apcs(target->trp_inforec)), val);
264 static TR_NAME *tr_ff_get_trp_apc(TR_FILTER_TARGET *target)
266 TR_APC *apc=trp_inforec_get_apcs(target->trp_inforec);
270 return tr_dup_name(tr_apc_get_id(apc));
273 /** Handlers for TRP owner_realm field */
274 static int tr_ff_cmp_trp_owner_realm(TR_FILTER_TARGET *target, TR_NAME *val)
276 return tr_name_cmp(trp_inforec_get_owner_realm(target->trp_inforec), val);
279 static TR_NAME *tr_ff_get_trp_owner_realm(TR_FILTER_TARGET *target)
281 return tr_dup_name(trp_inforec_get_owner_realm(target->trp_inforec));
284 /** Generic handlers for host:port fields*/
285 static TR_NAME *tr_ff_get_hostname_and_port(TR_NAME *hn, int port)
287 return tr_hostname_and_port_to_name(hn, port);
290 static int tr_ff_cmp_hostname_and_port(TR_NAME *hn, int port, int default_port, TR_NAME *val)
295 /* allow a match without :port if the default port is in use */
296 if ((port == default_port) && (tr_name_cmp(hn, val) == 0))
299 /* need to match with the :port */
300 n = tr_ff_get_hostname_and_port(hn, port);
303 cmp = tr_name_cmp(n, val);
309 /** Handlers for TRP trust_router field */
310 static int tr_ff_cmp_trp_trust_router(TR_FILTER_TARGET *target, TR_NAME *val)
312 return tr_ff_cmp_hostname_and_port(trp_inforec_get_trust_router(target->trp_inforec),
313 trp_inforec_get_trust_router_port(target->trp_inforec),
318 static TR_NAME *tr_ff_get_trp_trust_router(TR_FILTER_TARGET *target)
320 return tr_ff_get_hostname_and_port(trp_inforec_get_trust_router(target->trp_inforec),
321 trp_inforec_get_trust_router_port(target->trp_inforec));
324 /** Handlers for TRP next_hop field */
325 static int tr_ff_cmp_trp_next_hop(TR_FILTER_TARGET *target, TR_NAME *val)
327 return tr_ff_cmp_hostname_and_port(trp_inforec_get_next_hop(target->trp_inforec),
328 trp_inforec_get_next_hop_port(target->trp_inforec),
333 static TR_NAME *tr_ff_get_trp_next_hop(TR_FILTER_TARGET *target)
335 return tr_ff_get_hostname_and_port(trp_inforec_get_next_hop(target->trp_inforec),
336 trp_inforec_get_next_hop_port(target->trp_inforec));
339 /** Handlers for TRP owner_contact field */
340 static int tr_ff_cmp_trp_owner_contact(TR_FILTER_TARGET *target, TR_NAME *val)
342 return tr_name_cmp(trp_inforec_get_owner_contact(target->trp_inforec), val);
345 static TR_NAME *tr_ff_get_trp_owner_contact(TR_FILTER_TARGET *target)
347 return tr_dup_name(trp_inforec_get_owner_contact(target->trp_inforec));
350 /** Handlers for TID req original_coi field */
351 static int tr_ff_cmp_tid_orig_coi(TR_FILTER_TARGET *target, TR_NAME *val)
353 return tr_name_cmp(tid_req_get_orig_coi(target->tid_req), val);
356 static TR_NAME *tr_ff_get_tid_orig_coi(TR_FILTER_TARGET *target)
358 return tr_dup_name(tid_req_get_orig_coi(target->tid_req));
362 * Filter field handler table
364 struct tr_filter_field_entry {
365 TR_FILTER_TYPE filter_type;
367 TR_FILTER_FIELD_CMP cmp;
368 TR_FILTER_FIELD_GET get;
370 static struct tr_filter_field_entry tr_filter_field_table[] = {
372 {TR_FILTER_TYPE_TID_INBOUND, "realm", tr_ff_cmp_tid_realm, tr_ff_get_tid_realm},
373 {TR_FILTER_TYPE_TRP_INBOUND, "realm", tr_ff_cmp_trp_realm, tr_ff_get_trp_realm},
374 {TR_FILTER_TYPE_TRP_OUTBOUND, "realm", tr_ff_cmp_trp_realm, tr_ff_get_trp_realm},
377 {TR_FILTER_TYPE_TID_INBOUND, "comm", tr_ff_cmp_tid_comm, tr_ff_get_tid_comm},
378 {TR_FILTER_TYPE_TRP_INBOUND, "comm", tr_ff_cmp_trp_comm, tr_ff_get_trp_comm},
379 {TR_FILTER_TYPE_TRP_OUTBOUND, "comm", tr_ff_cmp_trp_comm, tr_ff_get_trp_comm},
382 {TR_FILTER_TYPE_TRP_INBOUND, "comm_type", tr_ff_cmp_trp_comm_type, tr_ff_get_trp_comm_type},
383 {TR_FILTER_TYPE_TRP_OUTBOUND, "comm_type", tr_ff_cmp_trp_comm_type, tr_ff_get_trp_comm_type},
386 {TR_FILTER_TYPE_TRP_INBOUND, "realm_role", tr_ff_cmp_trp_realm_role, tr_ff_get_trp_realm_role},
387 {TR_FILTER_TYPE_TRP_OUTBOUND, "realm_role", tr_ff_cmp_trp_realm_role, tr_ff_get_trp_realm_role},
390 {TR_FILTER_TYPE_TRP_INBOUND, "apc", tr_ff_cmp_trp_apc, tr_ff_get_trp_apc},
391 {TR_FILTER_TYPE_TRP_OUTBOUND, "apc", tr_ff_cmp_trp_apc, tr_ff_get_trp_apc},
394 {TR_FILTER_TYPE_TRP_INBOUND, "trust_router", tr_ff_cmp_trp_trust_router, tr_ff_get_trp_trust_router},
395 {TR_FILTER_TYPE_TRP_OUTBOUND, "trust_router", tr_ff_cmp_trp_trust_router, tr_ff_get_trp_trust_router},
398 {TR_FILTER_TYPE_TRP_INBOUND, "next_hop", tr_ff_cmp_trp_next_hop, tr_ff_get_trp_next_hop},
399 {TR_FILTER_TYPE_TRP_OUTBOUND, "next_hop", tr_ff_cmp_trp_next_hop, tr_ff_get_trp_next_hop},
402 {TR_FILTER_TYPE_TRP_INBOUND, "owner_realm", tr_ff_cmp_trp_owner_realm, tr_ff_get_trp_owner_realm},
403 {TR_FILTER_TYPE_TRP_OUTBOUND, "owner_realm", tr_ff_cmp_trp_owner_realm, tr_ff_get_trp_owner_realm},
406 {TR_FILTER_TYPE_TRP_INBOUND, "owner_contact", tr_ff_cmp_trp_owner_contact, tr_ff_get_trp_owner_contact},
407 {TR_FILTER_TYPE_TRP_OUTBOUND, "owner_contact", tr_ff_cmp_trp_owner_contact, tr_ff_get_trp_owner_contact},
410 {TR_FILTER_TYPE_TID_INBOUND, "rp_realm", tr_ff_cmp_tid_rp_realm, tr_ff_get_tid_rp_realm},
413 {TR_FILTER_TYPE_TID_INBOUND, "original_coi", tr_ff_cmp_tid_orig_coi, tr_ff_get_tid_orig_coi},
416 {TR_FILTER_TYPE_TRP_INBOUND, "info_type", tr_ff_cmp_trp_info_type, tr_ff_get_trp_info_type},
417 {TR_FILTER_TYPE_TRP_OUTBOUND, "info_type", tr_ff_cmp_trp_info_type, tr_ff_get_trp_info_type},
420 {TR_FILTER_TYPE_UNKNOWN, NULL } /* This must be the final entry */
423 /* TODO: support TRP metric field (requires > < comparison instead of wildcard match) */
425 static struct tr_filter_field_entry *tr_filter_field_entry(TR_FILTER_TYPE filter_type, TR_NAME *field_name)
429 for (ii=0; tr_filter_field_table[ii].filter_type!=TR_FILTER_TYPE_UNKNOWN; ii++) {
430 if ((tr_filter_field_table[ii].filter_type==filter_type)
431 && (tr_name_cmp_str(field_name, tr_filter_field_table[ii].name)==0)) {
432 return tr_filter_field_table+ii;
439 * Apply a filter to a target record or TID request.
441 * If one of the filter lines matches, out_action is set to the applicable action. If constraints
442 * is not NULL, the constraints from the matching filter line will be added to the constraint set
443 * *constraints, or to a new one if *constraints is NULL. In this case, TR_FILTER_MATCH will be
446 * If there is no match, returns TR_FILTER_NO_MATCH, out_action is undefined, and constraints
447 * will not be changed.
449 * @param target Record or request to which the filter is applied
450 * @param filt Filter to apply
451 * @param constraints Pointer to existing set of constraints (NULL if not tracking constraints)
452 * @param out_action Action to be carried out (output)
453 * @return TR_FILTER_MATCH or TR_FILTER_NO_MATCH
455 int tr_filter_apply(TR_FILTER_TARGET *target,
457 TR_CONSTRAINT_SET **constraints,
458 TR_FILTER_ACTION *out_action)
460 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
461 TR_FILTER_ITER *filt_iter = tr_filter_iter_new(tmp_ctx);
462 TR_FLINE *this_fline = NULL;
463 TR_FLINE_ITER *fline_iter = tr_fline_iter_new(tmp_ctx);
464 TR_FSPEC *this_fspec = NULL;
465 int retval=TR_FILTER_NO_MATCH;
467 /* Default action is reject */
468 *out_action = TR_FILTER_ACTION_REJECT;
470 /* Validate filter */
471 if ((filt_iter == NULL) || (fline_iter == NULL) || (filt==NULL) || (filt->type==TR_FILTER_TYPE_UNKNOWN)) {
472 talloc_free(tmp_ctx);
473 return TR_FILTER_NO_MATCH;
476 /* Step through filter lines looking for a match. If a line matches, retval
477 * will be set to TR_FILTER_MATCH, so stop then. */
478 for (this_fline = tr_filter_iter_first(filt_iter, filt);
480 this_fline = tr_filter_iter_next(filt_iter)) {
481 /* Assume we are going to succeed. If any specs fail to match, we'll set
482 * this to TR_FILTER_NO_MATCH. */
483 retval=TR_FILTER_MATCH;
484 for (this_fspec = tr_fline_iter_first(fline_iter, this_fline);
486 this_fspec = tr_fline_iter_next(fline_iter)) {
487 if (!tr_fspec_matches(this_fspec, filt->type, target)) {
488 retval=TR_FILTER_NO_MATCH; /* set this in case this is the last filter line */
489 break; /* give up on this filter line */
493 if (retval==TR_FILTER_MATCH)
498 if (retval==TR_FILTER_MATCH) {
499 /* Matched line ii. Grab its action and constraints. */
500 *out_action = this_fline->action;
501 if (constraints!=NULL) {
502 /* if either constraint is missing, these are no-ops */
503 tr_constraint_add_to_set(constraints, this_fline->realm_cons);
504 tr_constraint_add_to_set(constraints, this_fline->domain_cons);
511 void tr_fspec_free(TR_FSPEC *fspec)
517 * Helper for tr_fspec_destructor - calls tr_free_name on its first argument
519 * @param item void pointer to a TR_NAME
520 * @param cookie ignored
522 static void fspec_destruct_helper(void *item, void *cookie)
524 TR_NAME *name = (TR_NAME *) item;
527 static int tr_fspec_destructor(void *obj)
529 TR_FSPEC *fspec = talloc_get_type_abort(obj, TR_FSPEC);
531 if (fspec->field != NULL)
532 tr_free_name(fspec->field);
535 tr_list_foreach(fspec->match, fspec_destruct_helper, NULL);
540 TR_FSPEC *tr_fspec_new(TALLOC_CTX *mem_ctx)
542 TR_FSPEC *fspec = talloc(mem_ctx, TR_FSPEC);
546 fspec->match = tr_list_new(fspec);
547 if (fspec->match == NULL) {
551 talloc_set_destructor((void *)fspec, tr_fspec_destructor);
556 /* Helper function and cookie structure for finding a match. The helper is called
557 * for every item in the match list, even after a match is found. If a match is found,
558 * match should be pointed to the matching item. If this is not NULL, do not change it
559 * because a match has already been found. */
560 struct fspec_match_cookie { TR_NAME *name; TR_NAME *match;};
561 static void fspec_match_helper(void *item, void *data)
563 TR_NAME *this_name = (TR_NAME *) item;
564 struct fspec_match_cookie *cookie = (struct fspec_match_cookie *) data;
565 if (cookie->match == NULL) {
566 if (tr_name_prefix_wildcard_match(cookie->name, this_name))
567 cookie->match = this_name;
570 /* returns 1 if the spec matches */
571 int tr_fspec_matches(TR_FSPEC *fspec, TR_FILTER_TYPE ftype, TR_FILTER_TARGET *target)
573 struct tr_filter_field_entry *field=NULL;
574 struct fspec_match_cookie cookie = {0};
579 /* Look up how to handle the requested field */
580 field = tr_filter_field_entry(ftype, fspec->field);
582 tr_err("tr_fspec_matches: No entry to handle field %.*s for %*s filter.",
583 fspec->field->len, fspec->field->buf,
584 tr_filter_type_to_string(ftype));
588 cookie.name = field->get(target);
589 if (cookie.name==NULL)
590 return 0; /* if there's no value, there's no match */
593 tr_list_foreach(fspec->match,
597 tr_debug("tr_fspec_matches: Field %.*s value \"%.*s\" matches \"%.*s\" for %s filter.",
598 fspec->field->len, fspec->field->buf,
599 cookie.name->len, cookie.name->buf,
600 cookie.match->len, cookie.match->buf,
601 tr_filter_type_to_string(ftype));
603 tr_debug("tr_fspec_matches: Field %.*s value \"%.*s\" does not match for %s filter.",
604 fspec->field->len, fspec->field->buf,
605 cookie.name->len, cookie.name->buf,
606 tr_filter_type_to_string(ftype));
608 return (cookie.match != NULL);
611 void tr_fline_free(TR_FLINE *fline)
616 TR_FLINE *tr_fline_new(TALLOC_CTX *mem_ctx)
618 TR_FLINE *fl = talloc(mem_ctx, TR_FLINE);
621 fl->action = TR_FILTER_ACTION_UNKNOWN;
622 fl->realm_cons = NULL;
623 fl->domain_cons = NULL;
624 fl->specs = tr_list_new(fl);
625 if (fl->specs == NULL) {
633 TR_FILTER *tr_filter_new(TALLOC_CTX *mem_ctx)
635 TR_FILTER *f = talloc(mem_ctx, TR_FILTER);
638 f->type = TR_FILTER_TYPE_UNKNOWN;
639 f->lines = tr_list_new(f);
640 if (f->lines == NULL) {
648 void tr_filter_free(TR_FILTER *filt)
653 void tr_filter_set_type(TR_FILTER *filt, TR_FILTER_TYPE type)
658 TR_FILTER_TYPE tr_filter_get_type(TR_FILTER *filt)
664 * Check that a filter is valid, i.e., can be processed.
666 * @param filt Filter to verify
667 * @return 1 if the filter is valid, 0 otherwise
669 int tr_filter_validate(TR_FILTER *filt)
671 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
672 TR_FILTER_ITER *filt_iter = tr_filter_iter_new(tmp_ctx);
673 TR_FLINE *this_fline = NULL;
674 TR_FLINE_ITER *fline_iter = tr_fline_iter_new(tmp_ctx);
675 TR_FSPEC *this_fspec = NULL;
677 if ((!filt) || (!filt_iter) || (!fline_iter)) {
678 talloc_free(tmp_ctx);
682 /* check that we recognize the type */
684 case TR_FILTER_TYPE_TID_INBOUND:
685 case TR_FILTER_TYPE_TRP_INBOUND:
686 case TR_FILTER_TYPE_TRP_OUTBOUND:
690 talloc_free(tmp_ctx);
691 return 0; /* if we get here, either TR_FILTER_TYPE_UNKNOWN or an invalid value was found */
694 for (this_fline = tr_filter_iter_first(filt_iter, filt);
696 this_fline = tr_filter_iter_next(filt_iter)) {
697 /* check that we recognize the action */
698 switch(this_fline->action) {
699 case TR_FILTER_ACTION_ACCEPT:
700 case TR_FILTER_ACTION_REJECT:
704 /* if we get here, either TR_FILTER_ACTION_UNKNOWN or an invalid value was found */
705 talloc_free(tmp_ctx);
709 for (this_fspec = tr_fline_iter_first(fline_iter, this_fline);
711 this_fspec = tr_fline_iter_next(fline_iter)) {
712 if (!tr_filter_validate_spec_field(filt->type, this_fspec)) {
713 talloc_free(tmp_ctx);
717 /* check that at least one match is defined*/
718 if (tr_list_length(this_fspec->match) == 0) {
719 talloc_free(tmp_ctx);
725 /* We ran the gauntlet. Success! */
726 talloc_free(tmp_ctx);
730 int tr_filter_validate_spec_field(TR_FILTER_TYPE ftype, TR_FSPEC *fspec)
732 if ((fspec==NULL) || (tr_filter_field_entry(ftype, fspec->field)==NULL))
733 return 0; /* unknown field */
739 * Allocate a new filter set.
741 * @param mem_ctx Talloc context for the new set
742 * @return Pointer to new set, or null on error
744 TR_FILTER_SET *tr_filter_set_new(TALLOC_CTX *mem_ctx)
746 TR_FILTER_SET *set=talloc(mem_ctx, TR_FILTER_SET);
757 * @param fs Filter set to free
759 void tr_filter_set_free(TR_FILTER_SET *fs)
765 * Find the tail of the filter set linked list.
767 * @param set Set to find tail of
768 * @return Last element in the list
770 static TR_FILTER_SET *tr_filter_set_tail(TR_FILTER_SET *set)
778 * Add new filter to filter set.
780 * @param set Filter set
781 * @param new New filter to add
782 * @return 0 on success, nonzero on error
784 int tr_filter_set_add(TR_FILTER_SET *set, TR_FILTER *new)
786 TR_FILTER_SET *tail=NULL;
791 tail=tr_filter_set_tail(set);
792 tail->next=tr_filter_set_new(set);
793 if (tail->next==NULL)
798 talloc_steal(tail, new);
803 * Find a filter of a given type in the filter set. If there are multiple, returns the first one.
805 * @param set Filter set to search
806 * @param type Type of filter to find
807 * @return Borrowed pointer to the filter, or null if no filter of that type is found
809 TR_FILTER *tr_filter_set_get(TR_FILTER_SET *set, TR_FILTER_TYPE type)
811 TR_FILTER_SET *cur=set;
813 if ((cur->this != NULL) && (cur->this->type == type))
820 TR_FILTER_TYPE filter_type[]={TR_FILTER_TYPE_TID_INBOUND,
821 TR_FILTER_TYPE_TRP_INBOUND,
822 TR_FILTER_TYPE_TRP_OUTBOUND};
823 const char *filter_label[]={"tid_inbound",
826 size_t num_filter_types=sizeof(filter_type)/sizeof(filter_type[0]);
828 const char *tr_filter_type_to_string(TR_FILTER_TYPE ftype)
832 for (ii=0; ii<num_filter_types; ii++) {
833 if (ftype==filter_type[ii])
834 return filter_label[ii];
839 TR_FILTER_TYPE tr_filter_type_from_string(const char *s)
843 for(ii=0; ii<num_filter_types; ii++) {
844 if (0==strcmp(s, filter_label[ii]))
845 return filter_type[ii];
847 return TR_FILTER_TYPE_UNKNOWN;