⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 feat.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	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 + -