diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-11-04 23:54:04 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-04 23:54:04 -0800 |
commit | 61e6473efbd6087e1db3aaa93a5266c5bfd8aa99 (patch) | |
tree | 4717cfb41ad603d5def3db557628e5d96a918e63 | |
parent | 7d43d1a0f2cf535167ec7247f110a1f85cecac43 (diff) | |
download | linux-61e6473efbd6087e1db3aaa93a5266c5bfd8aa99.tar.gz linux-61e6473efbd6087e1db3aaa93a5266c5bfd8aa99.tar.bz2 linux-61e6473efbd6087e1db3aaa93a5266c5bfd8aa99.zip |
dccp: List management for new feature negotiation
This adds list initial fields and list management functions for the
new feature negotiation implementation.
Thanks to Arnaldo for suggestions and improvements.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/dccp/dccp.h | 2 | ||||
-rw-r--r-- | net/dccp/feat.c | 73 |
2 files changed, 75 insertions, 0 deletions
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index b4bc6e095a0e..d6fed595a3ff 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -441,6 +441,8 @@ static inline int dccp_ack_pending(const struct sock *sk) inet_csk_ack_scheduled(sk); } +extern void dccp_feat_list_purge(struct list_head *fn_list); + extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*); extern int dccp_insert_option_elapsed_time(struct sock *sk, diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 45e36fc7943b..9a37b6ce3aca 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c @@ -60,6 +60,79 @@ static const struct { }; #define DCCP_FEAT_SUPPORTED_MAX ARRAY_SIZE(dccp_feat_table) +/** + * dccp_feat_index - Hash function to map feature number into array position + * Returns consecutive array index or -1 if the feature is not understood. + */ +static int dccp_feat_index(u8 feat_num) +{ + /* The first 9 entries are occupied by the types from RFC 4340, 6.4 */ + if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM) + return feat_num - 1; + + /* + * Other features: add cases for new feature types here after adding + * them to the above table. + */ + switch (feat_num) { + case DCCPF_SEND_LEV_RATE: + return DCCP_FEAT_SUPPORTED_MAX - 1; + } + return -1; +} + +static u8 dccp_feat_type(u8 feat_num) +{ + int idx = dccp_feat_index(feat_num); + + if (idx < 0) + return FEAT_UNKNOWN; + return dccp_feat_table[idx].reconciliation; +} + +static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val) +{ + if (unlikely(val == NULL)) + return; + if (dccp_feat_type(feat_num) == FEAT_SP) + kfree(val->sp.vec); + memset(val, 0, sizeof(*val)); +} + +static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry) +{ + if (entry != NULL) { + dccp_feat_val_destructor(entry->feat_num, &entry->val); + kfree(entry); + } +} + +/* + * List management functions + * + * Feature negotiation lists rely on and maintain the following invariants: + * - each feat_num in the list is known, i.e. we know its type and default value + * - each feat_num/is_local combination is unique (old entries are overwritten) + * - SP values are always freshly allocated + * - list is sorted in increasing order of feature number (faster lookup) + */ + +static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry) +{ + list_del(&entry->node); + dccp_feat_entry_destructor(entry); +} + +void dccp_feat_list_purge(struct list_head *fn_list) +{ + struct dccp_feat_entry *entry, *next; + + list_for_each_entry_safe(entry, next, fn_list, node) + dccp_feat_entry_destructor(entry); + INIT_LIST_HEAD(fn_list); +} +EXPORT_SYMBOL_GPL(dccp_feat_list_purge); + int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, u8 *val, u8 len, gfp_t gfp) { |