📄 eth1394.c
字号:
{ int i; struct host_info *hi = NULL; struct net_device *dev = NULL; struct eth1394_priv *priv; static int version_printed = 0; if (version_printed++ == 0) ETH1394_PRINT_G (KERN_INFO, "%s\n", version); /* We should really have our own alloc_hpsbdev() function in * net_init.c instead of calling the one for ethernet then hijacking * it for ourselves. That way we'd be a real networking device. */ dev = alloc_etherdev(sizeof (struct eth1394_priv)); if (dev == NULL) { ETH1394_PRINT_G (KERN_ERR, "Out of memory trying to allocate " "etherdevice for IEEE 1394 device %s-%d\n", host->driver->name, host->id); goto out; } SET_MODULE_OWNER(dev); dev->init = ether1394_init_dev; priv = (struct eth1394_priv *)dev->priv; spin_lock_init(&priv->lock); priv->host = host; for (i = 0; i < ALL_NODES; i++) { spin_lock_init(&priv->pdg[i].lock); INIT_LIST_HEAD(&priv->pdg[i].list); priv->pdg[i].sz = 0; } hi = hpsb_create_hostinfo(ð1394_highlevel, host, sizeof(*hi)); if (hi == NULL) { ETH1394_PRINT_G (KERN_ERR, "Out of memory trying to create " "hostinfo for IEEE 1394 device %s-%d\n", host->driver->name, host->id); goto out; } if (register_netdev (dev)) { ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n"); goto out; } ETH1394_PRINT (KERN_ERR, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (%s)\n", host->driver->name); hi->host = host; hi->dev = dev; /* Ignore validity in hopes that it will be set in the future. It'll * be checked when the eth device is opened. */ priv->broadcast_channel = host->csr.broadcast_channel & 0x3f; priv->iso = hpsb_iso_recv_init(host, 16 * 4096, 16, priv->broadcast_channel, 1, ether1394_iso); if (priv->iso == NULL) { priv->bc_state = ETHER1394_BC_CLOSED; } return;out: if (dev != NULL) kfree(dev); if (hi) hpsb_destroy_hostinfo(ð1394_highlevel, host); return;}/* Remove a card from our list */static void ether1394_remove_host (struct hpsb_host *host){ struct host_info *hi = hpsb_get_hostinfo(ð1394_highlevel, host); if (hi != NULL) { struct eth1394_priv *priv = (struct eth1394_priv *)hi->dev->priv; eth1394_iso_shutdown(priv); if (hi->dev) { unregister_netdev (hi->dev); kfree(hi->dev); } } return;}/* A reset has just arisen */static void ether1394_host_reset (struct hpsb_host *host){ struct host_info *hi = hpsb_get_hostinfo(ð1394_highlevel, host); struct net_device *dev; /* This can happen for hosts that we don't use */ if (hi == NULL) return; dev = hi->dev; /* Reset our private host data, but not our mtu */ netif_stop_queue (dev); ether1394_reset_priv (dev, 0); netif_wake_queue (dev);}/****************************************** * HW Header net device functions ******************************************//* These functions have been adapted from net/ethernet/eth.c *//* Create a fake MAC header for an arbitrary protocol layer. * saddr=NULL means use device source address * daddr=NULL means leave destination address (eg unresolved arp). */static int ether1394_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len){ struct eth1394hdr *eth = (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN); eth->h_proto = htons(type); if (dev->flags & (IFF_LOOPBACK|IFF_NOARP)) { memset(eth->h_dest, 0, dev->addr_len); return(dev->hard_header_len); } if (daddr) { memcpy(eth->h_dest,daddr,dev->addr_len); return dev->hard_header_len; } return -dev->hard_header_len;}/* Rebuild the faked MAC header. This is called after an ARP * (or in future other address resolution) has completed on this * sk_buff. We now let ARP fill in the other fields. * * This routine CANNOT use cached dst->neigh! * Really, it is used only when dst->neigh is wrong. */static int ether1394_rebuild_header(struct sk_buff *skb){ struct eth1394hdr *eth = (struct eth1394hdr *)skb->data; struct net_device *dev = skb->dev; switch (eth->h_proto) {#ifdef CONFIG_INET case __constant_htons(ETH_P_IP): return arp_find((unsigned char*)ð->h_dest, skb);#endif default: printk(KERN_DEBUG "%s: unable to resolve type %X addresses.\n", dev->name, (int)eth->h_proto); break; } return 0;}static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr){ struct net_device *dev = skb->dev; memcpy(haddr, dev->dev_addr, ETH1394_ALEN); return ETH1394_ALEN;}static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh){ unsigned short type = hh->hh_type; struct eth1394hdr *eth = (struct eth1394hdr*)(((u8*)hh->hh_data) + 6); struct net_device *dev = neigh->dev; if (type == __constant_htons(ETH_P_802_3)) { return -1; } eth->h_proto = type; memcpy(eth->h_dest, neigh->ha, dev->addr_len); hh->hh_len = ETH1394_HLEN; return 0;}/* Called by Address Resolution module to notify changes in address. */static void ether1394_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr){ memcpy(((u8*)hh->hh_data) + 6, haddr, dev->addr_len);}static int ether1394_mac_addr(struct net_device *dev, void *p){ if (netif_running(dev)) return -EBUSY; /* Not going to allow setting the MAC address, we really need to use * the real one suppliled by the hardware */ return -EINVAL; }/****************************************** * Datagram reception code ******************************************//* Copied from net/ethernet/eth.c */static inline u16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev){ struct eth1394hdr *eth; unsigned char *rawp; skb->mac.raw = skb->data; skb_pull (skb, ETH1394_HLEN); eth = (struct eth1394hdr*)skb->mac.raw; if (*eth->h_dest & 1) { if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len)==0) skb->pkt_type = PACKET_BROADCAST;#if 0 else skb->pkt_type = PACKET_MULTICAST;#endif } else { if (memcmp(eth->h_dest, dev->dev_addr, dev->addr_len)) skb->pkt_type = PACKET_OTHERHOST; } if (ntohs (eth->h_proto) >= 1536) return eth->h_proto; rawp = skb->data; if (*(unsigned short *)rawp == 0xFFFF) return htons (ETH_P_802_3); return htons (ETH_P_802_2);}/* Parse an encapsulated IP1394 header into an ethernet frame packet. * We also perform ARP translation here, if need be. */static inline u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev, nodeid_t srcid, nodeid_t destid, u16 ether_type){ struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; u64 dest_hw; unsigned short ret = 0; /* Setup our hw addresses. We use these to build the * ethernet header. */ if (destid == (LOCAL_BUS | ALL_NODES)) dest_hw = ~0ULL; /* broadcast */ else dest_hw = priv->eui[NODEID_TO_NODE(destid)]; /* If this is an ARP packet, convert it. First, we want to make * use of some of the fields, since they tell us a little bit * about the sending machine. */ if (ether_type == __constant_htons (ETH_P_ARP)) { unsigned long flags; struct eth1394_arp *arp1394 = (struct eth1394_arp*)skb->data; struct arphdr *arp = (struct arphdr *)skb->data; unsigned char *arp_ptr = (unsigned char *)(arp + 1); u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 | ntohl(arp1394->fifo_lo); u8 host_max_rec = (be32_to_cpu(priv->host->csr.rom[2]) >> 12) & 0xf; u8 max_rec = min(host_max_rec, (u8)(arp1394->max_rec)); u16 maxpayload = min(eth1394_speedto_maxpayload[arp1394->sspd], (u16)(1 << (max_rec + 1))); /* Update our speed/payload/fifo_offset table */ spin_lock_irqsave (&priv->lock, flags); ether1394_register_limits(NODEID_TO_NODE(srcid), maxpayload, arp1394->sspd, arp1394->s_uniq_id, fifo_addr, priv); spin_unlock_irqrestore (&priv->lock, flags); /* 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 data so keep the call to * ether1394_register_limits() before munging the data for the * higher level IP stack. */ 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 == 1) /* just set ARP req target unique ID to 0 */ memset(arp_ptr, 0, ETH1394_ALEN); else memcpy(arp_ptr, dev->dev_addr, ETH1394_ALEN); } /* Now add the ethernet header. */ if (dev->hard_header (skb, dev, __constant_ntohs (ether_type), &dest_hw, NULL, skb->len) >= 0) ret = ether1394_type_trans(skb, dev); return ret;}static inline int fragment_overlap(struct list_head *frag_list, int offset, int len){ struct list_head *lh; struct fragment_info *fi; list_for_each(lh, frag_list) { fi = list_entry(lh, struct fragment_info, list); if ( ! ((offset > (fi->offset + fi->len - 1)) || ((offset + len - 1) < fi->offset))) return 1; } return 0;}static inline struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl){ struct list_head *lh; struct partial_datagram *pd; list_for_each(lh, pdgl) { pd = list_entry(lh, struct partial_datagram, list); if (pd->dgl == dgl) return lh; } return NULL;}/* Assumes that new fragment does not overlap any existing fragments */static inline 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(struct fragment_info), GFP_ATOMIC); if (!new) return -ENOMEM; new->offset = offset; new->len = len; list_add(&new->list, lh); return 0;}static inline int new_partial_datagram(struct net_device *dev, struct list_head *pdgl, int dgl,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -