1719 lines · 41.8 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * IPv4 over IEEE 1394, per RFC 2734 * IPv6 over IEEE 1394, per RFC 3146 * * Copyright (C) 2009 Jay Fenlason <fenlason@redhat.com> * * based on eth1394 by Ben Collins et al */ #include <linux/bug.h>#include <linux/compiler.h>#include <linux/delay.h>#include <linux/device.h>#include <linux/ethtool.h>#include <linux/firewire.h>#include <linux/firewire-constants.h>#include <linux/highmem.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/jiffies.h>#include <linux/mod_devicetable.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/mutex.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <linux/slab.h>#include <linux/spinlock.h> #include <asm/unaligned.h>#include <net/arp.h>#include <net/firewire.h> /* rx limits */#define FWNET_MAX_FRAGMENTS		30 /* arbitrary, > TX queue depth */#define FWNET_ISO_PAGE_COUNT		(PAGE_SIZE < 16*1024 ? 4 : 2) /* tx limits */#define FWNET_MAX_QUEUED_DATAGRAMS	20 /* < 64 = number of tlabels */#define FWNET_MIN_QUEUED_DATAGRAMS	10 /* should keep AT DMA busy enough */#define FWNET_TX_QUEUE_LEN		FWNET_MAX_QUEUED_DATAGRAMS /* ? */ #define IEEE1394_BROADCAST_CHANNEL	31#define IEEE1394_ALL_NODES		(0xffc0 | 0x003f)#define IEEE1394_MAX_PAYLOAD_S100	512#define FWNET_NO_FIFO_ADDR		(~0ULL) #define IANA_SPECIFIER_ID		0x00005eU#define RFC2734_SW_VERSION		0x000001U#define RFC3146_SW_VERSION		0x000002U #define IEEE1394_GASP_HDR_SIZE	8 #define RFC2374_UNFRAG_HDR_SIZE	4#define RFC2374_FRAG_HDR_SIZE	8#define RFC2374_FRAG_OVERHEAD	4 #define RFC2374_HDR_UNFRAG	0	/* unfragmented		*/#define RFC2374_HDR_FIRSTFRAG	1	/* first fragment	*/#define RFC2374_HDR_LASTFRAG	2	/* last fragment	*/#define RFC2374_HDR_INTFRAG	3	/* interior fragment	*/ static bool fwnet_hwaddr_is_multicast(u8 *ha){	return !!(*ha & 1);} /* IPv4 and IPv6 encapsulation header */struct rfc2734_header {	u32 w0;	u32 w1;}; #define fwnet_get_hdr_lf(h)		(((h)->w0 & 0xc0000000) >> 30)#define fwnet_get_hdr_ether_type(h)	(((h)->w0 & 0x0000ffff))#define fwnet_get_hdr_dg_size(h)	((((h)->w0 & 0x0fff0000) >> 16) + 1)#define fwnet_get_hdr_fg_off(h)		(((h)->w0 & 0x00000fff))#define fwnet_get_hdr_dgl(h)		(((h)->w1 & 0xffff0000) >> 16) #define fwnet_set_hdr_lf(lf)		((lf) << 30)#define fwnet_set_hdr_ether_type(et)	(et)#define fwnet_set_hdr_dg_size(dgs)	(((dgs) - 1) << 16)#define fwnet_set_hdr_fg_off(fgo)	(fgo) #define fwnet_set_hdr_dgl(dgl)		((dgl) << 16) static inline void fwnet_make_uf_hdr(struct rfc2734_header *hdr,		unsigned ether_type){	hdr->w0 = fwnet_set_hdr_lf(RFC2374_HDR_UNFRAG)		  | fwnet_set_hdr_ether_type(ether_type);} static inline void fwnet_make_ff_hdr(struct rfc2734_header *hdr,		unsigned ether_type, unsigned dg_size, unsigned dgl){	hdr->w0 = fwnet_set_hdr_lf(RFC2374_HDR_FIRSTFRAG)		  | fwnet_set_hdr_dg_size(dg_size)		  | fwnet_set_hdr_ether_type(ether_type);	hdr->w1 = fwnet_set_hdr_dgl(dgl);} static inline void fwnet_make_sf_hdr(struct rfc2734_header *hdr,		unsigned lf, unsigned dg_size, unsigned fg_off, unsigned dgl){	hdr->w0 = fwnet_set_hdr_lf(lf)		  | fwnet_set_hdr_dg_size(dg_size)		  | fwnet_set_hdr_fg_off(fg_off);	hdr->w1 = fwnet_set_hdr_dgl(dgl);} /* This list keeps track of what parts of the datagram have been filled in */struct fwnet_fragment_info {	struct list_head fi_link;	u16 offset;	u16 len;}; struct fwnet_partial_datagram {	struct list_head pd_link;	struct list_head fi_list;	struct sk_buff *skb;	/* FIXME Why not use skb->data? */	char *pbuf;	u16 datagram_label;	u16 ether_type;	u16 datagram_size;}; static DEFINE_MUTEX(fwnet_device_mutex);static LIST_HEAD(fwnet_device_list); struct fwnet_device {	struct list_head dev_link;	spinlock_t lock;	enum {		FWNET_BROADCAST_ERROR,		FWNET_BROADCAST_RUNNING,		FWNET_BROADCAST_STOPPED,	} broadcast_state;	struct fw_iso_context *broadcast_rcv_context;	struct fw_iso_buffer broadcast_rcv_buffer;	void **broadcast_rcv_buffer_ptrs;	unsigned broadcast_rcv_next_ptr;	unsigned num_broadcast_rcv_ptrs;	unsigned rcv_buffer_size;	/*	 * This value is the maximum unfragmented datagram size that can be	 * sent by the hardware.  It already has the GASP overhead and the	 * unfragmented datagram header overhead calculated into it.	 */	unsigned broadcast_xmt_max_payload;	u16 broadcast_xmt_datagramlabel; 	/*	 * The CSR address that remote nodes must send datagrams to for us to	 * receive them.	 */	struct fw_address_handler handler;	u64 local_fifo; 	/* Number of tx datagrams that have been queued but not yet acked */	int queued_datagrams; 	int peer_count;	struct list_head peer_list;	struct fw_card *card;	struct net_device *netdev;}; struct fwnet_peer {	struct list_head peer_link;	struct fwnet_device *dev;	u64 guid; 	/* guarded by dev->lock */	struct list_head pd_list; /* received partial datagrams */	unsigned pdg_size;        /* pd_list size */ 	u16 datagram_label;       /* outgoing datagram label */	u16 max_payload;          /* includes RFC2374_FRAG_HDR_SIZE overhead */	int node_id;	int generation;	unsigned speed;}; /* This is our task struct. It's used for the packet complete callback.  */struct fwnet_packet_task {	struct fw_transaction transaction;	struct rfc2734_header hdr;	struct sk_buff *skb;	struct fwnet_device *dev; 	int outstanding_pkts;	u64 fifo_addr;	u16 dest_node;	u16 max_payload;	u8 generation;	u8 speed;	u8 enqueued;}; /* * Get fifo address embedded in hwaddr */static __u64 fwnet_hwaddr_fifo(union fwnet_hwaddr *ha){	return (u64)get_unaligned_be16(&ha->uc.fifo_hi) << 32	       | get_unaligned_be32(&ha->uc.fifo_lo);} /* * saddr == NULL means use device source address. * daddr == NULL means leave destination address (eg unresolved arp). */static int fwnet_header_create(struct sk_buff *skb, struct net_device *net,			unsigned short type, const void *daddr,			const void *saddr, unsigned len){	struct fwnet_header *h; 	h = skb_push(skb, sizeof(*h));	put_unaligned_be16(type, &h->h_proto); 	if (net->flags & (IFF_LOOPBACK | IFF_NOARP)) {		memset(h->h_dest, 0, net->addr_len); 		return net->hard_header_len;	} 	if (daddr) {		memcpy(h->h_dest, daddr, net->addr_len); 		return net->hard_header_len;	} 	return -net->hard_header_len;} static int fwnet_header_cache(const struct neighbour *neigh,			      struct hh_cache *hh, __be16 type){	struct net_device *net;	struct fwnet_header *h; 	if (type == cpu_to_be16(ETH_P_802_3))		return -1;	net = neigh->dev;	h = (struct fwnet_header *)((u8 *)hh->hh_data + HH_DATA_OFF(sizeof(*h)));	h->h_proto = type;	memcpy(h->h_dest, neigh->ha, net->addr_len); 	/* Pairs with the READ_ONCE() in neigh_resolve_output(),	 * neigh_hh_output() and neigh_update_hhs().	 */	smp_store_release(&hh->hh_len, FWNET_HLEN); 	return 0;} /* Called by Address Resolution module to notify changes in address. */static void fwnet_header_cache_update(struct hh_cache *hh,		const struct net_device *net, const unsigned char *haddr){	memcpy((u8 *)hh->hh_data + HH_DATA_OFF(FWNET_HLEN), haddr, net->addr_len);} static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr){	memcpy(haddr, skb->dev->dev_addr, FWNET_ALEN); 	return FWNET_ALEN;} static const struct header_ops fwnet_header_ops = {	.create         = fwnet_header_create,	.cache		= fwnet_header_cache,	.cache_update	= fwnet_header_cache_update,	.parse          = fwnet_header_parse,}; /* FIXME: is this correct for all cases? */static bool fwnet_frag_overlap(struct fwnet_partial_datagram *pd,			       unsigned offset, unsigned len){	struct fwnet_fragment_info *fi;	unsigned end = offset + len; 	list_for_each_entry(fi, &pd->fi_list, fi_link)		if (offset < fi->offset + fi->len && end > fi->offset)			return true; 	return false;} /* Assumes that new fragment does not overlap any existing fragments */static struct fwnet_fragment_info *fwnet_frag_new(	struct fwnet_partial_datagram *pd, unsigned offset, unsigned len){	struct fwnet_fragment_info *fi, *fi2, *new;	struct list_head *list; 	list = &pd->fi_list;	list_for_each_entry(fi, &pd->fi_list, fi_link) {		if (fi->offset + fi->len == offset) {			/* The new fragment can be tacked on to the end */			/* Did the new fragment plug a hole? */			fi2 = list_entry(fi->fi_link.next,					 struct fwnet_fragment_info, fi_link);			if (fi->offset + fi->len == fi2->offset) {				/* glue fragments together */				fi->len += len + fi2->len;				list_del(&fi2->fi_link);				kfree(fi2);			} else {				fi->len += len;			} 			return fi;		}		if (offset + len == fi->offset) {			/* The new fragment can be tacked on to the beginning */			/* Did the new fragment plug a hole? */			fi2 = list_entry(fi->fi_link.prev,					 struct fwnet_fragment_info, fi_link);			if (fi2->offset + fi2->len == fi->offset) {				/* glue fragments together */				fi2->len += fi->len + len;				list_del(&fi->fi_link);				kfree(fi); 				return fi2;			}			fi->offset = offset;			fi->len += len; 			return fi;		}		if (offset > fi->offset + fi->len) {			list = &fi->fi_link;			break;		}		if (offset + len < fi->offset) {			list = fi->fi_link.prev;			break;		}	} 	new = kmalloc(sizeof(*new), GFP_ATOMIC);	if (!new)		return NULL; 	new->offset = offset;	new->len = len;	list_add(&new->fi_link, list); 	return new;} static struct fwnet_partial_datagram *fwnet_pd_new(struct net_device *net,		struct fwnet_peer *peer, u16 datagram_label, unsigned dg_size,		void *frag_buf, unsigned frag_off, unsigned frag_len){	struct fwnet_partial_datagram *new;	struct fwnet_fragment_info *fi; 	new = kmalloc(sizeof(*new), GFP_ATOMIC);	if (!new)		goto fail; 	INIT_LIST_HEAD(&new->fi_list);	fi = fwnet_frag_new(new, frag_off, frag_len);	if (fi == NULL)		goto fail_w_new; 	new->datagram_label = datagram_label;	new->datagram_size = dg_size;	new->skb = dev_alloc_skb(dg_size + LL_RESERVED_SPACE(net));	if (new->skb == NULL)		goto fail_w_fi; 	skb_reserve(new->skb, LL_RESERVED_SPACE(net));	new->pbuf = skb_put(new->skb, dg_size);	memcpy(new->pbuf + frag_off, frag_buf, frag_len);	list_add_tail(&new->pd_link, &peer->pd_list); 	return new; fail_w_fi:	kfree(fi);fail_w_new:	kfree(new);fail:	return NULL;} static struct fwnet_partial_datagram *fwnet_pd_find(struct fwnet_peer *peer,						    u16 datagram_label){	struct fwnet_partial_datagram *pd; 	list_for_each_entry(pd, &peer->pd_list, pd_link)		if (pd->datagram_label == datagram_label)			return pd; 	return NULL;}  static void fwnet_pd_delete(struct fwnet_partial_datagram *old){	struct fwnet_fragment_info *fi, *n; 	list_for_each_entry_safe(fi, n, &old->fi_list, fi_link)		kfree(fi); 	list_del(&old->pd_link);	dev_kfree_skb_any(old->skb);	kfree(old);} static bool fwnet_pd_update(struct fwnet_peer *peer,		struct fwnet_partial_datagram *pd, void *frag_buf,		unsigned frag_off, unsigned frag_len){	if (fwnet_frag_new(pd, frag_off, frag_len) == NULL)		return false; 	memcpy(pd->pbuf + frag_off, frag_buf, frag_len); 	/*	 * Move list entry to beginning of list so that oldest partial	 * datagrams percolate to the end of the list	 */	list_move_tail(&pd->pd_link, &peer->pd_list); 	return true;} static bool fwnet_pd_is_complete(struct fwnet_partial_datagram *pd){	struct fwnet_fragment_info *fi; 	fi = list_entry(pd->fi_list.next, struct fwnet_fragment_info, fi_link); 	return fi->len == pd->datagram_size;} /* caller must hold dev->lock */static struct fwnet_peer *fwnet_peer_find_by_guid(struct fwnet_device *dev,						  u64 guid){	struct fwnet_peer *peer; 	list_for_each_entry(peer, &dev->peer_list, peer_link)		if (peer->guid == guid)			return peer; 	return NULL;} /* caller must hold dev->lock */static struct fwnet_peer *fwnet_peer_find_by_node_id(struct fwnet_device *dev,						int node_id, int generation){	struct fwnet_peer *peer; 	list_for_each_entry(peer, &dev->peer_list, peer_link)		if (peer->node_id    == node_id &&		    peer->generation == generation)			return peer; 	return NULL;} /* See IEEE 1394-2008 table 6-4, table 8-8, table 16-18. */static unsigned fwnet_max_payload(unsigned max_rec, unsigned speed){	max_rec = min(max_rec, speed + 8);	max_rec = clamp(max_rec, 8U, 11U); /* 512...4096 */ 	return (1 << (max_rec + 1)) - RFC2374_FRAG_HDR_SIZE;}  static int fwnet_finish_incoming_packet(struct net_device *net,					struct sk_buff *skb, u16 source_node_id,					bool is_broadcast, u16 ether_type){	struct fwnet_device *dev;	int status;	__be64 guid; 	switch (ether_type) {	case ETH_P_ARP:	case ETH_P_IP:#if IS_ENABLED(CONFIG_IPV6)	case ETH_P_IPV6:#endif

Lines 1–500 of 1719.