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

📄 iwch_cm.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	struct tx_data_wr *req;	struct mpa_message *mpa;	struct sk_buff *skb;	PDBG("%s ep %p plen %d\n", __FUNCTION__, ep, plen);	mpalen = sizeof(*mpa) + plen;	skb = get_skb(NULL, mpalen + sizeof(*req), GFP_KERNEL);	if (!skb) {		printk(KERN_ERR MOD "%s - cannot alloc skb!\n", __FUNCTION__);		return -ENOMEM;	}	skb_reserve(skb, sizeof(*req));	mpa = (struct mpa_message *) skb_put(skb, mpalen);	memset(mpa, 0, sizeof(*mpa));	memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key));	mpa->flags = MPA_REJECT;	mpa->revision = mpa_rev;	mpa->private_data_size = htons(plen);	if (plen)		memcpy(mpa->private_data, pdata, plen);	/*	 * Reference the mpa skb again.  This ensures the data area	 * will remain in memory until the hw acks the tx.	 * Function tx_ack() will deref it.	 */	skb_get(skb);	skb->priority = CPL_PRIORITY_DATA;	set_arp_failure_handler(skb, arp_failure_discard);	skb_reset_transport_header(skb);	req = (struct tx_data_wr *) skb_push(skb, sizeof(*req));	req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));	req->wr_lo = htonl(V_WR_TID(ep->hwtid));	req->len = htonl(mpalen);	req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |			   V_TX_SNDBUF(snd_win>>15));	req->flags = htonl(F_TX_INIT);	req->sndseq = htonl(ep->snd_seq);	BUG_ON(ep->mpa_skb);	ep->mpa_skb = skb;	l2t_send(ep->com.tdev, skb, ep->l2t);	return 0;}static int send_mpa_reply(struct iwch_ep *ep, const void *pdata, u8 plen){	int mpalen;	struct tx_data_wr *req;	struct mpa_message *mpa;	int len;	struct sk_buff *skb;	PDBG("%s ep %p plen %d\n", __FUNCTION__, ep, plen);	mpalen = sizeof(*mpa) + plen;	skb = get_skb(NULL, mpalen + sizeof(*req), GFP_KERNEL);	if (!skb) {		printk(KERN_ERR MOD "%s - cannot alloc skb!\n", __FUNCTION__);		return -ENOMEM;	}	skb->priority = CPL_PRIORITY_DATA;	skb_reserve(skb, sizeof(*req));	mpa = (struct mpa_message *) skb_put(skb, mpalen);	memset(mpa, 0, sizeof(*mpa));	memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key));	mpa->flags = (ep->mpa_attr.crc_enabled ? MPA_CRC : 0) |		     (markers_enabled ? MPA_MARKERS : 0);	mpa->revision = mpa_rev;	mpa->private_data_size = htons(plen);	if (plen)		memcpy(mpa->private_data, pdata, plen);	/*	 * Reference the mpa skb.  This ensures the data area	 * will remain in memory until the hw acks the tx.	 * Function tx_ack() will deref it.	 */	skb_get(skb);	set_arp_failure_handler(skb, arp_failure_discard);	skb_reset_transport_header(skb);	len = skb->len;	req = (struct tx_data_wr *) skb_push(skb, sizeof(*req));	req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));	req->wr_lo = htonl(V_WR_TID(ep->hwtid));	req->len = htonl(len);	req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |			   V_TX_SNDBUF(snd_win>>15));	req->flags = htonl(F_TX_INIT);	req->sndseq = htonl(ep->snd_seq);	ep->mpa_skb = skb;	state_set(&ep->com, MPA_REP_SENT);	l2t_send(ep->com.tdev, skb, ep->l2t);	return 0;}static int act_establish(struct t3cdev *tdev, struct sk_buff *skb, void *ctx){	struct iwch_ep *ep = ctx;	struct cpl_act_establish *req = cplhdr(skb);	unsigned int tid = GET_TID(req);	PDBG("%s ep %p tid %d\n", __FUNCTION__, ep, tid);	dst_confirm(ep->dst);	/* setup the hwtid for this connection */	ep->hwtid = tid;	cxgb3_insert_tid(ep->com.tdev, &t3c_client, ep, tid);	ep->snd_seq = ntohl(req->snd_isn);	ep->rcv_seq = ntohl(req->rcv_isn);	set_emss(ep, ntohs(req->tcp_opt));	/* dealloc the atid */	cxgb3_free_atid(ep->com.tdev, ep->atid);	/* start MPA negotiation */	send_mpa_req(ep, skb);	return 0;}static void abort_connection(struct iwch_ep *ep, struct sk_buff *skb, gfp_t gfp){	PDBG("%s ep %p\n", __FILE__, ep);	state_set(&ep->com, ABORTING);	send_abort(ep, skb, gfp);}static void close_complete_upcall(struct iwch_ep *ep){	struct iw_cm_event event;	PDBG("%s ep %p\n", __FUNCTION__, ep);	memset(&event, 0, sizeof(event));	event.event = IW_CM_EVENT_CLOSE;	if (ep->com.cm_id) {		PDBG("close complete delivered ep %p cm_id %p tid %d\n",		     ep, ep->com.cm_id, ep->hwtid);		ep->com.cm_id->event_handler(ep->com.cm_id, &event);		ep->com.cm_id->rem_ref(ep->com.cm_id);		ep->com.cm_id = NULL;		ep->com.qp = NULL;	}}static void peer_close_upcall(struct iwch_ep *ep){	struct iw_cm_event event;	PDBG("%s ep %p\n", __FUNCTION__, ep);	memset(&event, 0, sizeof(event));	event.event = IW_CM_EVENT_DISCONNECT;	if (ep->com.cm_id) {		PDBG("peer close delivered ep %p cm_id %p tid %d\n",		     ep, ep->com.cm_id, ep->hwtid);		ep->com.cm_id->event_handler(ep->com.cm_id, &event);	}}static void peer_abort_upcall(struct iwch_ep *ep){	struct iw_cm_event event;	PDBG("%s ep %p\n", __FUNCTION__, ep);	memset(&event, 0, sizeof(event));	event.event = IW_CM_EVENT_CLOSE;	event.status = -ECONNRESET;	if (ep->com.cm_id) {		PDBG("abort delivered ep %p cm_id %p tid %d\n", ep,		     ep->com.cm_id, ep->hwtid);		ep->com.cm_id->event_handler(ep->com.cm_id, &event);		ep->com.cm_id->rem_ref(ep->com.cm_id);		ep->com.cm_id = NULL;		ep->com.qp = NULL;	}}static void connect_reply_upcall(struct iwch_ep *ep, int status){	struct iw_cm_event event;	PDBG("%s ep %p status %d\n", __FUNCTION__, ep, status);	memset(&event, 0, sizeof(event));	event.event = IW_CM_EVENT_CONNECT_REPLY;	event.status = status;	event.local_addr = ep->com.local_addr;	event.remote_addr = ep->com.remote_addr;	if ((status == 0) || (status == -ECONNREFUSED)) {		event.private_data_len = ep->plen;		event.private_data = ep->mpa_pkt + sizeof(struct mpa_message);	}	if (ep->com.cm_id) {		PDBG("%s ep %p tid %d status %d\n", __FUNCTION__, ep,		     ep->hwtid, status);		ep->com.cm_id->event_handler(ep->com.cm_id, &event);	}	if (status < 0) {		ep->com.cm_id->rem_ref(ep->com.cm_id);		ep->com.cm_id = NULL;		ep->com.qp = NULL;	}}static void connect_request_upcall(struct iwch_ep *ep){	struct iw_cm_event event;	PDBG("%s ep %p tid %d\n", __FUNCTION__, ep, ep->hwtid);	memset(&event, 0, sizeof(event));	event.event = IW_CM_EVENT_CONNECT_REQUEST;	event.local_addr = ep->com.local_addr;	event.remote_addr = ep->com.remote_addr;	event.private_data_len = ep->plen;	event.private_data = ep->mpa_pkt + sizeof(struct mpa_message);	event.provider_data = ep;	if (state_read(&ep->parent_ep->com) != DEAD)		ep->parent_ep->com.cm_id->event_handler(						ep->parent_ep->com.cm_id,						&event);	put_ep(&ep->parent_ep->com);	ep->parent_ep = NULL;}static void established_upcall(struct iwch_ep *ep){	struct iw_cm_event event;	PDBG("%s ep %p\n", __FUNCTION__, ep);	memset(&event, 0, sizeof(event));	event.event = IW_CM_EVENT_ESTABLISHED;	if (ep->com.cm_id) {		PDBG("%s ep %p tid %d\n", __FUNCTION__, ep, ep->hwtid);		ep->com.cm_id->event_handler(ep->com.cm_id, &event);	}}static int update_rx_credits(struct iwch_ep *ep, u32 credits){	struct cpl_rx_data_ack *req;	struct sk_buff *skb;	PDBG("%s ep %p credits %u\n", __FUNCTION__, ep, credits);	skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);	if (!skb) {		printk(KERN_ERR MOD "update_rx_credits - cannot alloc skb!\n");		return 0;	}	req = (struct cpl_rx_data_ack *) skb_put(skb, sizeof(*req));	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, ep->hwtid));	req->credit_dack = htonl(V_RX_CREDITS(credits) | V_RX_FORCE_ACK(1));	skb->priority = CPL_PRIORITY_ACK;	cxgb3_ofld_send(ep->com.tdev, skb);	return credits;}static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb){	struct mpa_message *mpa;	u16 plen;	struct iwch_qp_attributes attrs;	enum iwch_qp_attr_mask mask;	int err;	PDBG("%s ep %p\n", __FUNCTION__, ep);	/*	 * Stop mpa timer.  If it expired, then the state has	 * changed and we bail since ep_timeout already aborted	 * the connection.	 */	stop_ep_timer(ep);	if (state_read(&ep->com) != MPA_REQ_SENT)		return;	/*	 * If we get more than the supported amount of private data	 * then we must fail this connection.	 */	if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt)) {		err = -EINVAL;		goto err;	}	/*	 * copy the new data into our accumulation buffer.	 */	skb_copy_from_linear_data(skb, &(ep->mpa_pkt[ep->mpa_pkt_len]),				  skb->len);	ep->mpa_pkt_len += skb->len;	/*	 * if we don't even have the mpa message, then bail.	 */	if (ep->mpa_pkt_len < sizeof(*mpa))		return;	mpa = (struct mpa_message *) ep->mpa_pkt;	/* Validate MPA header. */	if (mpa->revision != mpa_rev) {		err = -EPROTO;		goto err;	}	if (memcmp(mpa->key, MPA_KEY_REP, sizeof(mpa->key))) {		err = -EPROTO;		goto err;	}	plen = ntohs(mpa->private_data_size);	/*	 * Fail if there's too much private data.	 */	if (plen > MPA_MAX_PRIVATE_DATA) {		err = -EPROTO;		goto err;	}	/*	 * If plen does not account for pkt size	 */	if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) {		err = -EPROTO;		goto err;	}	ep->plen = (u8) plen;	/*	 * If we don't have all the pdata yet, then bail.	 * We'll continue process when more data arrives.	 */	if (ep->mpa_pkt_len < (sizeof(*mpa) + plen))		return;	if (mpa->flags & MPA_REJECT) {		err = -ECONNREFUSED;		goto err;	}	/*	 * If we get here we have accumulated the entire mpa	 * start reply message including private data. And	 * the MPA header is valid.	 */	state_set(&ep->com, FPDU_MODE);	ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;	ep->mpa_attr.recv_marker_enabled = markers_enabled;	ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0;	ep->mpa_attr.version = mpa_rev;	PDBG("%s - crc_enabled=%d, recv_marker_enabled=%d, "	     "xmit_marker_enabled=%d, version=%d\n", __FUNCTION__,	     ep->mpa_attr.crc_enabled, ep->mpa_attr.recv_marker_enabled,	     ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version);	attrs.mpa_attr = ep->mpa_attr;	attrs.max_ird = ep->ird;	attrs.max_ord = ep->ord;	attrs.llp_stream_handle = ep;	attrs.next_state = IWCH_QP_STATE_RTS;	mask = IWCH_QP_ATTR_NEXT_STATE |	    IWCH_QP_ATTR_LLP_STREAM_HANDLE | IWCH_QP_ATTR_MPA_ATTR |	    IWCH_QP_ATTR_MAX_IRD | IWCH_QP_ATTR_MAX_ORD;	/* bind QP and TID with INIT_WR */	err = iwch_modify_qp(ep->com.qp->rhp,			     ep->com.qp, mask, &attrs, 1);	if (!err)		goto out;err:	abort_connection(ep, skb, GFP_KERNEL);out:	connect_reply_upcall(ep, err);	return;}static void process_mpa_request(struct iwch_ep *ep, struct sk_buff *skb){	struct mpa_message *mpa;	u16 plen;	PDBG("%s ep %p\n", __FUNCTION__, ep);	/*	 * Stop mpa timer.  If it expired, then the state has	 * changed and we bail since ep_timeout already aborted	 * the connection.	 */	stop_ep_timer(ep);	if (state_read(&ep->com) != MPA_REQ_WAIT)		return;	/*	 * If we get more than the supported amount of private data	 * then we must fail this connection.	 */	if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt)) {		abort_connection(ep, skb, GFP_KERNEL);		return;	}	PDBG("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);	/*	 * Copy the new data into our accumulation buffer.	 */	skb_copy_from_linear_data(skb, &(ep->mpa_pkt[ep->mpa_pkt_len]),				  skb->len);	ep->mpa_pkt_len += skb->len;	/*	 * If we don't even have the mpa message, then bail.	 * We'll continue process when more data arrives.	 */	if (ep->mpa_pkt_len < sizeof(*mpa))		return;	PDBG("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);	mpa = (struct mpa_message *) ep->mpa_pkt;	/*	 * Validate MPA Header.	 */	if (mpa->revision != mpa_rev) {		abort_connection(ep, skb, GFP_KERNEL);		return;	}	if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key))) {		abort_connection(ep, skb, GFP_KERNEL);		return;	}	plen = ntohs(mpa->private_data_size);	/*	 * Fail if there's too much private data.	 */	if (plen > MPA_MAX_PRIVATE_DATA) {		abort_connection(ep, skb, GFP_KERNEL);		return;	}	/*	 * If plen does not account for pkt size	 */	if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) {		abort_connection(ep, skb, GFP_KERNEL);		return;	}	ep->plen = (u8) plen;	/*	 * If we don't have all the pdata yet, then bail.	 */	if (ep->mpa_pkt_len < (sizeof(*mpa) + plen))		return;	/*	 * If we get here we have accumulated the entire mpa	 * start reply message including private data.	 */	ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;	ep->mpa_attr.recv_marker_enabled = markers_enabled;	ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0;	ep->mpa_attr.version = mpa_rev;	PDBG("%s - crc_enabled=%d, recv_marker_enabled=%d, "	     "xmit_marker_enabled=%d, version=%d\n", __FUNCTION__,	     ep->mpa_attr.crc_enabled, ep->mpa_attr.recv_marker_enabled,	     ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version);	state_set(&ep->com, MPA_REQ_RCVD);	/* drive upcall */	connect_request_upcall(ep);	return;}static int rx_data(struct t3cdev *tdev, struct sk_buff *skb, void *ctx){	struct iwch_ep *ep = ctx;	struct cpl_rx_data *hdr = cplhdr(skb);	unsigned int dlen = ntohs(hdr->len);	PDBG("%s ep %p dlen %u\n", __FUNCTION__, ep, dlen);	skb_pull(skb, sizeof(*hdr));	skb_trim(skb, dlen);	ep->rcv_seq += dlen;	BUG_ON(ep->rcv_seq != (ntohl(hdr->seq) + dlen));	switch (state_read(&ep->com)) {	case MPA_REQ_SENT:		process_mpa_reply(ep, skb);		break;	case MPA_REQ_WAIT:		process_mpa_request(ep, skb);		break;	case MPA_REP_SENT:		break;	default:		printk(KERN_ERR MOD "%s Unexpected streaming data."		       " ep %p state %d tid %d\n",		       __FUNCTION__, ep, state_read(&ep->com), ep->hwtid);		/*		 * The ep will timeout and inform the ULP of the failure.		 * See ep_timeout().		 */		break;	}	/* update RX credits */	update_rx_credits(ep, dlen);	return CPL_RET_BUF_DONE;}/*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -