static int fwnet_send_packet()

in net.c [953:1050]


static int fwnet_send_packet(struct fwnet_packet_task *ptask)
{
	struct fwnet_device *dev;
	unsigned tx_len;
	struct rfc2734_header *bufhdr;
	unsigned long flags;
	bool free;

	dev = ptask->dev;
	tx_len = ptask->max_payload;
	switch (fwnet_get_hdr_lf(&ptask->hdr)) {
	case RFC2374_HDR_UNFRAG:
		bufhdr = skb_push(ptask->skb, RFC2374_UNFRAG_HDR_SIZE);
		put_unaligned_be32(ptask->hdr.w0, &bufhdr->w0);
		break;

	case RFC2374_HDR_FIRSTFRAG:
	case RFC2374_HDR_INTFRAG:
	case RFC2374_HDR_LASTFRAG:
		bufhdr = skb_push(ptask->skb, RFC2374_FRAG_HDR_SIZE);
		put_unaligned_be32(ptask->hdr.w0, &bufhdr->w0);
		put_unaligned_be32(ptask->hdr.w1, &bufhdr->w1);
		break;

	default:
		BUG();
	}
	if (ptask->dest_node == IEEE1394_ALL_NODES) {
		u8 *p;
		int generation;
		int node_id;
		unsigned int sw_version;

		/* ptask->generation may not have been set yet */
		generation = dev->card->generation;
		smp_rmb();
		node_id = dev->card->node_id;

		switch (ptask->skb->protocol) {
		default:
			sw_version = RFC2734_SW_VERSION;
			break;
#if IS_ENABLED(CONFIG_IPV6)
		case htons(ETH_P_IPV6):
			sw_version = RFC3146_SW_VERSION;
#endif
		}

		p = skb_push(ptask->skb, IEEE1394_GASP_HDR_SIZE);
		put_unaligned_be32(node_id << 16 | IANA_SPECIFIER_ID >> 8, p);
		put_unaligned_be32((IANA_SPECIFIER_ID & 0xff) << 24
						| sw_version, &p[4]);

		/* We should not transmit if broadcast_channel.valid == 0. */
		fw_send_request(dev->card, &ptask->transaction,
				TCODE_STREAM_DATA,
				fw_stream_packet_destination_id(3,
						IEEE1394_BROADCAST_CHANNEL, 0),
				generation, SCODE_100, 0ULL, ptask->skb->data,
				tx_len + 8, fwnet_write_complete, ptask);

		spin_lock_irqsave(&dev->lock, flags);

		/* If the AT tasklet already ran, we may be last user. */
		free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
		if (!free)
			ptask->enqueued = true;
		else
			dec_queued_datagrams(dev);

		spin_unlock_irqrestore(&dev->lock, flags);

		goto out;
	}

	fw_send_request(dev->card, &ptask->transaction,
			TCODE_WRITE_BLOCK_REQUEST, ptask->dest_node,
			ptask->generation, ptask->speed, ptask->fifo_addr,
			ptask->skb->data, tx_len, fwnet_write_complete, ptask);

	spin_lock_irqsave(&dev->lock, flags);

	/* If the AT tasklet already ran, we may be last user. */
	free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
	if (!free)
		ptask->enqueued = true;
	else
		dec_queued_datagrams(dev);

	spin_unlock_irqrestore(&dev->lock, flags);

	netif_trans_update(dev->netdev);
 out:
	if (free)
		fwnet_free_ptask(ptask);

	return 0;
}