📄 iwch_cm.c
字号:
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 + -