📄 eth1394.c
字号:
node_info->fifo = fifo_addr;
/* Now that we're done with the 1394 specific stuff, we'll
* need to alter some of the data. Believe it or not, all
* that needs to be done is sender_IP_address needs to be
* moved, the destination hardware address get stuffed
* in and the hardware address length set to 8.
*
* IMPORTANT: The code below overwrites 1394 specific data
* needed above so keep the munging of the data for the
* higher level IP stack last. */
arp->ar_hln = 8;
arp_ptr += arp->ar_hln; /* skip over sender unique id */
*(u32 *)arp_ptr = arp1394->sip; /* move sender IP addr */
arp_ptr += arp->ar_pln; /* skip over sender IP addr */
if (arp->ar_op == htons(ARPOP_REQUEST))
memset(arp_ptr, 0, sizeof(u64));
else
memcpy(arp_ptr, dev->dev_addr, sizeof(u64));
}
/* Now add the ethernet header. */
if (dev->hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
skb->len) >= 0)
ret = ether1394_type_trans(skb, dev);
return ret;
}
static int fragment_overlap(struct list_head *frag_list, int offset, int len)
{
struct fragment_info *fi;
int end = offset + len;
list_for_each_entry(fi, frag_list, list)
if (offset < fi->offset + fi->len && end > fi->offset)
return 1;
return 0;
}
static struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl)
{
struct partial_datagram *pd;
list_for_each_entry(pd, pdgl, list)
if (pd->dgl == dgl)
return &pd->list;
return NULL;
}
/* Assumes that new fragment does not overlap any existing fragments */
static int new_fragment(struct list_head *frag_info, int offset, int len)
{
struct list_head *lh;
struct fragment_info *fi, *fi2, *new;
list_for_each(lh, frag_info) {
fi = list_entry(lh, struct fragment_info, list);
if (fi->offset + fi->len == offset) {
/* The new fragment can be tacked on to the end */
fi->len += len;
/* Did the new fragment plug a hole? */
fi2 = list_entry(lh->next, struct fragment_info, list);
if (fi->offset + fi->len == fi2->offset) {
/* glue fragments together */
fi->len += fi2->len;
list_del(lh->next);
kfree(fi2);
}
return 0;
} else if (offset + len == fi->offset) {
/* The new fragment can be tacked on to the beginning */
fi->offset = offset;
fi->len += len;
/* Did the new fragment plug a hole? */
fi2 = list_entry(lh->prev, struct fragment_info, list);
if (fi2->offset + fi2->len == fi->offset) {
/* glue fragments together */
fi2->len += fi->len;
list_del(lh);
kfree(fi);
}
return 0;
} else if (offset > fi->offset + fi->len) {
break;
} else if (offset + len < fi->offset) {
lh = lh->prev;
break;
}
}
new = kmalloc(sizeof(*new), GFP_ATOMIC);
if (!new)
return -ENOMEM;
new->offset = offset;
new->len = len;
list_add(&new->list, lh);
return 0;
}
static int new_partial_datagram(struct net_device *dev, struct list_head *pdgl,
int dgl, int dg_size, char *frag_buf,
int frag_off, int frag_len)
{
struct partial_datagram *new;
new = kmalloc(sizeof(*new), GFP_ATOMIC);
if (!new)
return -ENOMEM;
INIT_LIST_HEAD(&new->frag_info);
if (new_fragment(&new->frag_info, frag_off, frag_len) < 0) {
kfree(new);
return -ENOMEM;
}
new->dgl = dgl;
new->dg_size = dg_size;
new->skb = dev_alloc_skb(dg_size + dev->hard_header_len + 15);
if (!new->skb) {
struct fragment_info *fi = list_entry(new->frag_info.next,
struct fragment_info,
list);
kfree(fi);
kfree(new);
return -ENOMEM;
}
skb_reserve(new->skb, (dev->hard_header_len + 15) & ~15);
new->pbuf = skb_put(new->skb, dg_size);
memcpy(new->pbuf + frag_off, frag_buf, frag_len);
list_add(&new->list, pdgl);
return 0;
}
static int update_partial_datagram(struct list_head *pdgl, struct list_head *lh,
char *frag_buf, int frag_off, int frag_len)
{
struct partial_datagram *pd =
list_entry(lh, struct partial_datagram, list);
if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0)
return -ENOMEM;
memcpy(pd->pbuf + frag_off, frag_buf, frag_len);
/* Move list entry to beginnig of list so that oldest partial
* datagrams percolate to the end of the list */
list_move(lh, pdgl);
return 0;
}
static int is_datagram_complete(struct list_head *lh, int dg_size)
{
struct partial_datagram *pd;
struct fragment_info *fi;
pd = list_entry(lh, struct partial_datagram, list);
fi = list_entry(pd->frag_info.next, struct fragment_info, list);
return (fi->len == dg_size);
}
/* Packet reception. We convert the IP1394 encapsulation header to an
* ethernet header, and fill it with some of our other fields. This is
* an incoming packet from the 1394 bus. */
static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
char *buf, int len)
{
struct sk_buff *skb;
unsigned long flags;
struct eth1394_priv *priv = netdev_priv(dev);
union eth1394_hdr *hdr = (union eth1394_hdr *)buf;
u16 ether_type = 0; /* initialized to clear warning */
int hdr_len;
struct unit_directory *ud = priv->ud_list[NODEID_TO_NODE(srcid)];
struct eth1394_node_info *node_info;
if (!ud) {
struct eth1394_node_ref *node;
node = eth1394_find_node_nodeid(&priv->ip_node_list, srcid);
if (unlikely(!node)) {
HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid "
"lookup failure: " NODE_BUS_FMT,
NODE_BUS_ARGS(priv->host, srcid));
priv->stats.rx_dropped++;
return -1;
}
ud = node->ud;
priv->ud_list[NODEID_TO_NODE(srcid)] = ud;
}
node_info = (struct eth1394_node_info *)ud->device.driver_data;
/* First, did we receive a fragmented or unfragmented datagram? */
hdr->words.word1 = ntohs(hdr->words.word1);
hdr_len = hdr_type_len[hdr->common.lf];
if (hdr->common.lf == ETH1394_HDR_LF_UF) {
/* An unfragmented datagram has been received by the ieee1394
* bus. Build an skbuff around it so we can pass it to the
* high level network layer. */
skb = dev_alloc_skb(len + dev->hard_header_len + 15);
if (unlikely(!skb)) {
ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
priv->stats.rx_dropped++;
return -1;
}
skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
memcpy(skb_put(skb, len - hdr_len), buf + hdr_len,
len - hdr_len);
ether_type = hdr->uf.ether_type;
} else {
/* A datagram fragment has been received, now the fun begins. */
struct list_head *pdgl, *lh;
struct partial_datagram *pd;
int fg_off;
int fg_len = len - hdr_len;
int dg_size;
int dgl;
int retval;
struct pdg_list *pdg = &(node_info->pdg);
hdr->words.word3 = ntohs(hdr->words.word3);
/* The 4th header word is reserved so no need to do ntohs() */
if (hdr->common.lf == ETH1394_HDR_LF_FF) {
ether_type = hdr->ff.ether_type;
dgl = hdr->ff.dgl;
dg_size = hdr->ff.dg_size + 1;
fg_off = 0;
} else {
hdr->words.word2 = ntohs(hdr->words.word2);
dgl = hdr->sf.dgl;
dg_size = hdr->sf.dg_size + 1;
fg_off = hdr->sf.fg_off;
}
spin_lock_irqsave(&pdg->lock, flags);
pdgl = &(pdg->list);
lh = find_partial_datagram(pdgl, dgl);
if (lh == NULL) {
while (pdg->sz >= max_partial_datagrams) {
/* remove the oldest */
purge_partial_datagram(pdgl->prev);
pdg->sz--;
}
retval = new_partial_datagram(dev, pdgl, dgl, dg_size,
buf + hdr_len, fg_off,
fg_len);
if (retval < 0) {
spin_unlock_irqrestore(&pdg->lock, flags);
goto bad_proto;
}
pdg->sz++;
lh = find_partial_datagram(pdgl, dgl);
} else {
struct partial_datagram *pd;
pd = list_entry(lh, struct partial_datagram, list);
if (fragment_overlap(&pd->frag_info, fg_off, fg_len)) {
/* Overlapping fragments, obliterate old
* datagram and start new one. */
purge_partial_datagram(lh);
retval = new_partial_datagram(dev, pdgl, dgl,
dg_size,
buf + hdr_len,
fg_off, fg_len);
if (retval < 0) {
pdg->sz--;
spin_unlock_irqrestore(&pdg->lock, flags);
goto bad_proto;
}
} else {
retval = update_partial_datagram(pdgl, lh,
buf + hdr_len,
fg_off, fg_len);
if (retval < 0) {
/* Couldn't save off fragment anyway
* so might as well obliterate the
* datagram now. */
purge_partial_datagram(lh);
pdg->sz--;
spin_unlock_irqrestore(&pdg->lock, flags);
goto bad_proto;
}
} /* fragment overlap */
} /* new datagram or add to existing one */
pd = list_entry(lh, struct partial_datagram, list);
if (hdr->common.lf == ETH1394_HDR_LF_FF)
pd->ether_type = ether_type;
if (is_datagram_complete(lh, dg_size)) {
ether_type = pd->ether_type;
pdg->sz--;
skb = skb_get(pd->skb);
purge_partial_datagram(lh);
spin_unlock_irqrestore(&pdg->lock, flags);
} else {
/* Datagram is not complete, we're done for the
* moment. */
spin_unlock_irqrestore(&pdg->lock, flags);
return 0;
}
} /* unframgented datagram or fragmented one */
/* Write metadata, and then pass to the receive level */
skb->dev = dev;
skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
/* Parse the encapsulation header. This actually does the job of
* converting to an ethernet frame header, aswell as arp
* conversion if needed. ARP conversion is easier in this
* direction, since we are using ethernet as our backend. */
skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid,
ether_type);
spin_lock_irqsave(&priv->lock, flags);
if (!skb->protocol) {
priv->stats.rx_errors++;
priv->stats.rx_dropped++;
dev_kfree_skb_any(skb);
goto bad_proto;
}
if (netif_rx(skb) == NET_RX_DROP) {
priv->stats.rx_errors++;
priv->stats.rx_dropped++;
goto bad_proto;
}
/* Statistics */
priv->stats.rx_packets++;
priv->stats.rx_bytes += skb->len;
bad_proto:
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
spin_unlock_irqrestore(&priv->lock, flags);
dev->last_rx = jiffies;
return 0;
}
static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
quadlet_t *data, u64 addr, size_t len, u16 flags)
{
struct eth1394_host_info *hi;
hi = hpsb_get_hostinfo(ð1394_highlevel, host);
if (unlikely(!hi)) {
ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
host->id);
return RCODE_ADDRESS_ERROR;
}
if (ether1394_data_handler(hi->dev, srcid, destid, (char*)data, len))
return RCODE_ADDRESS_ERROR;
else
return RCODE_COMPLETE;
}
static void ether1394_iso(struct hpsb_iso *iso)
{
quadlet_t *data;
char *buf;
struct eth1394_host_info *hi;
struct net_device *dev;
struct eth1394_priv *priv;
unsigned int len;
u32 specifier_id;
u16 source_id;
int i;
int nready;
hi = hpsb_get_hostinfo(ð1394_highlevel, iso->host);
if (unlikely(!hi)) {
ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
iso->host->id);
return;
}
dev = hi->dev;
nready = hpsb_iso_n_ready(iso);
for (i = 0; i < nready; i++) {
struct hpsb_iso_packet_info *info =
&iso->infos[(iso->first_packet + i) % iso->buf_packets];
data = (quadlet_t *)(iso->data_buf.kvirt + info->offset);
/* skip over GASP header */
buf = (char *)data + 8;
len = info->len - 8;
specifier_id = (be32_to_cpu(data[0]) & 0xffff) << 8 |
(be32_to_cpu(data[1]) & 0xff000000) >> 24;
source_id = be32_to_cpu(data[0]) >> 16;
priv = netdev_priv(dev);
if (info->channel != (iso->host->csr.broadcast_channel & 0x3f)
|| specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
/* This packet is not for us */
continue;
}
ether1394_data_handler(dev, source_id, LOCAL_BUS | ALL_NODES,
buf, len);
}
hpsb_iso_recv_release_packets(iso, i);
dev->last_rx = jiffies;
}
/******************************************
* Datagram transmission code
******************************************/
/* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the entire
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -