📄 feat.c
字号:
} switch (type) { case DCCPO_CHANGE_L: opt->dccpop_type = DCCPO_CONFIRM_R; break; case DCCPO_CHANGE_R: opt->dccpop_type = DCCPO_CONFIRM_L; break; default: DCCP_WARN("invalid type %d\n", type); kfree(opt); return; } opt->dccpop_feat = feature; opt->dccpop_val = NULL; opt->dccpop_len = 0; /* change feature */ dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature); list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);}static void dccp_feat_flush_confirm(struct sock *sk){ struct dccp_minisock *dmsk = dccp_msk(sk); /* Check if there is anything to confirm in the first place */ int yes = !list_empty(&dmsk->dccpms_conf); if (!yes) { struct dccp_opt_pend *opt; list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { if (opt->dccpop_conf) { yes = 1; break; } } } if (!yes) return; /* OK there is something to confirm... */ /* XXX check if packet is in flight? Send delayed ack?? */ if (sk->sk_state == DCCP_OPEN) dccp_send_ack(sk);}int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len){ int rc; dccp_feat_debug(type, feature, *val); /* figure out if it's SP or NN feature */ switch (feature) { /* deal with SP features */ case DCCPF_CCID: rc = dccp_feat_sp(sk, type, feature, val, len); break; /* deal with NN features */ case DCCPF_ACK_RATIO: rc = dccp_feat_nn(sk, type, feature, val, len); break; /* XXX implement other features */ default: dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n", dccp_feat_typename(type), feature); rc = -EFAULT; break; } /* check if there were problems changing features */ if (rc) { /* If we don't agree on SP, we sent a confirm for old value. * However we propagate rc to caller in case option was * mandatory */ if (rc != DCCP_FEAT_SP_NOAGREE) dccp_feat_empty_confirm(dccp_msk(sk), type, feature); } /* generate the confirm [if required] */ dccp_feat_flush_confirm(sk); return rc;}EXPORT_SYMBOL_GPL(dccp_feat_change_recv);int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len){ u8 t; struct dccp_opt_pend *opt; struct dccp_minisock *dmsk = dccp_msk(sk); int found = 0; int all_confirmed = 1; dccp_feat_debug(type, feature, *val); /* locate our change request */ switch (type) { case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break; case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break; default: DCCP_WARN("invalid type %d\n", type); return 1; } /* XXX sanity check feature value */ list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { if (!opt->dccpop_conf && opt->dccpop_type == t && opt->dccpop_feat == feature) { found = 1; dccp_pr_debug("feature %d found\n", opt->dccpop_feat); /* XXX do sanity check */ opt->dccpop_conf = 1; /* We got a confirmation---change the option */ dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *val); /* XXX check the return value of dccp_feat_update */ break; } if (!opt->dccpop_conf) all_confirmed = 0; } /* fix re-transmit timer */ /* XXX gotta make sure that no option negotiation occurs during * connection shutdown. Consider that the CLOSEREQ is sent and timer is * on. if all options are confirmed it might kill timer which should * remain alive until close is received. */ if (all_confirmed) { dccp_pr_debug("clear feat negotiation timer %p\n", sk); inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); } if (!found) dccp_pr_debug("%s(%d, ...) never requested\n", dccp_feat_typename(type), feature); return 0;}EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);void dccp_feat_clean(struct dccp_minisock *dmsk){ struct dccp_opt_pend *opt, *next; list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending, dccpop_node) { BUG_ON(opt->dccpop_val == NULL); kfree(opt->dccpop_val); if (opt->dccpop_sc != NULL) { BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); kfree(opt->dccpop_sc->dccpoc_val); kfree(opt->dccpop_sc); } kfree(opt); } INIT_LIST_HEAD(&dmsk->dccpms_pending); list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { BUG_ON(opt == NULL); if (opt->dccpop_val != NULL) kfree(opt->dccpop_val); kfree(opt); } INIT_LIST_HEAD(&dmsk->dccpms_conf);}EXPORT_SYMBOL_GPL(dccp_feat_clean);/* this is to be called only when a listening sock creates its child. It is * assumed by the function---the confirm is not duplicated, but rather it is * "passed on". */int dccp_feat_clone(struct sock *oldsk, struct sock *newsk){ struct dccp_minisock *olddmsk = dccp_msk(oldsk); struct dccp_minisock *newdmsk = dccp_msk(newsk); struct dccp_opt_pend *opt; int rc = 0; INIT_LIST_HEAD(&newdmsk->dccpms_pending); INIT_LIST_HEAD(&newdmsk->dccpms_conf); list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) { struct dccp_opt_pend *newopt; /* copy the value of the option */ u8 *val = kmemdup(opt->dccpop_val, opt->dccpop_len, GFP_ATOMIC); if (val == NULL) goto out_clean; newopt = kmemdup(opt, sizeof(*newopt), GFP_ATOMIC); if (newopt == NULL) { kfree(val); goto out_clean; } /* insert the option */ newopt->dccpop_val = val; list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending); /* XXX what happens with backlogs and multiple connections at * once... */ /* the master socket no longer needs to worry about confirms */ opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */ /* reset state for a new socket */ opt->dccpop_conf = 0; } /* XXX not doing anything about the conf queue */out: return rc;out_clean: dccp_feat_clean(newdmsk); rc = -ENOMEM; goto out;}EXPORT_SYMBOL_GPL(dccp_feat_clone);static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat, u8 *val, u8 len){ int rc = -ENOMEM; u8 *copy = kmemdup(val, len, GFP_KERNEL); if (copy != NULL) { rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL); if (rc) kfree(copy); } return rc;}int dccp_feat_init(struct dccp_minisock *dmsk){ int rc; INIT_LIST_HEAD(&dmsk->dccpms_pending); INIT_LIST_HEAD(&dmsk->dccpms_conf); /* CCID L */ rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID, &dmsk->dccpms_tx_ccid, 1); if (rc) goto out; /* CCID R */ rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID, &dmsk->dccpms_rx_ccid, 1); if (rc) goto out; /* Ack ratio */ rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO, &dmsk->dccpms_ack_ratio, 1);out: return rc;}EXPORT_SYMBOL_GPL(dccp_feat_init);#ifdef CONFIG_IP_DCCP_DEBUGconst char *dccp_feat_typename(const u8 type){ switch(type) { case DCCPO_CHANGE_L: return("ChangeL"); case DCCPO_CONFIRM_L: return("ConfirmL"); case DCCPO_CHANGE_R: return("ChangeR"); case DCCPO_CONFIRM_R: return("ConfirmR"); /* the following case must not appear in feature negotation */ default: dccp_pr_debug("unknown type %d [BUG!]\n", type); } return NULL;}EXPORT_SYMBOL_GPL(dccp_feat_typename);const char *dccp_feat_name(const u8 feat){ static const char *feature_names[] = { [DCCPF_RESERVED] = "Reserved", [DCCPF_CCID] = "CCID", [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos", [DCCPF_SEQUENCE_WINDOW] = "Sequence Window", [DCCPF_ECN_INCAPABLE] = "ECN Incapable", [DCCPF_ACK_RATIO] = "Ack Ratio", [DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector", [DCCPF_SEND_NDP_COUNT] = "Send NDP Count", [DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage", [DCCPF_DATA_CHECKSUM] = "Send Data Checksum", }; if (feat >= DCCPF_MIN_CCID_SPECIFIC) return "CCID-specific"; if (dccp_feat_is_reserved(feat)) return feature_names[DCCPF_RESERVED]; return feature_names[feat];}EXPORT_SYMBOL_GPL(dccp_feat_name);#endif /* CONFIG_IP_DCCP_DEBUG */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -