aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/dccp/dccp.h2
-rw-r--r--net/dccp/feat.c73
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)
441 inet_csk_ack_scheduled(sk); 441 inet_csk_ack_scheduled(sk);
442} 442}
443 443
444extern void dccp_feat_list_purge(struct list_head *fn_list);
445
444extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); 446extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
445extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*); 447extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
446extern int dccp_insert_option_elapsed_time(struct sock *sk, 448extern 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 {
60}; 60};
61#define DCCP_FEAT_SUPPORTED_MAX ARRAY_SIZE(dccp_feat_table) 61#define DCCP_FEAT_SUPPORTED_MAX ARRAY_SIZE(dccp_feat_table)
62 62
63/**
64 * dccp_feat_index - Hash function to map feature number into array position
65 * Returns consecutive array index or -1 if the feature is not understood.
66 */
67static int dccp_feat_index(u8 feat_num)
68{
69 /* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
70 if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
71 return feat_num - 1;
72
73 /*
74 * Other features: add cases for new feature types here after adding
75 * them to the above table.
76 */
77 switch (feat_num) {
78 case DCCPF_SEND_LEV_RATE:
79 return DCCP_FEAT_SUPPORTED_MAX - 1;
80 }
81 return -1;
82}
83
84static u8 dccp_feat_type(u8 feat_num)
85{
86 int idx = dccp_feat_index(feat_num);
87
88 if (idx < 0)
89 return FEAT_UNKNOWN;
90 return dccp_feat_table[idx].reconciliation;
91}
92
93static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
94{
95 if (unlikely(val == NULL))
96 return;
97 if (dccp_feat_type(feat_num) == FEAT_SP)
98 kfree(val->sp.vec);
99 memset(val, 0, sizeof(*val));
100}
101
102static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
103{
104 if (entry != NULL) {
105 dccp_feat_val_destructor(entry->feat_num, &entry->val);
106 kfree(entry);
107 }
108}
109
110/*
111 * List management functions
112 *
113 * Feature negotiation lists rely on and maintain the following invariants:
114 * - each feat_num in the list is known, i.e. we know its type and default value
115 * - each feat_num/is_local combination is unique (old entries are overwritten)
116 * - SP values are always freshly allocated
117 * - list is sorted in increasing order of feature number (faster lookup)
118 */
119
120static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
121{
122 list_del(&entry->node);
123 dccp_feat_entry_destructor(entry);
124}
125
126void dccp_feat_list_purge(struct list_head *fn_list)
127{
128 struct dccp_feat_entry *entry, *next;
129
130 list_for_each_entry_safe(entry, next, fn_list, node)
131 dccp_feat_entry_destructor(entry);
132 INIT_LIST_HEAD(fn_list);
133}
134EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
135
63int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, 136int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
64 u8 *val, u8 len, gfp_t gfp) 137 u8 *val, u8 len, gfp_t gfp)
65{ 138{