in clients/ssi_protocol.c [971:1039]
static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct hsi_client *cl = to_hsi_client(dev->dev.parent);
struct ssi_protocol *ssi = hsi_client_drvdata(cl);
struct hsi_msg *msg;
if ((skb->protocol != htons(ETH_P_PHONET)) ||
(skb->len < SSIP_MIN_PN_HDR))
goto drop;
/* Pad to 32-bits - FIXME: Revisit*/
if ((skb->len & 3) && skb_pad(skb, 4 - (skb->len & 3)))
goto inc_dropped;
/*
* Modem sends Phonet messages over SSI with its own endianness.
* Assume that modem has the same endianness as we do.
*/
if (skb_cow_head(skb, 0))
goto drop;
/* length field is exchanged in network byte order */
((u16 *)skb->data)[2] = htons(((u16 *)skb->data)[2]);
msg = ssip_alloc_data(ssi, skb, GFP_ATOMIC);
if (!msg) {
dev_dbg(&cl->device, "Dropping tx data: No memory\n");
goto drop;
}
msg->complete = ssip_tx_data_complete;
spin_lock_bh(&ssi->lock);
if (unlikely(ssi->main_state != ACTIVE)) {
spin_unlock_bh(&ssi->lock);
dev_dbg(&cl->device, "Dropping tx data: CMT is OFFLINE\n");
goto drop2;
}
list_add_tail(&msg->link, &ssi->txqueue);
ssi->txqueue_len++;
if (dev->tx_queue_len < ssi->txqueue_len) {
dev_info(&cl->device, "TX queue full %d\n", ssi->txqueue_len);
netif_stop_queue(dev);
}
if (ssi->send_state == SEND_IDLE) {
ssip_set_txstate(ssi, WAIT4READY);
spin_unlock_bh(&ssi->lock);
dev_dbg(&cl->device, "Start TX qlen %d\n", ssi->txqueue_len);
hsi_start_tx(cl);
} else if (ssi->send_state == SEND_READY) {
/* Needed for cmt-speech workaround */
dev_dbg(&cl->device, "Start TX on SEND READY qlen %d\n",
ssi->txqueue_len);
spin_unlock_bh(&ssi->lock);
schedule_work(&ssi->work);
} else {
spin_unlock_bh(&ssi->lock);
}
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
return 0;
drop2:
hsi_free_msg(msg);
drop:
dev_kfree_skb(skb);
inc_dropped:
dev->stats.tx_dropped++;
return 0;
}