⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eth1394.c

📁 IEE1394 火线接口驱动 for linux
💻 C
📖 第 1 页 / 共 4 页
字号:
{	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(&eth1394_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(&eth1394_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(&eth1394_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(&eth1394_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*)&eth->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 + -