]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/dccp/feat.c
ARM: OMAP3: Add OMAP34xx pin multiplexing into I2C bus registration helper
[linux-2.6-omap-h63xx.git] / net / dccp / feat.c
index faade82856fe36f931d1114eb84ac7a27354b41f..933a0ecf8d463b0649fd69f78335533d86950517 100644 (file)
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
-static const struct {
-       u8                      feat_num;               /* DCCPF_xxx */
-       enum dccp_feat_type     rxtx;                   /* RX or TX  */
-       enum dccp_feat_type     reconciliation;         /* SP or NN  */
-       u8                      default_value;          /* as in 6.4 */
-/*
- *    Lookup table for location and type of features (from RFC 4340/4342)
- *  +--------------------------+----+-----+----+----+---------+-----------+
- *  | Feature                  | Location | Reconc. | Initial |  Section  |
- *  |                          | RX | TX  | SP | NN |  Value  | Reference |
- *  +--------------------------+----+-----+----+----+---------+-----------+
- *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
- *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
- *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
- *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
- *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
- *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
- *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
- *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
- *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
- *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
- *  +--------------------------+----+-----+----+----+---------+-----------+
- */
-} dccp_feat_table[] = {
-       { DCCPF_CCID,            FEAT_AT_TX, FEAT_SP, 2 },
-       { DCCPF_SHORT_SEQNOS,    FEAT_AT_TX, FEAT_SP, 0 },
-       { DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
-       { DCCPF_ECN_INCAPABLE,   FEAT_AT_RX, FEAT_SP, 0 },
-       { DCCPF_ACK_RATIO,       FEAT_AT_TX, FEAT_NN, 2 },
-       { DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
-       { DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
-       { DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
-       { DCCPF_DATA_CHECKSUM,   FEAT_AT_RX, FEAT_SP, 0 },
-       { DCCPF_SEND_LEV_RATE,   FEAT_AT_RX, FEAT_SP, 0 },
-};
-#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 int dccp_feat_default_value(u8 feat_num)
-{
-       int idx = dccp_feat_index(feat_num);
-
-       return idx < 0 ? : dccp_feat_table[idx].default_value;
-}
-
-/* copy constructor, fval must not already contain allocated memory */
-static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
-{
-       fval->sp.len = len;
-       if (fval->sp.len > 0) {
-               fval->sp.vec = kmemdup(val, len, gfp_any());
-               if (fval->sp.vec == NULL) {
-                       fval->sp.len = 0;
-                       return -ENOBUFS;
-               }
-       }
-       return 0;
-}
-
-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 struct dccp_feat_entry *
-             dccp_feat_clone_entry(struct dccp_feat_entry const *original)
-{
-       struct dccp_feat_entry *new;
-       u8 type = dccp_feat_type(original->feat_num);
-
-       if (type == FEAT_UNKNOWN)
-               return NULL;
-
-       new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
-       if (new == NULL)
-               return NULL;
-
-       if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
-                                                     original->val.sp.vec,
-                                                     original->val.sp.len)) {
-               kfree(new);
-               return NULL;
-       }
-       return new;
-}
-
-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 struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
-                                                    u8 feat_num, bool is_local)
-{
-       struct dccp_feat_entry *entry;
-
-       list_for_each_entry(entry, fn_list, node)
-               if (entry->feat_num == feat_num && entry->is_local == is_local)
-                       return entry;
-               else if (entry->feat_num > feat_num)
-                       break;
-       return NULL;
-}
-
-/**
- * dccp_feat_entry_new  -  Central list update routine (called by all others)
- * @head:  list to add to
- * @feat:  feature number
- * @local: whether the local (1) or remote feature with number @feat is meant
- * This is the only constructor and serves to ensure the above invariants.
- */
-static struct dccp_feat_entry *
-             dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
-{
-       struct dccp_feat_entry *entry;
-
-       list_for_each_entry(entry, head, node)
-               if (entry->feat_num == feat && entry->is_local == local) {
-                       dccp_feat_val_destructor(entry->feat_num, &entry->val);
-                       return entry;
-               } else if (entry->feat_num > feat) {
-                       head = &entry->node;
-                       break;
-               }
-
-       entry = kmalloc(sizeof(*entry), gfp_any());
-       if (entry != NULL) {
-               entry->feat_num = feat;
-               entry->is_local = local;
-               list_add_tail(&entry->node, head);
-       }
-       return entry;
-}
-
-/**
- * dccp_feat_push_change  -  Add/overwrite a Change option in the list
- * @fn_list: feature-negotiation list to update
- * @feat: one of %dccp_feature_numbers
- * @local: whether local (1) or remote (0) @feat_num is meant
- * @needs_mandatory: whether to use Mandatory feature negotiation options
- * @fval: pointer to NN/SP value to be inserted (will be copied)
- */
-static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
-                                u8 mandatory, dccp_feat_val *fval)
-{
-       struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
-
-       if (new == NULL)
-               return -ENOMEM;
-
-       new->feat_num        = feat;
-       new->is_local        = local;
-       new->state           = FEAT_INITIALISING;
-       new->needs_confirm   = 0;
-       new->empty_confirm   = 0;
-       new->val             = *fval;
-       new->needs_mandatory = mandatory;
-
-       return 0;
-}
-
-/**
- * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
- * @fn_list: feature-negotiation list to add to
- * @feat: one of %dccp_feature_numbers
- * @local: whether local (1) or remote (0) @feat_num is being confirmed
- * @fval: pointer to NN/SP value to be inserted or NULL
- * Returns 0 on success, a Reset code for further processing otherwise.
- */
-static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
-                                 dccp_feat_val *fval)
-{
-       struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
-
-       if (new == NULL)
-               return DCCP_RESET_CODE_TOO_BUSY;
-
-       new->feat_num        = feat;
-       new->is_local        = local;
-       new->state           = FEAT_STABLE;     /* transition in 6.6.2 */
-       new->needs_confirm   = 1;
-       new->empty_confirm   = (fval == NULL);
-       new->val.nn          = 0;               /* zeroes the whole structure */
-       if (!new->empty_confirm)
-               new->val     = *fval;
-       new->needs_mandatory = 0;
-
-       return 0;
-}
-
-static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
-{
-       return dccp_feat_push_confirm(fn_list, feat, local, NULL);
-}
-
-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);
-
-/* generate @to as full clone of @from - @to must not contain any nodes */
-int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
-{
-       struct dccp_feat_entry *entry, *new;
-
-       INIT_LIST_HEAD(to);
-       list_for_each_entry(entry, from, node) {
-               new = dccp_feat_clone_entry(entry);
-               if (new == NULL)
-                       goto cloning_failed;
-               list_add_tail(&new->node, to);
-       }
-       return 0;
-
-cloning_failed:
-       dccp_feat_list_purge(to);
-       return -ENOMEM;
-}
-
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
                     u8 *val, u8 len, gfp_t gfp)
 {
@@ -914,8 +639,6 @@ const char *dccp_feat_name(const u8 feat)
        if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
                return feature_names[DCCPF_RESERVED];
 
-       if (feat ==  DCCPF_SEND_LEV_RATE)
-               return "Send Loss Event Rate";
        if (feat >= DCCPF_MIN_CCID_SPECIFIC)
                return "CCID-specific";