static void ctcmpc_unpack_skb()

in net/ctcm_mpc.c [1027:1212]


static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
{
	struct net_device *dev	= ch->netdev;
	struct ctcm_priv *priv = dev->ml_priv;
	struct mpc_group *grp = priv->mpcg;
	struct pdu *curr_pdu;
	struct mpcg_info *mpcginfo;
	struct th_header *header = NULL;
	struct th_sweep *sweep = NULL;
	int pdu_last_seen = 0;
	__u32 new_len;
	struct sk_buff *skb;
	int skblen;
	int sendrc = 0;

	CTCM_PR_DEBUG("ctcmpc enter: %s() %s cp:%i ch:%s\n",
			__func__, dev->name, smp_processor_id(), ch->id);

	header = (struct th_header *)pskb->data;
	if ((header->th_seg == 0) &&
		(header->th_ch_flag == 0) &&
		(header->th_blk_flag == 0) &&
		(header->th_seq_num == 0))
		/* nothing for us */	goto done;

	CTCM_PR_DBGDATA("%s: th_header\n", __func__);
	CTCM_D3_DUMP((char *)header, TH_HEADER_LENGTH);
	CTCM_PR_DBGDATA("%s: pskb len: %04x \n", __func__, pskb->len);

	pskb->dev = dev;
	pskb->ip_summed = CHECKSUM_UNNECESSARY;
	skb_pull(pskb, TH_HEADER_LENGTH);

	if (likely(header->th_ch_flag == TH_HAS_PDU)) {
		CTCM_PR_DBGDATA("%s: came into th_has_pdu\n", __func__);
		if ((fsm_getstate(grp->fsm) == MPCG_STATE_FLOWC) ||
		   ((fsm_getstate(grp->fsm) == MPCG_STATE_READY) &&
		    (header->th_seq_num != ch->th_seq_num + 1) &&
		    (ch->th_seq_num != 0))) {
			/* This is NOT the next segment		*
			 * we are not the correct race winner	*
			 * go away and let someone else win	*
			 * BUT..this only applies if xid negot	*
			 * is done				*
			*/
			grp->out_of_sequence += 1;
			__skb_push(pskb, TH_HEADER_LENGTH);
			skb_queue_tail(&ch->io_queue, pskb);
			CTCM_PR_DBGDATA("%s: th_seq_num expect:%08x "
					"got:%08x\n", __func__,
				ch->th_seq_num + 1, header->th_seq_num);

			return;
		}
		grp->out_of_sequence = 0;
		ch->th_seq_num = header->th_seq_num;

		CTCM_PR_DBGDATA("ctcmpc: %s() FromVTAM_th_seq=%08x\n",
					__func__, ch->th_seq_num);

		if (unlikely(fsm_getstate(grp->fsm) != MPCG_STATE_READY))
					goto done;
		while ((pskb->len > 0) && !pdu_last_seen) {
			curr_pdu = (struct pdu *)pskb->data;

			CTCM_PR_DBGDATA("%s: pdu_header\n", __func__);
			CTCM_D3_DUMP((char *)pskb->data, PDU_HEADER_LENGTH);
			CTCM_PR_DBGDATA("%s: pskb len: %04x \n",
						__func__, pskb->len);

			skb_pull(pskb, PDU_HEADER_LENGTH);

			if (curr_pdu->pdu_flag & PDU_LAST)
				pdu_last_seen = 1;
			if (curr_pdu->pdu_flag & PDU_CNTL)
				pskb->protocol = htons(ETH_P_SNAP);
			else
				pskb->protocol = htons(ETH_P_SNA_DIX);

			if ((pskb->len <= 0) || (pskb->len > ch->max_bufsize)) {
				CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
					"%s(%s): Dropping packet with "
					"illegal siize %d",
					CTCM_FUNTAIL, dev->name, pskb->len);

				priv->stats.rx_dropped++;
				priv->stats.rx_length_errors++;
					goto done;
			}
			skb_reset_mac_header(pskb);
			new_len = curr_pdu->pdu_offset;
			CTCM_PR_DBGDATA("%s: new_len: %04x \n",
						__func__, new_len);
			if ((new_len == 0) || (new_len > pskb->len)) {
				/* should never happen		    */
				/* pskb len must be hosed...bail out */
				CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
					"%s(%s): non valid pdu_offset: %04x",
					/* "data may be lost", */
					CTCM_FUNTAIL, dev->name, new_len);
				goto done;
			}
			skb = __dev_alloc_skb(new_len+4, GFP_ATOMIC);

			if (!skb) {
				CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
					"%s(%s): MEMORY allocation error",
						CTCM_FUNTAIL, dev->name);
				priv->stats.rx_dropped++;
				fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
						goto done;
			}
			skb_put_data(skb, pskb->data, new_len);

			skb_reset_mac_header(skb);
			skb->dev = pskb->dev;
			skb->protocol = pskb->protocol;
			skb->ip_summed = CHECKSUM_UNNECESSARY;
			*((__u32 *) skb_push(skb, 4)) = ch->pdu_seq;
			ch->pdu_seq++;

			if (do_debug_data) {
				ctcm_pr_debug("%s: ToDCM_pdu_seq= %08x\n",
						__func__, ch->pdu_seq);
				ctcm_pr_debug("%s: skb:%0lx "
					"skb len: %d \n", __func__,
					(unsigned long)skb, skb->len);
				ctcm_pr_debug("%s: up to 32 bytes "
					"of pdu_data sent\n", __func__);
				ctcmpc_dump32((char *)skb->data, skb->len);
			}

			skblen = skb->len;
			sendrc = netif_rx(skb);
			priv->stats.rx_packets++;
			priv->stats.rx_bytes += skblen;
			skb_pull(pskb, new_len); /* point to next PDU */
		}
	} else {
		mpcginfo = kmalloc(sizeof(struct mpcg_info), GFP_ATOMIC);
		if (mpcginfo == NULL)
					goto done;

		mpcginfo->ch = ch;
		mpcginfo->th = header;
		mpcginfo->skb = pskb;
		CTCM_PR_DEBUG("%s: Not PDU - may be control pkt\n",
					__func__);
		/*  it's a sweep?   */
		sweep = (struct th_sweep *)pskb->data;
		mpcginfo->sweep = sweep;
		if (header->th_ch_flag == TH_SWEEP_REQ)
			mpc_rcvd_sweep_req(mpcginfo);
		else if (header->th_ch_flag == TH_SWEEP_RESP)
			mpc_rcvd_sweep_resp(mpcginfo);
		else if (header->th_blk_flag == TH_DATA_IS_XID) {
			struct xid2 *thisxid = (struct xid2 *)pskb->data;
			skb_pull(pskb, XID2_LENGTH);
			mpcginfo->xid = thisxid;
			fsm_event(grp->fsm, MPCG_EVENT_XID2, mpcginfo);
		} else if (header->th_blk_flag == TH_DISCONTACT)
			fsm_event(grp->fsm, MPCG_EVENT_DISCONC, mpcginfo);
		else if (header->th_seq_num != 0) {
			CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
				"%s(%s): control pkt expected\n",
						CTCM_FUNTAIL, dev->name);
			priv->stats.rx_dropped++;
			/* mpcginfo only used for non-data transfers */
			kfree(mpcginfo);
			if (do_debug_data)
				ctcmpc_dump_skb(pskb, -8);
		}
	}
done:

	dev_kfree_skb_any(pskb);
	if (sendrc == NET_RX_DROP) {
		dev_warn(&dev->dev,
			"The network backlog for %s is exceeded, "
			"package dropped\n", __func__);
		fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
	}

	CTCM_PR_DEBUG("exit %s: %s: ch=0x%p id=%s\n",
			__func__, dev->name, ch, ch->id);
}