Blame view

drivers/firewire/net.c 43.1 KB
c76acec6d   Jay Fenlason   firewire: add IPv...
1
2
3
4
5
6
7
  /*
   * IPv4 over IEEE 1394, per RFC 2734
   *
   * Copyright (C) 2009 Jay Fenlason <fenlason@redhat.com>
   *
   * based on eth1394 by Ben Collins et al
   */
f91e3bd84   Stefan Richter   firewire: net: st...
8
  #include <linux/bug.h>
bf337b15c   August Lilleaas   firewire: net: re...
9
  #include <linux/compiler.h>
48553011c   Stefan Richter   firewire: net: re...
10
  #include <linux/delay.h>
c76acec6d   Jay Fenlason   firewire: add IPv...
11
  #include <linux/device.h>
c16714704   Stefan Richter   firewire: net: se...
12
  #include <linux/ethtool.h>
c76acec6d   Jay Fenlason   firewire: add IPv...
13
14
15
16
17
  #include <linux/firewire.h>
  #include <linux/firewire-constants.h>
  #include <linux/highmem.h>
  #include <linux/in.h>
  #include <linux/ip.h>
f91e3bd84   Stefan Richter   firewire: net: st...
18
  #include <linux/jiffies.h>
c76acec6d   Jay Fenlason   firewire: add IPv...
19
20
21
  #include <linux/mod_devicetable.h>
  #include <linux/module.h>
  #include <linux/moduleparam.h>
5a124d382   Stefan Richter   firewire: net: al...
22
  #include <linux/mutex.h>
c76acec6d   Jay Fenlason   firewire: add IPv...
23
24
  #include <linux/netdevice.h>
  #include <linux/skbuff.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
25
  #include <linux/slab.h>
5a124d382   Stefan Richter   firewire: net: al...
26
  #include <linux/spinlock.h>
c76acec6d   Jay Fenlason   firewire: add IPv...
27
28
29
  
  #include <asm/unaligned.h>
  #include <net/arp.h>
b2268830f   Stefan Richter   firewire: net: th...
30
31
32
33
34
35
36
37
  /* 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 /* ? */
c76acec6d   Jay Fenlason   firewire: add IPv...
38

f91e3bd84   Stefan Richter   firewire: net: st...
39
40
41
42
  #define IEEE1394_BROADCAST_CHANNEL	31
  #define IEEE1394_ALL_NODES		(0xffc0 | 0x003f)
  #define IEEE1394_MAX_PAYLOAD_S100	512
  #define FWNET_NO_FIFO_ADDR		(~0ULL)
c76acec6d   Jay Fenlason   firewire: add IPv...
43

f91e3bd84   Stefan Richter   firewire: net: st...
44
45
  #define IANA_SPECIFIER_ID		0x00005eU
  #define RFC2734_SW_VERSION		0x000001U
c76acec6d   Jay Fenlason   firewire: add IPv...
46

f91e3bd84   Stefan Richter   firewire: net: st...
47
  #define IEEE1394_GASP_HDR_SIZE	8
c76acec6d   Jay Fenlason   firewire: add IPv...
48

f91e3bd84   Stefan Richter   firewire: net: st...
49
50
51
  #define RFC2374_UNFRAG_HDR_SIZE	4
  #define RFC2374_FRAG_HDR_SIZE	8
  #define RFC2374_FRAG_OVERHEAD	4
c76acec6d   Jay Fenlason   firewire: add IPv...
52

f91e3bd84   Stefan Richter   firewire: net: st...
53
54
55
56
  #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	*/
c76acec6d   Jay Fenlason   firewire: add IPv...
57

f91e3bd84   Stefan Richter   firewire: net: st...
58
  #define RFC2734_HW_ADDR_LEN	16
c76acec6d   Jay Fenlason   firewire: add IPv...
59

f91e3bd84   Stefan Richter   firewire: net: st...
60
61
62
63
64
65
66
  struct rfc2734_arp {
  	__be16 hw_type;		/* 0x0018	*/
  	__be16 proto_type;	/* 0x0806       */
  	u8 hw_addr_len;		/* 16		*/
  	u8 ip_addr_len;		/* 4		*/
  	__be16 opcode;		/* ARP Opcode	*/
  	/* Above is exactly the same format as struct arphdr */
c76acec6d   Jay Fenlason   firewire: add IPv...
67

f91e3bd84   Stefan Richter   firewire: net: st...
68
69
70
71
72
73
74
  	__be64 s_uniq_id;	/* Sender's 64bit EUI			*/
  	u8 max_rec;		/* Sender's max packet size		*/
  	u8 sspd;		/* Sender's max speed			*/
  	__be16 fifo_hi;		/* hi 16bits of sender's FIFO addr	*/
  	__be32 fifo_lo;		/* lo 32bits of sender's FIFO addr	*/
  	__be32 sip;		/* Sender's IP Address			*/
  	__be32 tip;		/* IP Address of requested hw addr	*/
bf337b15c   August Lilleaas   firewire: net: re...
75
  } __packed;
c76acec6d   Jay Fenlason   firewire: add IPv...
76

f91e3bd84   Stefan Richter   firewire: net: st...
77
78
79
80
81
82
  /* This header format is specific to this driver implementation. */
  #define FWNET_ALEN	8
  #define FWNET_HLEN	10
  struct fwnet_header {
  	u8 h_dest[FWNET_ALEN];	/* destination address */
  	__be16 h_proto;		/* packet type ID field */
bf337b15c   August Lilleaas   firewire: net: re...
83
  } __packed;
c76acec6d   Jay Fenlason   firewire: add IPv...
84

f91e3bd84   Stefan Richter   firewire: net: st...
85
86
  /* IPv4 and IPv6 encapsulation header */
  struct rfc2734_header {
c76acec6d   Jay Fenlason   firewire: add IPv...
87
88
89
  	u32 w0;
  	u32 w1;
  };
f91e3bd84   Stefan Richter   firewire: net: st...
90
91
92
93
94
  #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)
  #define fwnet_get_hdr_fg_off(h)		(((h)->w0 & 0x00000fff))
  #define fwnet_get_hdr_dgl(h)		(((h)->w1 & 0xffff0000) >> 16)
c76acec6d   Jay Fenlason   firewire: add IPv...
95

f91e3bd84   Stefan Richter   firewire: net: st...
96
97
98
99
  #define fwnet_set_hdr_lf(lf)		((lf)  << 30)
  #define fwnet_set_hdr_ether_type(et)	(et)
  #define fwnet_set_hdr_dg_size(dgs)	((dgs) << 16)
  #define fwnet_set_hdr_fg_off(fgo)	(fgo)
c76acec6d   Jay Fenlason   firewire: add IPv...
100

f91e3bd84   Stefan Richter   firewire: net: st...
101
  #define fwnet_set_hdr_dgl(dgl)		((dgl) << 16)
c76acec6d   Jay Fenlason   firewire: add IPv...
102

f91e3bd84   Stefan Richter   firewire: net: st...
103
104
105
106
107
108
  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);
  }
c76acec6d   Jay Fenlason   firewire: add IPv...
109

f91e3bd84   Stefan Richter   firewire: net: st...
110
111
112
113
114
115
116
117
  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);
  }
c76acec6d   Jay Fenlason   firewire: add IPv...
118

f91e3bd84   Stefan Richter   firewire: net: st...
119
120
121
122
123
124
125
126
  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);
  }
c76acec6d   Jay Fenlason   firewire: add IPv...
127
128
  
  /* This list keeps track of what parts of the datagram have been filled in */
f91e3bd84   Stefan Richter   firewire: net: st...
129
130
  struct fwnet_fragment_info {
  	struct list_head fi_link;
c76acec6d   Jay Fenlason   firewire: add IPv...
131
132
133
  	u16 offset;
  	u16 len;
  };
f91e3bd84   Stefan Richter   firewire: net: st...
134
135
136
  struct fwnet_partial_datagram {
  	struct list_head pd_link;
  	struct list_head fi_list;
c76acec6d   Jay Fenlason   firewire: add IPv...
137
138
139
140
141
142
143
  	struct sk_buff *skb;
  	/* FIXME Why not use skb->data? */
  	char *pbuf;
  	u16 datagram_label;
  	u16 ether_type;
  	u16 datagram_size;
  };
5a124d382   Stefan Richter   firewire: net: al...
144
145
  static DEFINE_MUTEX(fwnet_device_mutex);
  static LIST_HEAD(fwnet_device_list);
c76acec6d   Jay Fenlason   firewire: add IPv...
146

f91e3bd84   Stefan Richter   firewire: net: st...
147
  struct fwnet_device {
5a124d382   Stefan Richter   firewire: net: al...
148
  	struct list_head dev_link;
c76acec6d   Jay Fenlason   firewire: add IPv...
149
  	spinlock_t lock;
f91e3bd84   Stefan Richter   firewire: net: st...
150
151
152
153
154
  	enum {
  		FWNET_BROADCAST_ERROR,
  		FWNET_BROADCAST_RUNNING,
  		FWNET_BROADCAST_STOPPED,
  	} broadcast_state;
c76acec6d   Jay Fenlason   firewire: add IPv...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  	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;
  
  	/*
f91e3bd84   Stefan Richter   firewire: net: st...
170
  	 * The CSR address that remote nodes must send datagrams to for us to
c76acec6d   Jay Fenlason   firewire: add IPv...
171
172
173
174
  	 * receive them.
  	 */
  	struct fw_address_handler handler;
  	u64 local_fifo;
48553011c   Stefan Richter   firewire: net: re...
175
176
  	/* Number of tx datagrams that have been queued but not yet acked */
  	int queued_datagrams;
c76acec6d   Jay Fenlason   firewire: add IPv...
177

c16714704   Stefan Richter   firewire: net: se...
178
  	int peer_count;
5a124d382   Stefan Richter   firewire: net: al...
179
  	struct list_head peer_list;
c76acec6d   Jay Fenlason   firewire: add IPv...
180
  	struct fw_card *card;
5a124d382   Stefan Richter   firewire: net: al...
181
182
183
184
185
186
187
188
  	struct net_device *netdev;
  };
  
  struct fwnet_peer {
  	struct list_head peer_link;
  	struct fwnet_device *dev;
  	u64 guid;
  	u64 fifo;
74a145049   Maxim Levitsky   firewire: net: in...
189
  	__be32 ip;
5a124d382   Stefan Richter   firewire: net: al...
190
191
192
193
194
195
  
  	/* guarded by dev->lock */
  	struct list_head pd_list; /* received partial datagrams */
  	unsigned pdg_size;        /* pd_list size */
  
  	u16 datagram_label;       /* outgoing datagram label */
48553011c   Stefan Richter   firewire: net: re...
196
  	u16 max_payload;          /* includes RFC2374_FRAG_HDR_SIZE overhead */
5a124d382   Stefan Richter   firewire: net: al...
197
198
199
  	int node_id;
  	int generation;
  	unsigned speed;
c76acec6d   Jay Fenlason   firewire: add IPv...
200
201
202
  };
  
  /* This is our task struct. It's used for the packet complete callback.  */
f91e3bd84   Stefan Richter   firewire: net: st...
203
  struct fwnet_packet_task {
c76acec6d   Jay Fenlason   firewire: add IPv...
204
  	struct fw_transaction transaction;
f91e3bd84   Stefan Richter   firewire: net: st...
205
  	struct rfc2734_header hdr;
c76acec6d   Jay Fenlason   firewire: add IPv...
206
  	struct sk_buff *skb;
f91e3bd84   Stefan Richter   firewire: net: st...
207
  	struct fwnet_device *dev;
c76acec6d   Jay Fenlason   firewire: add IPv...
208
  	int outstanding_pkts;
c76acec6d   Jay Fenlason   firewire: add IPv...
209
210
  	u64 fifo_addr;
  	u16 dest_node;
48553011c   Stefan Richter   firewire: net: re...
211
  	u16 max_payload;
c76acec6d   Jay Fenlason   firewire: add IPv...
212
213
  	u8 generation;
  	u8 speed;
48553011c   Stefan Richter   firewire: net: re...
214
  	u8 enqueued;
c76acec6d   Jay Fenlason   firewire: add IPv...
215
  };
f91e3bd84   Stefan Richter   firewire: net: st...
216
217
218
219
220
221
222
223
224
  /*
   * 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;
c76acec6d   Jay Fenlason   firewire: add IPv...
225

f91e3bd84   Stefan Richter   firewire: net: st...
226
227
  	h = (struct fwnet_header *)skb_push(skb, sizeof(*h));
  	put_unaligned_be16(type, &h->h_proto);
c76acec6d   Jay Fenlason   firewire: add IPv...
228

f91e3bd84   Stefan Richter   firewire: net: st...
229
230
  	if (net->flags & (IFF_LOOPBACK | IFF_NOARP)) {
  		memset(h->h_dest, 0, net->addr_len);
c76acec6d   Jay Fenlason   firewire: add IPv...
231

f91e3bd84   Stefan Richter   firewire: net: st...
232
  		return net->hard_header_len;
c76acec6d   Jay Fenlason   firewire: add IPv...
233
234
235
  	}
  
  	if (daddr) {
f91e3bd84   Stefan Richter   firewire: net: st...
236
237
238
  		memcpy(h->h_dest, daddr, net->addr_len);
  
  		return net->hard_header_len;
c76acec6d   Jay Fenlason   firewire: add IPv...
239
  	}
f91e3bd84   Stefan Richter   firewire: net: st...
240
  	return -net->hard_header_len;
c76acec6d   Jay Fenlason   firewire: add IPv...
241
  }
f91e3bd84   Stefan Richter   firewire: net: st...
242
  static int fwnet_header_rebuild(struct sk_buff *skb)
c76acec6d   Jay Fenlason   firewire: add IPv...
243
  {
f91e3bd84   Stefan Richter   firewire: net: st...
244
  	struct fwnet_header *h = (struct fwnet_header *)skb->data;
c76acec6d   Jay Fenlason   firewire: add IPv...
245

f91e3bd84   Stefan Richter   firewire: net: st...
246
247
  	if (get_unaligned_be16(&h->h_proto) == ETH_P_IP)
  		return arp_find((unsigned char *)&h->h_dest, skb);
c76acec6d   Jay Fenlason   firewire: add IPv...
248

f91e3bd84   Stefan Richter   firewire: net: st...
249
250
251
  	fw_notify("%s: unable to resolve type %04x addresses
  ",
  		  skb->dev->name, be16_to_cpu(h->h_proto));
c76acec6d   Jay Fenlason   firewire: add IPv...
252
253
  	return 0;
  }
f91e3bd84   Stefan Richter   firewire: net: st...
254
  static int fwnet_header_cache(const struct neighbour *neigh,
e69dd336e   David S. Miller   net: Push protoco...
255
  			      struct hh_cache *hh, __be16 type)
f91e3bd84   Stefan Richter   firewire: net: st...
256
257
258
  {
  	struct net_device *net;
  	struct fwnet_header *h;
c76acec6d   Jay Fenlason   firewire: add IPv...
259

e69dd336e   David S. Miller   net: Push protoco...
260
  	if (type == cpu_to_be16(ETH_P_802_3))
c76acec6d   Jay Fenlason   firewire: add IPv...
261
  		return -1;
f91e3bd84   Stefan Richter   firewire: net: st...
262
263
  	net = neigh->dev;
  	h = (struct fwnet_header *)((u8 *)hh->hh_data + 16 - sizeof(*h));
e69dd336e   David S. Miller   net: Push protoco...
264
  	h->h_proto = type;
f91e3bd84   Stefan Richter   firewire: net: st...
265
266
  	memcpy(h->h_dest, neigh->ha, net->addr_len);
  	hh->hh_len = FWNET_HLEN;
c76acec6d   Jay Fenlason   firewire: add IPv...
267

c76acec6d   Jay Fenlason   firewire: add IPv...
268
269
270
271
  	return 0;
  }
  
  /* Called by Address Resolution module to notify changes in address. */
f91e3bd84   Stefan Richter   firewire: net: st...
272
273
274
275
  static void fwnet_header_cache_update(struct hh_cache *hh,
  		const struct net_device *net, const unsigned char *haddr)
  {
  	memcpy((u8 *)hh->hh_data + 16 - FWNET_HLEN, haddr, net->addr_len);
c76acec6d   Jay Fenlason   firewire: add IPv...
276
  }
f91e3bd84   Stefan Richter   firewire: net: st...
277
278
279
280
281
  static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr)
  {
  	memcpy(haddr, skb->dev->dev_addr, FWNET_ALEN);
  
  	return FWNET_ALEN;
c76acec6d   Jay Fenlason   firewire: add IPv...
282
  }
f91e3bd84   Stefan Richter   firewire: net: st...
283
284
285
286
287
288
  static const struct header_ops fwnet_header_ops = {
  	.create         = fwnet_header_create,
  	.rebuild        = fwnet_header_rebuild,
  	.cache		= fwnet_header_cache,
  	.cache_update	= fwnet_header_cache_update,
  	.parse          = fwnet_header_parse,
c76acec6d   Jay Fenlason   firewire: add IPv...
289
  };
c76acec6d   Jay Fenlason   firewire: add IPv...
290
  /* FIXME: is this correct for all cases? */
f91e3bd84   Stefan Richter   firewire: net: st...
291
292
  static bool fwnet_frag_overlap(struct fwnet_partial_datagram *pd,
  			       unsigned offset, unsigned len)
c76acec6d   Jay Fenlason   firewire: add IPv...
293
  {
f91e3bd84   Stefan Richter   firewire: net: st...
294
  	struct fwnet_fragment_info *fi;
c76acec6d   Jay Fenlason   firewire: add IPv...
295
  	unsigned end = offset + len;
f91e3bd84   Stefan Richter   firewire: net: st...
296
297
  	list_for_each_entry(fi, &pd->fi_list, fi_link)
  		if (offset < fi->offset + fi->len && end > fi->offset)
c76acec6d   Jay Fenlason   firewire: add IPv...
298
  			return true;
f91e3bd84   Stefan Richter   firewire: net: st...
299

c76acec6d   Jay Fenlason   firewire: add IPv...
300
301
302
303
  	return false;
  }
  
  /* Assumes that new fragment does not overlap any existing fragments */
f91e3bd84   Stefan Richter   firewire: net: st...
304
305
306
307
  static struct fwnet_fragment_info *fwnet_frag_new(
  	struct fwnet_partial_datagram *pd, unsigned offset, unsigned len)
  {
  	struct fwnet_fragment_info *fi, *fi2, *new;
c76acec6d   Jay Fenlason   firewire: add IPv...
308
  	struct list_head *list;
f91e3bd84   Stefan Richter   firewire: net: st...
309
310
  	list = &pd->fi_list;
  	list_for_each_entry(fi, &pd->fi_list, fi_link) {
c76acec6d   Jay Fenlason   firewire: add IPv...
311
312
313
  		if (fi->offset + fi->len == offset) {
  			/* The new fragment can be tacked on to the end */
  			/* Did the new fragment plug a hole? */
f91e3bd84   Stefan Richter   firewire: net: st...
314
315
  			fi2 = list_entry(fi->fi_link.next,
  					 struct fwnet_fragment_info, fi_link);
c76acec6d   Jay Fenlason   firewire: add IPv...
316
  			if (fi->offset + fi->len == fi2->offset) {
c76acec6d   Jay Fenlason   firewire: add IPv...
317
318
  				/* glue fragments together */
  				fi->len += len + fi2->len;
f91e3bd84   Stefan Richter   firewire: net: st...
319
  				list_del(&fi2->fi_link);
c76acec6d   Jay Fenlason   firewire: add IPv...
320
321
  				kfree(fi2);
  			} else {
c76acec6d   Jay Fenlason   firewire: add IPv...
322
323
  				fi->len += len;
  			}
f91e3bd84   Stefan Richter   firewire: net: st...
324

c76acec6d   Jay Fenlason   firewire: add IPv...
325
326
327
328
329
  			return fi;
  		}
  		if (offset + len == fi->offset) {
  			/* The new fragment can be tacked on to the beginning */
  			/* Did the new fragment plug a hole? */
f91e3bd84   Stefan Richter   firewire: net: st...
330
331
  			fi2 = list_entry(fi->fi_link.prev,
  					 struct fwnet_fragment_info, fi_link);
c76acec6d   Jay Fenlason   firewire: add IPv...
332
333
  			if (fi2->offset + fi2->len == fi->offset) {
  				/* glue fragments together */
c76acec6d   Jay Fenlason   firewire: add IPv...
334
  				fi2->len += fi->len + len;
f91e3bd84   Stefan Richter   firewire: net: st...
335
  				list_del(&fi->fi_link);
c76acec6d   Jay Fenlason   firewire: add IPv...
336
  				kfree(fi);
f91e3bd84   Stefan Richter   firewire: net: st...
337

c76acec6d   Jay Fenlason   firewire: add IPv...
338
339
  				return fi2;
  			}
c76acec6d   Jay Fenlason   firewire: add IPv...
340
341
  			fi->offset = offset;
  			fi->len += len;
f91e3bd84   Stefan Richter   firewire: net: st...
342

c76acec6d   Jay Fenlason   firewire: add IPv...
343
344
345
  			return fi;
  		}
  		if (offset > fi->offset + fi->len) {
f91e3bd84   Stefan Richter   firewire: net: st...
346
  			list = &fi->fi_link;
c76acec6d   Jay Fenlason   firewire: add IPv...
347
348
349
  			break;
  		}
  		if (offset + len < fi->offset) {
f91e3bd84   Stefan Richter   firewire: net: st...
350
  			list = fi->fi_link.prev;
c76acec6d   Jay Fenlason   firewire: add IPv...
351
352
353
354
355
356
  			break;
  		}
  	}
  
  	new = kmalloc(sizeof(*new), GFP_ATOMIC);
  	if (!new) {
f91e3bd84   Stefan Richter   firewire: net: st...
357
358
  		fw_error("out of memory
  ");
c76acec6d   Jay Fenlason   firewire: add IPv...
359
360
361
362
363
  		return NULL;
  	}
  
  	new->offset = offset;
  	new->len = len;
f91e3bd84   Stefan Richter   firewire: net: st...
364
  	list_add(&new->fi_link, list);
c76acec6d   Jay Fenlason   firewire: add IPv...
365
366
  	return new;
  }
f91e3bd84   Stefan Richter   firewire: net: st...
367
368
369
370
371
372
  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;
c76acec6d   Jay Fenlason   firewire: add IPv...
373
374
375
376
  
  	new = kmalloc(sizeof(*new), GFP_ATOMIC);
  	if (!new)
  		goto fail;
f91e3bd84   Stefan Richter   firewire: net: st...
377
378
379
380
  
  	INIT_LIST_HEAD(&new->fi_list);
  	fi = fwnet_frag_new(new, frag_off, frag_len);
  	if (fi == NULL)
c76acec6d   Jay Fenlason   firewire: add IPv...
381
  		goto fail_w_new;
f91e3bd84   Stefan Richter   firewire: net: st...
382

c76acec6d   Jay Fenlason   firewire: add IPv...
383
384
  	new->datagram_label = datagram_label;
  	new->datagram_size = dg_size;
f91e3bd84   Stefan Richter   firewire: net: st...
385
386
  	new->skb = dev_alloc_skb(dg_size + net->hard_header_len + 15);
  	if (new->skb == NULL)
c76acec6d   Jay Fenlason   firewire: add IPv...
387
  		goto fail_w_fi;
f91e3bd84   Stefan Richter   firewire: net: st...
388
389
  
  	skb_reserve(new->skb, (net->hard_header_len + 15) & ~15);
c76acec6d   Jay Fenlason   firewire: add IPv...
390
391
  	new->pbuf = skb_put(new->skb, dg_size);
  	memcpy(new->pbuf + frag_off, frag_buf, frag_len);
f91e3bd84   Stefan Richter   firewire: net: st...
392
  	list_add_tail(&new->pd_link, &peer->pd_list);
c76acec6d   Jay Fenlason   firewire: add IPv...
393
394
395
396
397
398
399
  	return new;
  
  fail_w_fi:
  	kfree(fi);
  fail_w_new:
  	kfree(new);
  fail:
f91e3bd84   Stefan Richter   firewire: net: st...
400
401
  	fw_error("out of memory
  ");
c76acec6d   Jay Fenlason   firewire: add IPv...
402
403
  	return NULL;
  }
f91e3bd84   Stefan Richter   firewire: net: st...
404
405
406
407
  static struct fwnet_partial_datagram *fwnet_pd_find(struct fwnet_peer *peer,
  						    u16 datagram_label)
  {
  	struct fwnet_partial_datagram *pd;
c76acec6d   Jay Fenlason   firewire: add IPv...
408

f91e3bd84   Stefan Richter   firewire: net: st...
409
410
  	list_for_each_entry(pd, &peer->pd_list, pd_link)
  		if (pd->datagram_label == datagram_label)
c76acec6d   Jay Fenlason   firewire: add IPv...
411
  			return pd;
f91e3bd84   Stefan Richter   firewire: net: st...
412

c76acec6d   Jay Fenlason   firewire: add IPv...
413
414
  	return NULL;
  }
f91e3bd84   Stefan Richter   firewire: net: st...
415
416
417
  static void fwnet_pd_delete(struct fwnet_partial_datagram *old)
  {
  	struct fwnet_fragment_info *fi, *n;
c76acec6d   Jay Fenlason   firewire: add IPv...
418

f91e3bd84   Stefan Richter   firewire: net: st...
419
  	list_for_each_entry_safe(fi, n, &old->fi_list, fi_link)
c76acec6d   Jay Fenlason   firewire: add IPv...
420
  		kfree(fi);
f91e3bd84   Stefan Richter   firewire: net: st...
421
422
  
  	list_del(&old->pd_link);
c76acec6d   Jay Fenlason   firewire: add IPv...
423
424
425
  	dev_kfree_skb_any(old->skb);
  	kfree(old);
  }
f91e3bd84   Stefan Richter   firewire: net: st...
426
427
428
429
430
  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)
c76acec6d   Jay Fenlason   firewire: add IPv...
431
  		return false;
f91e3bd84   Stefan Richter   firewire: net: st...
432

c76acec6d   Jay Fenlason   firewire: add IPv...
433
434
435
  	memcpy(pd->pbuf + frag_off, frag_buf, frag_len);
  
  	/*
25985edce   Lucas De Marchi   Fix common misspe...
436
  	 * Move list entry to beginning of list so that oldest partial
c76acec6d   Jay Fenlason   firewire: add IPv...
437
438
  	 * datagrams percolate to the end of the list
  	 */
f91e3bd84   Stefan Richter   firewire: net: st...
439
  	list_move_tail(&pd->pd_link, &peer->pd_list);
c76acec6d   Jay Fenlason   firewire: add IPv...
440
441
  	return true;
  }
f91e3bd84   Stefan Richter   firewire: net: st...
442
443
444
  static bool fwnet_pd_is_complete(struct fwnet_partial_datagram *pd)
  {
  	struct fwnet_fragment_info *fi;
c76acec6d   Jay Fenlason   firewire: add IPv...
445

f91e3bd84   Stefan Richter   firewire: net: st...
446
  	fi = list_entry(pd->fi_list.next, struct fwnet_fragment_info, fi_link);
c76acec6d   Jay Fenlason   firewire: add IPv...
447

f91e3bd84   Stefan Richter   firewire: net: st...
448
  	return fi->len == pd->datagram_size;
c76acec6d   Jay Fenlason   firewire: add IPv...
449
  }
5a124d382   Stefan Richter   firewire: net: al...
450
  /* caller must hold dev->lock */
f91e3bd84   Stefan Richter   firewire: net: st...
451
452
453
  static struct fwnet_peer *fwnet_peer_find_by_guid(struct fwnet_device *dev,
  						  u64 guid)
  {
5a124d382   Stefan Richter   firewire: net: al...
454
  	struct fwnet_peer *peer;
c76acec6d   Jay Fenlason   firewire: add IPv...
455

5a124d382   Stefan Richter   firewire: net: al...
456
457
458
  	list_for_each_entry(peer, &dev->peer_list, peer_link)
  		if (peer->guid == guid)
  			return peer;
c76acec6d   Jay Fenlason   firewire: add IPv...
459

5a124d382   Stefan Richter   firewire: net: al...
460
  	return NULL;
c76acec6d   Jay Fenlason   firewire: add IPv...
461
  }
5a124d382   Stefan Richter   firewire: net: al...
462
  /* caller must hold dev->lock */
f91e3bd84   Stefan Richter   firewire: net: st...
463
  static struct fwnet_peer *fwnet_peer_find_by_node_id(struct fwnet_device *dev,
5a124d382   Stefan Richter   firewire: net: al...
464
  						int node_id, int generation)
f91e3bd84   Stefan Richter   firewire: net: st...
465
  {
5a124d382   Stefan Richter   firewire: net: al...
466
  	struct fwnet_peer *peer;
c76acec6d   Jay Fenlason   firewire: add IPv...
467

5a124d382   Stefan Richter   firewire: net: al...
468
469
470
471
  	list_for_each_entry(peer, &dev->peer_list, peer_link)
  		if (peer->node_id    == node_id &&
  		    peer->generation == generation)
  			return peer;
f91e3bd84   Stefan Richter   firewire: net: st...
472

5a124d382   Stefan Richter   firewire: net: al...
473
  	return NULL;
c76acec6d   Jay Fenlason   firewire: add IPv...
474
  }
5a124d382   Stefan Richter   firewire: net: al...
475
476
  /* See IEEE 1394-2008 table 6-4, table 8-8, table 16-18. */
  static unsigned fwnet_max_payload(unsigned max_rec, unsigned speed)
f91e3bd84   Stefan Richter   firewire: net: st...
477
  {
5a124d382   Stefan Richter   firewire: net: al...
478
  	max_rec = min(max_rec, speed + 8);
4ec4a67aa   Stefan Richter   firewire: use cla...
479
  	max_rec = clamp(max_rec, 8U, 11U); /* 512...4096 */
5a124d382   Stefan Richter   firewire: net: al...
480
481
  
  	return (1 << (max_rec + 1)) - RFC2374_FRAG_HDR_SIZE;
c76acec6d   Jay Fenlason   firewire: add IPv...
482
  }
5a124d382   Stefan Richter   firewire: net: al...
483

f91e3bd84   Stefan Richter   firewire: net: st...
484
485
486
487
488
489
  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;
  	static const __be64 broadcast_hw = cpu_to_be64(~0ULL);
c76acec6d   Jay Fenlason   firewire: add IPv...
490
  	int status;
f91e3bd84   Stefan Richter   firewire: net: st...
491
  	__be64 guid;
c76acec6d   Jay Fenlason   firewire: add IPv...
492

f91e3bd84   Stefan Richter   firewire: net: st...
493
  	dev = netdev_priv(net);
c76acec6d   Jay Fenlason   firewire: add IPv...
494
  	/* Write metadata, and then pass to the receive level */
f91e3bd84   Stefan Richter   firewire: net: st...
495
  	skb->dev = net;
c76acec6d   Jay Fenlason   firewire: add IPv...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
  	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, as well as arp
  	 * conversion if needed. ARP conversion is easier in this
  	 * direction, since we are using ethernet as our backend.
  	 */
  	/*
  	 * 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 == ETH_P_ARP) {
f91e3bd84   Stefan Richter   firewire: net: st...
510
  		struct rfc2734_arp *arp1394;
c76acec6d   Jay Fenlason   firewire: add IPv...
511
512
513
  		struct arphdr *arp;
  		unsigned char *arp_ptr;
  		u64 fifo_addr;
f91e3bd84   Stefan Richter   firewire: net: st...
514
  		u64 peer_guid;
5a124d382   Stefan Richter   firewire: net: al...
515
  		unsigned sspd;
c76acec6d   Jay Fenlason   firewire: add IPv...
516
  		u16 max_payload;
f91e3bd84   Stefan Richter   firewire: net: st...
517
  		struct fwnet_peer *peer;
5a124d382   Stefan Richter   firewire: net: al...
518
519
520
521
522
523
524
525
  		unsigned long flags;
  
  		arp1394   = (struct rfc2734_arp *)skb->data;
  		arp       = (struct arphdr *)skb->data;
  		arp_ptr   = (unsigned char *)(arp + 1);
  		peer_guid = get_unaligned_be64(&arp1394->s_uniq_id);
  		fifo_addr = (u64)get_unaligned_be16(&arp1394->fifo_hi) << 32
  				| get_unaligned_be32(&arp1394->fifo_lo);
c76acec6d   Jay Fenlason   firewire: add IPv...
526

c76acec6d   Jay Fenlason   firewire: add IPv...
527
  		sspd = arp1394->sspd;
f91e3bd84   Stefan Richter   firewire: net: st...
528
529
530
531
  		/* Sanity check.  OS X 10.3 PPC reportedly sends 131. */
  		if (sspd > SCODE_3200) {
  			fw_notify("sspd %x out of range
  ", sspd);
5a124d382   Stefan Richter   firewire: net: al...
532
  			sspd = SCODE_3200;
c76acec6d   Jay Fenlason   firewire: add IPv...
533
  		}
5a124d382   Stefan Richter   firewire: net: al...
534
  		max_payload = fwnet_max_payload(arp1394->max_rec, sspd);
c76acec6d   Jay Fenlason   firewire: add IPv...
535

5a124d382   Stefan Richter   firewire: net: al...
536
  		spin_lock_irqsave(&dev->lock, flags);
f91e3bd84   Stefan Richter   firewire: net: st...
537
  		peer = fwnet_peer_find_by_guid(dev, peer_guid);
5a124d382   Stefan Richter   firewire: net: al...
538
539
540
541
542
543
544
  		if (peer) {
  			peer->fifo = fifo_addr;
  
  			if (peer->speed > sspd)
  				peer->speed = sspd;
  			if (peer->max_payload > max_payload)
  				peer->max_payload = max_payload;
74a145049   Maxim Levitsky   firewire: net: in...
545
546
  
  			peer->ip = arp1394->sip;
5a124d382   Stefan Richter   firewire: net: al...
547
548
  		}
  		spin_unlock_irqrestore(&dev->lock, flags);
f91e3bd84   Stefan Richter   firewire: net: st...
549
550
551
552
  		if (!peer) {
  			fw_notify("No peer for ARP packet from %016llx
  ",
  				  (unsigned long long)peer_guid);
1bf145fed   Stefan Richter   firewire: net: fi...
553
  			goto no_peer;
c76acec6d   Jay Fenlason   firewire: add IPv...
554
  		}
f91e3bd84   Stefan Richter   firewire: net: st...
555

c76acec6d   Jay Fenlason   firewire: add IPv...
556
557
558
559
560
561
562
563
564
565
566
567
568
  		/*
  		 * 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;
f91e3bd84   Stefan Richter   firewire: net: st...
569
570
571
572
573
574
  		/* skip over sender unique id */
  		arp_ptr += arp->ar_hln;
  		/* move sender IP addr */
  		put_unaligned(arp1394->sip, (u32 *)arp_ptr);
  		/* skip over sender IP addr */
  		arp_ptr += arp->ar_pln;
c76acec6d   Jay Fenlason   firewire: add IPv...
575
576
577
578
  
  		if (arp->ar_op == htons(ARPOP_REQUEST))
  			memset(arp_ptr, 0, sizeof(u64));
  		else
f91e3bd84   Stefan Richter   firewire: net: st...
579
  			memcpy(arp_ptr, net->dev_addr, sizeof(u64));
c76acec6d   Jay Fenlason   firewire: add IPv...
580
581
582
  	}
  
  	/* Now add the ethernet header. */
f91e3bd84   Stefan Richter   firewire: net: st...
583
584
585
586
587
  	guid = cpu_to_be64(dev->card->guid);
  	if (dev_hard_header(skb, net, ether_type,
  			   is_broadcast ? &broadcast_hw : &guid,
  			   NULL, skb->len) >= 0) {
  		struct fwnet_header *eth;
c76acec6d   Jay Fenlason   firewire: add IPv...
588
589
590
591
592
  		u16 *rawp;
  		__be16 protocol;
  
  		skb_reset_mac_header(skb);
  		skb_pull(skb, sizeof(*eth));
f91e3bd84   Stefan Richter   firewire: net: st...
593
  		eth = (struct fwnet_header *)skb_mac_header(skb);
c76acec6d   Jay Fenlason   firewire: add IPv...
594
  		if (*eth->h_dest & 1) {
f91e3bd84   Stefan Richter   firewire: net: st...
595
596
  			if (memcmp(eth->h_dest, net->broadcast,
  				   net->addr_len) == 0)
c76acec6d   Jay Fenlason   firewire: add IPv...
597
  				skb->pkt_type = PACKET_BROADCAST;
c76acec6d   Jay Fenlason   firewire: add IPv...
598
599
600
601
602
  #if 0
  			else
  				skb->pkt_type = PACKET_MULTICAST;
  #endif
  		} else {
156ce867a   Stefan Richter   firewire: net: re...
603
  			if (memcmp(eth->h_dest, net->dev_addr, net->addr_len))
c76acec6d   Jay Fenlason   firewire: add IPv...
604
  				skb->pkt_type = PACKET_OTHERHOST;
c76acec6d   Jay Fenlason   firewire: add IPv...
605
606
  		}
  		if (ntohs(eth->h_proto) >= 1536) {
c76acec6d   Jay Fenlason   firewire: add IPv...
607
608
609
  			protocol = eth->h_proto;
  		} else {
  			rawp = (u16 *)skb->data;
f91e3bd84   Stefan Richter   firewire: net: st...
610
  			if (*rawp == 0xffff)
c76acec6d   Jay Fenlason   firewire: add IPv...
611
  				protocol = htons(ETH_P_802_3);
f91e3bd84   Stefan Richter   firewire: net: st...
612
  			else
c76acec6d   Jay Fenlason   firewire: add IPv...
613
  				protocol = htons(ETH_P_802_2);
c76acec6d   Jay Fenlason   firewire: add IPv...
614
615
616
617
  		}
  		skb->protocol = protocol;
  	}
  	status = netif_rx(skb);
f91e3bd84   Stefan Richter   firewire: net: st...
618
619
620
  	if (status == NET_RX_DROP) {
  		net->stats.rx_errors++;
  		net->stats.rx_dropped++;
c76acec6d   Jay Fenlason   firewire: add IPv...
621
  	} else {
f91e3bd84   Stefan Richter   firewire: net: st...
622
623
  		net->stats.rx_packets++;
  		net->stats.rx_bytes += skb->len;
c76acec6d   Jay Fenlason   firewire: add IPv...
624
  	}
f91e3bd84   Stefan Richter   firewire: net: st...
625

c76acec6d   Jay Fenlason   firewire: add IPv...
626
  	return 0;
1bf145fed   Stefan Richter   firewire: net: fi...
627
   no_peer:
f91e3bd84   Stefan Richter   firewire: net: st...
628
629
  	net->stats.rx_errors++;
  	net->stats.rx_dropped++;
c76acec6d   Jay Fenlason   firewire: add IPv...
630
  	dev_kfree_skb_any(skb);
f91e3bd84   Stefan Richter   firewire: net: st...
631

1bf145fed   Stefan Richter   firewire: net: fi...
632
  	return -ENOENT;
c76acec6d   Jay Fenlason   firewire: add IPv...
633
  }
f91e3bd84   Stefan Richter   firewire: net: st...
634
  static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
5a124d382   Stefan Richter   firewire: net: al...
635
636
  				 int source_node_id, int generation,
  				 bool is_broadcast)
f91e3bd84   Stefan Richter   firewire: net: st...
637
  {
c76acec6d   Jay Fenlason   firewire: add IPv...
638
  	struct sk_buff *skb;
5a124d382   Stefan Richter   firewire: net: al...
639
  	struct net_device *net = dev->netdev;
f91e3bd84   Stefan Richter   firewire: net: st...
640
  	struct rfc2734_header hdr;
c76acec6d   Jay Fenlason   firewire: add IPv...
641
642
  	unsigned lf;
  	unsigned long flags;
f91e3bd84   Stefan Richter   firewire: net: st...
643
644
  	struct fwnet_peer *peer;
  	struct fwnet_partial_datagram *pd;
c76acec6d   Jay Fenlason   firewire: add IPv...
645
646
647
648
649
  	int fg_off;
  	int dg_size;
  	u16 datagram_label;
  	int retval;
  	u16 ether_type;
f91e3bd84   Stefan Richter   firewire: net: st...
650
651
652
  	hdr.w0 = be32_to_cpu(buf[0]);
  	lf = fwnet_get_hdr_lf(&hdr);
  	if (lf == RFC2374_HDR_UNFRAG) {
c76acec6d   Jay Fenlason   firewire: add IPv...
653
654
655
656
657
  		/*
  		 * 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.
  		 */
f91e3bd84   Stefan Richter   firewire: net: st...
658
  		ether_type = fwnet_get_hdr_ether_type(&hdr);
c76acec6d   Jay Fenlason   firewire: add IPv...
659
  		buf++;
f91e3bd84   Stefan Richter   firewire: net: st...
660
  		len -= RFC2374_UNFRAG_HDR_SIZE;
c76acec6d   Jay Fenlason   firewire: add IPv...
661

f91e3bd84   Stefan Richter   firewire: net: st...
662
  		skb = dev_alloc_skb(len + net->hard_header_len + 15);
c76acec6d   Jay Fenlason   firewire: add IPv...
663
  		if (unlikely(!skb)) {
f91e3bd84   Stefan Richter   firewire: net: st...
664
665
666
  			fw_error("out of memory
  ");
  			net->stats.rx_dropped++;
1bf145fed   Stefan Richter   firewire: net: fi...
667
  			return -ENOMEM;
c76acec6d   Jay Fenlason   firewire: add IPv...
668
  		}
f91e3bd84   Stefan Richter   firewire: net: st...
669
670
671
672
673
  		skb_reserve(skb, (net->hard_header_len + 15) & ~15);
  		memcpy(skb_put(skb, len), buf, len);
  
  		return fwnet_finish_incoming_packet(net, skb, source_node_id,
  						    is_broadcast, ether_type);
c76acec6d   Jay Fenlason   firewire: add IPv...
674
675
676
  	}
  	/* A datagram fragment has been received, now the fun begins. */
  	hdr.w1 = ntohl(buf[1]);
f91e3bd84   Stefan Richter   firewire: net: st...
677
678
679
680
  	buf += 2;
  	len -= RFC2374_FRAG_HDR_SIZE;
  	if (lf == RFC2374_HDR_FIRSTFRAG) {
  		ether_type = fwnet_get_hdr_ether_type(&hdr);
c76acec6d   Jay Fenlason   firewire: add IPv...
681
682
  		fg_off = 0;
  	} else {
f91e3bd84   Stefan Richter   firewire: net: st...
683
684
  		ether_type = 0;
  		fg_off = fwnet_get_hdr_fg_off(&hdr);
c76acec6d   Jay Fenlason   firewire: add IPv...
685
  	}
f91e3bd84   Stefan Richter   firewire: net: st...
686
687
  	datagram_label = fwnet_get_hdr_dgl(&hdr);
  	dg_size = fwnet_get_hdr_dg_size(&hdr); /* ??? + 1 */
f91e3bd84   Stefan Richter   firewire: net: st...
688

5a124d382   Stefan Richter   firewire: net: al...
689
690
691
  	spin_lock_irqsave(&dev->lock, flags);
  
  	peer = fwnet_peer_find_by_node_id(dev, source_node_id, generation);
1bf145fed   Stefan Richter   firewire: net: fi...
692
693
694
695
  	if (!peer) {
  		retval = -ENOENT;
  		goto fail;
  	}
f91e3bd84   Stefan Richter   firewire: net: st...
696
697
  
  	pd = fwnet_pd_find(peer, datagram_label);
c76acec6d   Jay Fenlason   firewire: add IPv...
698
  	if (pd == NULL) {
f91e3bd84   Stefan Richter   firewire: net: st...
699
  		while (peer->pdg_size >= FWNET_MAX_FRAGMENTS) {
c76acec6d   Jay Fenlason   firewire: add IPv...
700
  			/* remove the oldest */
f91e3bd84   Stefan Richter   firewire: net: st...
701
702
703
  			fwnet_pd_delete(list_first_entry(&peer->pd_list,
  				struct fwnet_partial_datagram, pd_link));
  			peer->pdg_size--;
c76acec6d   Jay Fenlason   firewire: add IPv...
704
  		}
f91e3bd84   Stefan Richter   firewire: net: st...
705
706
707
  		pd = fwnet_pd_new(net, peer, datagram_label,
  				  dg_size, buf, fg_off, len);
  		if (pd == NULL) {
c76acec6d   Jay Fenlason   firewire: add IPv...
708
  			retval = -ENOMEM;
1bf145fed   Stefan Richter   firewire: net: fi...
709
  			goto fail;
c76acec6d   Jay Fenlason   firewire: add IPv...
710
  		}
f91e3bd84   Stefan Richter   firewire: net: st...
711
  		peer->pdg_size++;
c76acec6d   Jay Fenlason   firewire: add IPv...
712
  	} else {
f91e3bd84   Stefan Richter   firewire: net: st...
713
714
  		if (fwnet_frag_overlap(pd, fg_off, len) ||
  		    pd->datagram_size != dg_size) {
c76acec6d   Jay Fenlason   firewire: add IPv...
715
716
  			/*
  			 * Differing datagram sizes or overlapping fragments,
f91e3bd84   Stefan Richter   firewire: net: st...
717
  			 * discard old datagram and start a new one.
c76acec6d   Jay Fenlason   firewire: add IPv...
718
  			 */
f91e3bd84   Stefan Richter   firewire: net: st...
719
720
721
722
  			fwnet_pd_delete(pd);
  			pd = fwnet_pd_new(net, peer, datagram_label,
  					  dg_size, buf, fg_off, len);
  			if (pd == NULL) {
f91e3bd84   Stefan Richter   firewire: net: st...
723
  				peer->pdg_size--;
1bf145fed   Stefan Richter   firewire: net: fi...
724
725
  				retval = -ENOMEM;
  				goto fail;
c76acec6d   Jay Fenlason   firewire: add IPv...
726
727
  			}
  		} else {
f91e3bd84   Stefan Richter   firewire: net: st...
728
  			if (!fwnet_pd_update(peer, pd, buf, fg_off, len)) {
c76acec6d   Jay Fenlason   firewire: add IPv...
729
730
731
732
733
  				/*
  				 * Couldn't save off fragment anyway
  				 * so might as well obliterate the
  				 * datagram now.
  				 */
f91e3bd84   Stefan Richter   firewire: net: st...
734
735
  				fwnet_pd_delete(pd);
  				peer->pdg_size--;
1bf145fed   Stefan Richter   firewire: net: fi...
736
737
  				retval = -ENOMEM;
  				goto fail;
c76acec6d   Jay Fenlason   firewire: add IPv...
738
739
740
  			}
  		}
  	} /* new datagram or add to existing one */
f91e3bd84   Stefan Richter   firewire: net: st...
741
  	if (lf == RFC2374_HDR_FIRSTFRAG)
c76acec6d   Jay Fenlason   firewire: add IPv...
742
  		pd->ether_type = ether_type;
f91e3bd84   Stefan Richter   firewire: net: st...
743
744
  
  	if (fwnet_pd_is_complete(pd)) {
c76acec6d   Jay Fenlason   firewire: add IPv...
745
  		ether_type = pd->ether_type;
f91e3bd84   Stefan Richter   firewire: net: st...
746
  		peer->pdg_size--;
c76acec6d   Jay Fenlason   firewire: add IPv...
747
  		skb = skb_get(pd->skb);
f91e3bd84   Stefan Richter   firewire: net: st...
748
  		fwnet_pd_delete(pd);
5a124d382   Stefan Richter   firewire: net: al...
749
  		spin_unlock_irqrestore(&dev->lock, flags);
f91e3bd84   Stefan Richter   firewire: net: st...
750
751
752
  
  		return fwnet_finish_incoming_packet(net, skb, source_node_id,
  						    false, ether_type);
c76acec6d   Jay Fenlason   firewire: add IPv...
753
754
755
756
757
  	}
  	/*
  	 * Datagram is not complete, we're done for the
  	 * moment.
  	 */
b2268830f   Stefan Richter   firewire: net: th...
758
  	retval = 0;
1bf145fed   Stefan Richter   firewire: net: fi...
759
   fail:
5a124d382   Stefan Richter   firewire: net: al...
760
  	spin_unlock_irqrestore(&dev->lock, flags);
f91e3bd84   Stefan Richter   firewire: net: st...
761

1bf145fed   Stefan Richter   firewire: net: fi...
762
  	return retval;
c76acec6d   Jay Fenlason   firewire: add IPv...
763
  }
f91e3bd84   Stefan Richter   firewire: net: st...
764
765
  static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r,
  		int tcode, int destination, int source, int generation,
33e553fe2   Stefan Richter   firewire: remove ...
766
767
  		unsigned long long offset, void *payload, size_t length,
  		void *callback_data)
f91e3bd84   Stefan Richter   firewire: net: st...
768
  {
00635b8ee   Stefan Richter   firewire: net: be...
769
770
  	struct fwnet_device *dev = callback_data;
  	int rcode;
c76acec6d   Jay Fenlason   firewire: add IPv...
771

00635b8ee   Stefan Richter   firewire: net: be...
772
773
  	if (destination == IEEE1394_ALL_NODES) {
  		kfree(r);
f91e3bd84   Stefan Richter   firewire: net: st...
774

c76acec6d   Jay Fenlason   firewire: add IPv...
775
776
  		return;
  	}
f91e3bd84   Stefan Richter   firewire: net: st...
777

00635b8ee   Stefan Richter   firewire: net: be...
778
779
780
781
782
783
  	if (offset != dev->handler.offset)
  		rcode = RCODE_ADDRESS_ERROR;
  	else if (tcode != TCODE_WRITE_BLOCK_REQUEST)
  		rcode = RCODE_TYPE_ERROR;
  	else if (fwnet_incoming_packet(dev, payload, length,
  				       source, generation, false) != 0) {
f91e3bd84   Stefan Richter   firewire: net: st...
784
785
  		fw_error("Incoming packet failure
  ");
00635b8ee   Stefan Richter   firewire: net: be...
786
787
788
  		rcode = RCODE_CONFLICT_ERROR;
  	} else
  		rcode = RCODE_COMPLETE;
f91e3bd84   Stefan Richter   firewire: net: st...
789

00635b8ee   Stefan Richter   firewire: net: be...
790
  	fw_send_response(card, r, rcode);
c76acec6d   Jay Fenlason   firewire: add IPv...
791
  }
f91e3bd84   Stefan Richter   firewire: net: st...
792
793
794
795
  static void fwnet_receive_broadcast(struct fw_iso_context *context,
  		u32 cycle, size_t header_length, void *header, void *data)
  {
  	struct fwnet_device *dev;
c76acec6d   Jay Fenlason   firewire: add IPv...
796
797
  	struct fw_iso_packet packet;
  	struct fw_card *card;
f91e3bd84   Stefan Richter   firewire: net: st...
798
799
  	__be16 *hdr_ptr;
  	__be32 *buf_ptr;
c76acec6d   Jay Fenlason   firewire: add IPv...
800
801
802
803
804
805
806
  	int retval;
  	u32 length;
  	u16 source_node_id;
  	u32 specifier_id;
  	u32 ver;
  	unsigned long offset;
  	unsigned long flags;
f91e3bd84   Stefan Richter   firewire: net: st...
807
808
  	dev = data;
  	card = dev->card;
c76acec6d   Jay Fenlason   firewire: add IPv...
809
  	hdr_ptr = header;
f91e3bd84   Stefan Richter   firewire: net: st...
810
811
812
813
814
815
816
817
818
819
  	length = be16_to_cpup(hdr_ptr);
  
  	spin_lock_irqsave(&dev->lock, flags);
  
  	offset = dev->rcv_buffer_size * dev->broadcast_rcv_next_ptr;
  	buf_ptr = dev->broadcast_rcv_buffer_ptrs[dev->broadcast_rcv_next_ptr++];
  	if (dev->broadcast_rcv_next_ptr == dev->num_broadcast_rcv_ptrs)
  		dev->broadcast_rcv_next_ptr = 0;
  
  	spin_unlock_irqrestore(&dev->lock, flags);
c76acec6d   Jay Fenlason   firewire: add IPv...
820
821
822
  
  	specifier_id =    (be32_to_cpu(buf_ptr[0]) & 0xffff) << 8
  			| (be32_to_cpu(buf_ptr[1]) & 0xff000000) >> 24;
f91e3bd84   Stefan Richter   firewire: net: st...
823
  	ver = be32_to_cpu(buf_ptr[1]) & 0xffffff;
c76acec6d   Jay Fenlason   firewire: add IPv...
824
  	source_node_id = be32_to_cpu(buf_ptr[0]) >> 16;
f91e3bd84   Stefan Richter   firewire: net: st...
825
826
  
  	if (specifier_id == IANA_SPECIFIER_ID && ver == RFC2734_SW_VERSION) {
c76acec6d   Jay Fenlason   firewire: add IPv...
827
  		buf_ptr += 2;
f91e3bd84   Stefan Richter   firewire: net: st...
828
829
  		length -= IEEE1394_GASP_HDR_SIZE;
  		fwnet_incoming_packet(dev, buf_ptr, length,
5a124d382   Stefan Richter   firewire: net: al...
830
  				      source_node_id, -1, true);
f91e3bd84   Stefan Richter   firewire: net: st...
831
832
833
  	}
  
  	packet.payload_length = dev->rcv_buffer_size;
c76acec6d   Jay Fenlason   firewire: add IPv...
834
835
836
837
  	packet.interrupt = 1;
  	packet.skip = 0;
  	packet.tag = 3;
  	packet.sy = 0;
f91e3bd84   Stefan Richter   firewire: net: st...
838
839
840
  	packet.header_length = IEEE1394_GASP_HDR_SIZE;
  
  	spin_lock_irqsave(&dev->lock, flags);
c76acec6d   Jay Fenlason   firewire: add IPv...
841

f91e3bd84   Stefan Richter   firewire: net: st...
842
843
844
845
  	retval = fw_iso_context_queue(dev->broadcast_rcv_context, &packet,
  				      &dev->broadcast_rcv_buffer, offset);
  
  	spin_unlock_irqrestore(&dev->lock, flags);
13882a82e   Clemens Ladisch   firewire: optimiz...
846
847
848
  	if (retval >= 0)
  		fw_iso_context_queue_flush(dev->broadcast_rcv_context);
  	else
f91e3bd84   Stefan Richter   firewire: net: st...
849
850
  		fw_error("requeue failed
  ");
c76acec6d   Jay Fenlason   firewire: add IPv...
851
  }
f91e3bd84   Stefan Richter   firewire: net: st...
852
  static struct kmem_cache *fwnet_packet_task_cache;
110f82d7a   Stefan Richter   firewire: net: fi...
853
854
855
856
857
  static void fwnet_free_ptask(struct fwnet_packet_task *ptask)
  {
  	dev_kfree_skb_any(ptask->skb);
  	kmem_cache_free(fwnet_packet_task_cache, ptask);
  }
b2268830f   Stefan Richter   firewire: net: th...
858
859
860
861
862
863
  /* Caller must hold dev->lock. */
  static void dec_queued_datagrams(struct fwnet_device *dev)
  {
  	if (--dev->queued_datagrams == FWNET_MIN_QUEUED_DATAGRAMS)
  		netif_wake_queue(dev->netdev);
  }
f91e3bd84   Stefan Richter   firewire: net: st...
864
865
866
867
  static int fwnet_send_packet(struct fwnet_packet_task *ptask);
  
  static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
  {
110f82d7a   Stefan Richter   firewire: net: fi...
868
  	struct fwnet_device *dev = ptask->dev;
902bca00d   Stefan Richter   firewire: net: co...
869
  	struct sk_buff *skb = ptask->skb;
c76acec6d   Jay Fenlason   firewire: add IPv...
870
  	unsigned long flags;
110f82d7a   Stefan Richter   firewire: net: fi...
871
  	bool free;
f91e3bd84   Stefan Richter   firewire: net: st...
872
873
  
  	spin_lock_irqsave(&dev->lock, flags);
f91e3bd84   Stefan Richter   firewire: net: st...
874

110f82d7a   Stefan Richter   firewire: net: fi...
875
876
877
  	ptask->outstanding_pkts--;
  
  	/* Check whether we or the networking TX soft-IRQ is last user. */
48553011c   Stefan Richter   firewire: net: re...
878
  	free = (ptask->outstanding_pkts == 0 && ptask->enqueued);
7ee11fa8d   Stefan Richter   firewire: net: fi...
879
  	if (free)
b2268830f   Stefan Richter   firewire: net: th...
880
  		dec_queued_datagrams(dev);
110f82d7a   Stefan Richter   firewire: net: fi...
881

902bca00d   Stefan Richter   firewire: net: co...
882
  	if (ptask->outstanding_pkts == 0) {
902bca00d   Stefan Richter   firewire: net: co...
883
884
885
  		dev->netdev->stats.tx_packets++;
  		dev->netdev->stats.tx_bytes += skb->len;
  	}
110f82d7a   Stefan Richter   firewire: net: fi...
886
887
  
  	spin_unlock_irqrestore(&dev->lock, flags);
f91e3bd84   Stefan Richter   firewire: net: st...
888
889
  
  	if (ptask->outstanding_pkts > 0) {
c76acec6d   Jay Fenlason   firewire: add IPv...
890
891
892
893
  		u16 dg_size;
  		u16 fg_off;
  		u16 datagram_label;
  		u16 lf;
c76acec6d   Jay Fenlason   firewire: add IPv...
894
895
  
  		/* Update the ptask to point to the next fragment and send it */
f91e3bd84   Stefan Richter   firewire: net: st...
896
  		lf = fwnet_get_hdr_lf(&ptask->hdr);
c76acec6d   Jay Fenlason   firewire: add IPv...
897
  		switch (lf) {
f91e3bd84   Stefan Richter   firewire: net: st...
898
899
  		case RFC2374_HDR_LASTFRAG:
  		case RFC2374_HDR_UNFRAG:
c76acec6d   Jay Fenlason   firewire: add IPv...
900
  		default:
f91e3bd84   Stefan Richter   firewire: net: st...
901
902
903
904
  			fw_error("Outstanding packet %x lf %x, header %x,%x
  ",
  				 ptask->outstanding_pkts, lf, ptask->hdr.w0,
  				 ptask->hdr.w1);
c76acec6d   Jay Fenlason   firewire: add IPv...
905
  			BUG();
f91e3bd84   Stefan Richter   firewire: net: st...
906
  		case RFC2374_HDR_FIRSTFRAG:
c76acec6d   Jay Fenlason   firewire: add IPv...
907
  			/* Set frag type here for future interior fragments */
f91e3bd84   Stefan Richter   firewire: net: st...
908
909
910
  			dg_size = fwnet_get_hdr_dg_size(&ptask->hdr);
  			fg_off = ptask->max_payload - RFC2374_FRAG_HDR_SIZE;
  			datagram_label = fwnet_get_hdr_dgl(&ptask->hdr);
c76acec6d   Jay Fenlason   firewire: add IPv...
911
  			break;
f91e3bd84   Stefan Richter   firewire: net: st...
912
913
914
915
916
  		case RFC2374_HDR_INTFRAG:
  			dg_size = fwnet_get_hdr_dg_size(&ptask->hdr);
  			fg_off = fwnet_get_hdr_fg_off(&ptask->hdr)
  				  + ptask->max_payload - RFC2374_FRAG_HDR_SIZE;
  			datagram_label = fwnet_get_hdr_dgl(&ptask->hdr);
c76acec6d   Jay Fenlason   firewire: add IPv...
917
918
  			break;
  		}
902bca00d   Stefan Richter   firewire: net: co...
919

f91e3bd84   Stefan Richter   firewire: net: st...
920
921
922
923
  		skb_pull(skb, ptask->max_payload);
  		if (ptask->outstanding_pkts > 1) {
  			fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG,
  					  dg_size, fg_off, datagram_label);
c76acec6d   Jay Fenlason   firewire: add IPv...
924
  		} else {
f91e3bd84   Stefan Richter   firewire: net: st...
925
926
927
  			fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_LASTFRAG,
  					  dg_size, fg_off, datagram_label);
  			ptask->max_payload = skb->len + RFC2374_FRAG_HDR_SIZE;
c76acec6d   Jay Fenlason   firewire: add IPv...
928
  		}
f91e3bd84   Stefan Richter   firewire: net: st...
929
  		fwnet_send_packet(ptask);
c76acec6d   Jay Fenlason   firewire: add IPv...
930
  	}
110f82d7a   Stefan Richter   firewire: net: fi...
931
932
933
  
  	if (free)
  		fwnet_free_ptask(ptask);
c76acec6d   Jay Fenlason   firewire: add IPv...
934
  }
7ee11fa8d   Stefan Richter   firewire: net: fi...
935
936
937
938
939
940
941
942
943
944
945
946
  static void fwnet_transmit_packet_failed(struct fwnet_packet_task *ptask)
  {
  	struct fwnet_device *dev = ptask->dev;
  	unsigned long flags;
  	bool free;
  
  	spin_lock_irqsave(&dev->lock, flags);
  
  	/* One fragment failed; don't try to send remaining fragments. */
  	ptask->outstanding_pkts = 0;
  
  	/* Check whether we or the networking TX soft-IRQ is last user. */
48553011c   Stefan Richter   firewire: net: re...
947
  	free = ptask->enqueued;
7ee11fa8d   Stefan Richter   firewire: net: fi...
948
  	if (free)
b2268830f   Stefan Richter   firewire: net: th...
949
  		dec_queued_datagrams(dev);
7ee11fa8d   Stefan Richter   firewire: net: fi...
950
951
952
953
954
955
956
957
958
  
  	dev->netdev->stats.tx_dropped++;
  	dev->netdev->stats.tx_errors++;
  
  	spin_unlock_irqrestore(&dev->lock, flags);
  
  	if (free)
  		fwnet_free_ptask(ptask);
  }
f91e3bd84   Stefan Richter   firewire: net: st...
959
960
961
  static void fwnet_write_complete(struct fw_card *card, int rcode,
  				 void *payload, size_t length, void *data)
  {
c4d6fd40d   Maxim Levitsky   firewire: net: ra...
962
963
964
  	struct fwnet_packet_task *ptask = data;
  	static unsigned long j;
  	static int last_rcode, errors_skipped;
c76acec6d   Jay Fenlason   firewire: add IPv...
965

7ee11fa8d   Stefan Richter   firewire: net: fi...
966
  	if (rcode == RCODE_COMPLETE) {
f91e3bd84   Stefan Richter   firewire: net: st...
967
  		fwnet_transmit_packet_done(ptask);
7ee11fa8d   Stefan Richter   firewire: net: fi...
968
  	} else {
7ee11fa8d   Stefan Richter   firewire: net: fi...
969
  		fwnet_transmit_packet_failed(ptask);
c4d6fd40d   Maxim Levitsky   firewire: net: ra...
970
971
972
973
974
975
976
977
978
979
  
  		if (printk_timed_ratelimit(&j,  1000) || rcode != last_rcode) {
  			fw_error("fwnet_write_complete: "
  				"failed: %x (skipped %d)
  ", rcode, errors_skipped);
  
  			errors_skipped = 0;
  			last_rcode = rcode;
  		} else
  			errors_skipped++;
7ee11fa8d   Stefan Richter   firewire: net: fi...
980
  	}
c76acec6d   Jay Fenlason   firewire: add IPv...
981
  }
f91e3bd84   Stefan Richter   firewire: net: st...
982
983
984
  static int fwnet_send_packet(struct fwnet_packet_task *ptask)
  {
  	struct fwnet_device *dev;
c76acec6d   Jay Fenlason   firewire: add IPv...
985
  	unsigned tx_len;
f91e3bd84   Stefan Richter   firewire: net: st...
986
  	struct rfc2734_header *bufhdr;
c76acec6d   Jay Fenlason   firewire: add IPv...
987
  	unsigned long flags;
110f82d7a   Stefan Richter   firewire: net: fi...
988
  	bool free;
c76acec6d   Jay Fenlason   firewire: add IPv...
989

f91e3bd84   Stefan Richter   firewire: net: st...
990
  	dev = ptask->dev;
c76acec6d   Jay Fenlason   firewire: add IPv...
991
  	tx_len = ptask->max_payload;
f91e3bd84   Stefan Richter   firewire: net: st...
992
993
994
995
996
  	switch (fwnet_get_hdr_lf(&ptask->hdr)) {
  	case RFC2374_HDR_UNFRAG:
  		bufhdr = (struct rfc2734_header *)
  				skb_push(ptask->skb, RFC2374_UNFRAG_HDR_SIZE);
  		put_unaligned_be32(ptask->hdr.w0, &bufhdr->w0);
c76acec6d   Jay Fenlason   firewire: add IPv...
997
  		break;
f91e3bd84   Stefan Richter   firewire: net: st...
998
999
1000
1001
1002
1003
1004
  	case RFC2374_HDR_FIRSTFRAG:
  	case RFC2374_HDR_INTFRAG:
  	case RFC2374_HDR_LASTFRAG:
  		bufhdr = (struct rfc2734_header *)
  				skb_push(ptask->skb, RFC2374_FRAG_HDR_SIZE);
  		put_unaligned_be32(ptask->hdr.w0, &bufhdr->w0);
  		put_unaligned_be32(ptask->hdr.w1, &bufhdr->w1);
c76acec6d   Jay Fenlason   firewire: add IPv...
1005
1006
1007
1008
1009
  		break;
  
  	default:
  		BUG();
  	}
f91e3bd84   Stefan Richter   firewire: net: st...
1010
1011
  	if (ptask->dest_node == IEEE1394_ALL_NODES) {
  		u8 *p;
c76acec6d   Jay Fenlason   firewire: add IPv...
1012
  		int generation;
f91e3bd84   Stefan Richter   firewire: net: st...
1013
  		int node_id;
c76acec6d   Jay Fenlason   firewire: add IPv...
1014
1015
  
  		/* ptask->generation may not have been set yet */
f91e3bd84   Stefan Richter   firewire: net: st...
1016
  		generation = dev->card->generation;
c76acec6d   Jay Fenlason   firewire: add IPv...
1017
  		smp_rmb();
f91e3bd84   Stefan Richter   firewire: net: st...
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
  		node_id = dev->card->node_id;
  
  		p = skb_push(ptask->skb, 8);
  		put_unaligned_be32(node_id << 16 | IANA_SPECIFIER_ID >> 8, p);
  		put_unaligned_be32((IANA_SPECIFIER_ID & 0xff) << 24
  						| RFC2734_SW_VERSION, &p[4]);
  
  		/* We should not transmit if broadcast_channel.valid == 0. */
  		fw_send_request(dev->card, &ptask->transaction,
  				TCODE_STREAM_DATA,
  				fw_stream_packet_destination_id(3,
  						IEEE1394_BROADCAST_CHANNEL, 0),
  				generation, SCODE_100, 0ULL, ptask->skb->data,
  				tx_len + 8, fwnet_write_complete, ptask);
f91e3bd84   Stefan Richter   firewire: net: st...
1032
  		spin_lock_irqsave(&dev->lock, flags);
110f82d7a   Stefan Richter   firewire: net: fi...
1033
1034
  
  		/* If the AT tasklet already ran, we may be last user. */
48553011c   Stefan Richter   firewire: net: re...
1035
  		free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
110f82d7a   Stefan Richter   firewire: net: fi...
1036
  		if (!free)
48553011c   Stefan Richter   firewire: net: re...
1037
1038
  			ptask->enqueued = true;
  		else
b2268830f   Stefan Richter   firewire: net: th...
1039
  			dec_queued_datagrams(dev);
110f82d7a   Stefan Richter   firewire: net: fi...
1040

f91e3bd84   Stefan Richter   firewire: net: st...
1041
  		spin_unlock_irqrestore(&dev->lock, flags);
110f82d7a   Stefan Richter   firewire: net: fi...
1042
  		goto out;
c76acec6d   Jay Fenlason   firewire: add IPv...
1043
  	}
f91e3bd84   Stefan Richter   firewire: net: st...
1044
1045
1046
1047
1048
  
  	fw_send_request(dev->card, &ptask->transaction,
  			TCODE_WRITE_BLOCK_REQUEST, ptask->dest_node,
  			ptask->generation, ptask->speed, ptask->fifo_addr,
  			ptask->skb->data, tx_len, fwnet_write_complete, ptask);
f91e3bd84   Stefan Richter   firewire: net: st...
1049
  	spin_lock_irqsave(&dev->lock, flags);
110f82d7a   Stefan Richter   firewire: net: fi...
1050
1051
  
  	/* If the AT tasklet already ran, we may be last user. */
48553011c   Stefan Richter   firewire: net: re...
1052
  	free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
110f82d7a   Stefan Richter   firewire: net: fi...
1053
  	if (!free)
48553011c   Stefan Richter   firewire: net: re...
1054
1055
  		ptask->enqueued = true;
  	else
b2268830f   Stefan Richter   firewire: net: th...
1056
  		dec_queued_datagrams(dev);
110f82d7a   Stefan Richter   firewire: net: fi...
1057

f91e3bd84   Stefan Richter   firewire: net: st...
1058
  	spin_unlock_irqrestore(&dev->lock, flags);
5a124d382   Stefan Richter   firewire: net: al...
1059
  	dev->netdev->trans_start = jiffies;
110f82d7a   Stefan Richter   firewire: net: fi...
1060
1061
1062
   out:
  	if (free)
  		fwnet_free_ptask(ptask);
f91e3bd84   Stefan Richter   firewire: net: st...
1063

c76acec6d   Jay Fenlason   firewire: add IPv...
1064
1065
  	return 0;
  }
f91e3bd84   Stefan Richter   firewire: net: st...
1066
1067
  static int fwnet_broadcast_start(struct fwnet_device *dev)
  {
c76acec6d   Jay Fenlason   firewire: add IPv...
1068
1069
1070
1071
1072
1073
1074
  	struct fw_iso_context *context;
  	int retval;
  	unsigned num_packets;
  	unsigned max_receive;
  	struct fw_iso_packet packet;
  	unsigned long offset;
  	unsigned u;
c76acec6d   Jay Fenlason   firewire: add IPv...
1075

f91e3bd84   Stefan Richter   firewire: net: st...
1076
  	if (dev->local_fifo == FWNET_NO_FIFO_ADDR) {
f91e3bd84   Stefan Richter   firewire: net: st...
1077
1078
1079
  		dev->handler.length = 4096;
  		dev->handler.address_callback = fwnet_receive_packet;
  		dev->handler.callback_data = dev;
a74477db9   Stephan Gatzka   firewire: net: Us...
1080
1081
  		retval = fw_core_add_address_handler(&dev->handler,
  					&fw_high_memory_region);
f91e3bd84   Stefan Richter   firewire: net: st...
1082
  		if (retval < 0)
c76acec6d   Jay Fenlason   firewire: add IPv...
1083
  			goto failed_initial;
f91e3bd84   Stefan Richter   firewire: net: st...
1084
1085
  
  		dev->local_fifo = dev->handler.offset;
c76acec6d   Jay Fenlason   firewire: add IPv...
1086
  	}
f91e3bd84   Stefan Richter   firewire: net: st...
1087
1088
1089
1090
  	max_receive = 1U << (dev->card->max_receive + 1);
  	num_packets = (FWNET_ISO_PAGE_COUNT * PAGE_SIZE) / max_receive;
  
  	if (!dev->broadcast_rcv_context) {
c76acec6d   Jay Fenlason   firewire: add IPv...
1091
  		void **ptrptr;
f91e3bd84   Stefan Richter   firewire: net: st...
1092
1093
1094
  		context = fw_iso_context_create(dev->card,
  		    FW_ISO_CONTEXT_RECEIVE, IEEE1394_BROADCAST_CHANNEL,
  		    dev->card->link_speed, 8, fwnet_receive_broadcast, dev);
c76acec6d   Jay Fenlason   firewire: add IPv...
1095
1096
1097
1098
  		if (IS_ERR(context)) {
  			retval = PTR_ERR(context);
  			goto failed_context_create;
  		}
f91e3bd84   Stefan Richter   firewire: net: st...
1099
1100
1101
1102
  
  		retval = fw_iso_buffer_init(&dev->broadcast_rcv_buffer,
  		    dev->card, FWNET_ISO_PAGE_COUNT, DMA_FROM_DEVICE);
  		if (retval < 0)
c76acec6d   Jay Fenlason   firewire: add IPv...
1103
  			goto failed_buffer_init;
f91e3bd84   Stefan Richter   firewire: net: st...
1104
1105
1106
  
  		ptrptr = kmalloc(sizeof(void *) * num_packets, GFP_KERNEL);
  		if (!ptrptr) {
c76acec6d   Jay Fenlason   firewire: add IPv...
1107
1108
1109
  			retval = -ENOMEM;
  			goto failed_ptrs_alloc;
  		}
f91e3bd84   Stefan Richter   firewire: net: st...
1110
1111
1112
  
  		dev->broadcast_rcv_buffer_ptrs = ptrptr;
  		for (u = 0; u < FWNET_ISO_PAGE_COUNT; u++) {
c76acec6d   Jay Fenlason   firewire: add IPv...
1113
1114
  			void *ptr;
  			unsigned v;
f91e3bd84   Stefan Richter   firewire: net: st...
1115
1116
1117
1118
  			ptr = kmap(dev->broadcast_rcv_buffer.pages[u]);
  			for (v = 0; v < num_packets / FWNET_ISO_PAGE_COUNT; v++)
  				*ptrptr++ = (void *)
  						((char *)ptr + v * max_receive);
c76acec6d   Jay Fenlason   firewire: add IPv...
1119
  		}
f91e3bd84   Stefan Richter   firewire: net: st...
1120
1121
1122
1123
  		dev->broadcast_rcv_context = context;
  	} else {
  		context = dev->broadcast_rcv_context;
  	}
c76acec6d   Jay Fenlason   firewire: add IPv...
1124
1125
1126
1127
1128
1129
  
  	packet.payload_length = max_receive;
  	packet.interrupt = 1;
  	packet.skip = 0;
  	packet.tag = 3;
  	packet.sy = 0;
f91e3bd84   Stefan Richter   firewire: net: st...
1130
  	packet.header_length = IEEE1394_GASP_HDR_SIZE;
c76acec6d   Jay Fenlason   firewire: add IPv...
1131
  	offset = 0;
f91e3bd84   Stefan Richter   firewire: net: st...
1132
1133
1134
1135
1136
  
  	for (u = 0; u < num_packets; u++) {
  		retval = fw_iso_context_queue(context, &packet,
  				&dev->broadcast_rcv_buffer, offset);
  		if (retval < 0)
c76acec6d   Jay Fenlason   firewire: add IPv...
1137
  			goto failed_rcv_queue;
f91e3bd84   Stefan Richter   firewire: net: st...
1138

c76acec6d   Jay Fenlason   firewire: add IPv...
1139
1140
  		offset += max_receive;
  	}
f91e3bd84   Stefan Richter   firewire: net: st...
1141
1142
1143
1144
1145
1146
  	dev->num_broadcast_rcv_ptrs = num_packets;
  	dev->rcv_buffer_size = max_receive;
  	dev->broadcast_rcv_next_ptr = 0U;
  	retval = fw_iso_context_start(context, -1, 0,
  			FW_ISO_CONTEXT_MATCH_ALL_TAGS); /* ??? sync */
  	if (retval < 0)
c76acec6d   Jay Fenlason   firewire: add IPv...
1147
  		goto failed_rcv_queue;
f91e3bd84   Stefan Richter   firewire: net: st...
1148
1149
1150
1151
1152
  
  	/* FIXME: adjust it according to the min. speed of all known peers? */
  	dev->broadcast_xmt_max_payload = IEEE1394_MAX_PAYLOAD_S100
  			- IEEE1394_GASP_HDR_SIZE - RFC2374_UNFRAG_HDR_SIZE;
  	dev->broadcast_state = FWNET_BROADCAST_RUNNING;
c76acec6d   Jay Fenlason   firewire: add IPv...
1153
1154
1155
  	return 0;
  
   failed_rcv_queue:
f91e3bd84   Stefan Richter   firewire: net: st...
1156
1157
  	kfree(dev->broadcast_rcv_buffer_ptrs);
  	dev->broadcast_rcv_buffer_ptrs = NULL;
c76acec6d   Jay Fenlason   firewire: add IPv...
1158
   failed_ptrs_alloc:
f91e3bd84   Stefan Richter   firewire: net: st...
1159
  	fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer, dev->card);
c76acec6d   Jay Fenlason   firewire: add IPv...
1160
   failed_buffer_init:
f91e3bd84   Stefan Richter   firewire: net: st...
1161
1162
  	fw_iso_context_destroy(context);
  	dev->broadcast_rcv_context = NULL;
c76acec6d   Jay Fenlason   firewire: add IPv...
1163
   failed_context_create:
f91e3bd84   Stefan Richter   firewire: net: st...
1164
  	fw_core_remove_address_handler(&dev->handler);
c76acec6d   Jay Fenlason   firewire: add IPv...
1165
   failed_initial:
f91e3bd84   Stefan Richter   firewire: net: st...
1166
  	dev->local_fifo = FWNET_NO_FIFO_ADDR;
c76acec6d   Jay Fenlason   firewire: add IPv...
1167
1168
  	return retval;
  }
c16714704   Stefan Richter   firewire: net: se...
1169
1170
1171
1172
1173
1174
1175
  static void set_carrier_state(struct fwnet_device *dev)
  {
  	if (dev->peer_count > 1)
  		netif_carrier_on(dev->netdev);
  	else
  		netif_carrier_off(dev->netdev);
  }
f91e3bd84   Stefan Richter   firewire: net: st...
1176
1177
1178
1179
  /* ifup */
  static int fwnet_open(struct net_device *net)
  {
  	struct fwnet_device *dev = netdev_priv(net);
c76acec6d   Jay Fenlason   firewire: add IPv...
1180
  	int ret;
f91e3bd84   Stefan Richter   firewire: net: st...
1181
1182
  	if (dev->broadcast_state == FWNET_BROADCAST_ERROR) {
  		ret = fwnet_broadcast_start(dev);
c76acec6d   Jay Fenlason   firewire: add IPv...
1183
1184
1185
  		if (ret)
  			return ret;
  	}
f91e3bd84   Stefan Richter   firewire: net: st...
1186
  	netif_start_queue(net);
c16714704   Stefan Richter   firewire: net: se...
1187
1188
1189
  	spin_lock_irq(&dev->lock);
  	set_carrier_state(dev);
  	spin_unlock_irq(&dev->lock);
c76acec6d   Jay Fenlason   firewire: add IPv...
1190
1191
  	return 0;
  }
f91e3bd84   Stefan Richter   firewire: net: st...
1192
1193
  /* ifdown */
  static int fwnet_stop(struct net_device *net)
c76acec6d   Jay Fenlason   firewire: add IPv...
1194
  {
f91e3bd84   Stefan Richter   firewire: net: st...
1195
1196
1197
  	netif_stop_queue(net);
  
  	/* Deallocate iso context for use by other applications? */
c76acec6d   Jay Fenlason   firewire: add IPv...
1198

c76acec6d   Jay Fenlason   firewire: add IPv...
1199
1200
  	return 0;
  }
424efe9ca   Stephen Hemminger   netdev: convert p...
1201
  static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
c76acec6d   Jay Fenlason   firewire: add IPv...
1202
  {
f91e3bd84   Stefan Richter   firewire: net: st...
1203
1204
  	struct fwnet_header hdr_buf;
  	struct fwnet_device *dev = netdev_priv(net);
c76acec6d   Jay Fenlason   firewire: add IPv...
1205
1206
  	__be16 proto;
  	u16 dest_node;
c76acec6d   Jay Fenlason   firewire: add IPv...
1207
1208
1209
  	unsigned max_payload;
  	u16 dg_size;
  	u16 *datagram_label_ptr;
f91e3bd84   Stefan Richter   firewire: net: st...
1210
  	struct fwnet_packet_task *ptask;
5a124d382   Stefan Richter   firewire: net: al...
1211
1212
  	struct fwnet_peer *peer;
  	unsigned long flags;
c76acec6d   Jay Fenlason   firewire: add IPv...
1213

b2268830f   Stefan Richter   firewire: net: th...
1214
1215
1216
1217
1218
1219
1220
1221
  	spin_lock_irqsave(&dev->lock, flags);
  
  	/* Can this happen? */
  	if (netif_queue_stopped(dev->netdev)) {
  		spin_unlock_irqrestore(&dev->lock, flags);
  
  		return NETDEV_TX_BUSY;
  	}
f91e3bd84   Stefan Richter   firewire: net: st...
1222
  	ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC);
c76acec6d   Jay Fenlason   firewire: add IPv...
1223
1224
1225
1226
1227
1228
1229
1230
  	if (ptask == NULL)
  		goto fail;
  
  	skb = skb_share_check(skb, GFP_ATOMIC);
  	if (!skb)
  		goto fail;
  
  	/*
f91e3bd84   Stefan Richter   firewire: net: st...
1231
  	 * Make a copy of the driver-specific header.
c76acec6d   Jay Fenlason   firewire: add IPv...
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
  	 * We might need to rebuild the header on tx failure.
  	 */
  	memcpy(&hdr_buf, skb->data, sizeof(hdr_buf));
  	skb_pull(skb, sizeof(hdr_buf));
  
  	proto = hdr_buf.h_proto;
  	dg_size = skb->len;
  
  	/*
  	 * Set the transmission type for the packet.  ARP packets and IP
  	 * broadcast packets are sent via GASP.
  	 */
f91e3bd84   Stefan Richter   firewire: net: st...
1244
  	if (memcmp(hdr_buf.h_dest, net->broadcast, FWNET_ALEN) == 0
c76acec6d   Jay Fenlason   firewire: add IPv...
1245
  	    || proto == htons(ETH_P_ARP)
f91e3bd84   Stefan Richter   firewire: net: st...
1246
1247
  	    || (proto == htons(ETH_P_IP)
  		&& IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) {
5a124d382   Stefan Richter   firewire: net: al...
1248
  		max_payload        = dev->broadcast_xmt_max_payload;
f91e3bd84   Stefan Richter   firewire: net: st...
1249
  		datagram_label_ptr = &dev->broadcast_xmt_datagramlabel;
5a124d382   Stefan Richter   firewire: net: al...
1250
1251
1252
1253
  		ptask->fifo_addr   = FWNET_NO_FIFO_ADDR;
  		ptask->generation  = 0;
  		ptask->dest_node   = IEEE1394_ALL_NODES;
  		ptask->speed       = SCODE_100;
c76acec6d   Jay Fenlason   firewire: add IPv...
1254
  	} else {
f91e3bd84   Stefan Richter   firewire: net: st...
1255
  		__be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest);
c76acec6d   Jay Fenlason   firewire: add IPv...
1256
  		u8 generation;
f91e3bd84   Stefan Richter   firewire: net: st...
1257
  		peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid));
5a124d382   Stefan Richter   firewire: net: al...
1258
  		if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR)
b2268830f   Stefan Richter   firewire: net: th...
1259
  			goto fail;
c76acec6d   Jay Fenlason   firewire: add IPv...
1260

5a124d382   Stefan Richter   firewire: net: al...
1261
1262
1263
  		generation         = peer->generation;
  		dest_node          = peer->node_id;
  		max_payload        = peer->max_payload;
f91e3bd84   Stefan Richter   firewire: net: st...
1264
  		datagram_label_ptr = &peer->datagram_label;
c76acec6d   Jay Fenlason   firewire: add IPv...
1265

5a124d382   Stefan Richter   firewire: net: al...
1266
1267
1268
1269
  		ptask->fifo_addr   = peer->fifo;
  		ptask->generation  = generation;
  		ptask->dest_node   = dest_node;
  		ptask->speed       = peer->speed;
c76acec6d   Jay Fenlason   firewire: add IPv...
1270
1271
1272
1273
  	}
  
  	/* If this is an ARP packet, convert it */
  	if (proto == htons(ETH_P_ARP)) {
c76acec6d   Jay Fenlason   firewire: add IPv...
1274
1275
  		struct arphdr *arp = (struct arphdr *)skb->data;
  		unsigned char *arp_ptr = (unsigned char *)(arp + 1);
f91e3bd84   Stefan Richter   firewire: net: st...
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
  		struct rfc2734_arp *arp1394 = (struct rfc2734_arp *)skb->data;
  		__be32 ipaddr;
  
  		ipaddr = get_unaligned((__be32 *)(arp_ptr + FWNET_ALEN));
  
  		arp1394->hw_addr_len    = RFC2734_HW_ADDR_LEN;
  		arp1394->max_rec        = dev->card->max_receive;
  		arp1394->sspd		= dev->card->link_speed;
  
  		put_unaligned_be16(dev->local_fifo >> 32,
  				   &arp1394->fifo_hi);
  		put_unaligned_be32(dev->local_fifo & 0xffffffff,
  				   &arp1394->fifo_lo);
  		put_unaligned(ipaddr, &arp1394->sip);
c76acec6d   Jay Fenlason   firewire: add IPv...
1290
  	}
c76acec6d   Jay Fenlason   firewire: add IPv...
1291
1292
1293
1294
  
  	ptask->hdr.w0 = 0;
  	ptask->hdr.w1 = 0;
  	ptask->skb = skb;
f91e3bd84   Stefan Richter   firewire: net: st...
1295
  	ptask->dev = dev;
c76acec6d   Jay Fenlason   firewire: add IPv...
1296
  	/* Does it all fit in one packet? */
f91e3bd84   Stefan Richter   firewire: net: st...
1297
1298
  	if (dg_size <= max_payload) {
  		fwnet_make_uf_hdr(&ptask->hdr, ntohs(proto));
c76acec6d   Jay Fenlason   firewire: add IPv...
1299
  		ptask->outstanding_pkts = 1;
f91e3bd84   Stefan Richter   firewire: net: st...
1300
  		max_payload = dg_size + RFC2374_UNFRAG_HDR_SIZE;
c76acec6d   Jay Fenlason   firewire: add IPv...
1301
1302
  	} else {
  		u16 datagram_label;
f91e3bd84   Stefan Richter   firewire: net: st...
1303
  		max_payload -= RFC2374_FRAG_OVERHEAD;
c76acec6d   Jay Fenlason   firewire: add IPv...
1304
  		datagram_label = (*datagram_label_ptr)++;
f91e3bd84   Stefan Richter   firewire: net: st...
1305
1306
  		fwnet_make_ff_hdr(&ptask->hdr, ntohs(proto), dg_size,
  				  datagram_label);
c76acec6d   Jay Fenlason   firewire: add IPv...
1307
  		ptask->outstanding_pkts = DIV_ROUND_UP(dg_size, max_payload);
f91e3bd84   Stefan Richter   firewire: net: st...
1308
  		max_payload += RFC2374_FRAG_HDR_SIZE;
c76acec6d   Jay Fenlason   firewire: add IPv...
1309
  	}
5a124d382   Stefan Richter   firewire: net: al...
1310

b2268830f   Stefan Richter   firewire: net: th...
1311
1312
  	if (++dev->queued_datagrams == FWNET_MAX_QUEUED_DATAGRAMS)
  		netif_stop_queue(dev->netdev);
48553011c   Stefan Richter   firewire: net: re...
1313

5a124d382   Stefan Richter   firewire: net: al...
1314
  	spin_unlock_irqrestore(&dev->lock, flags);
c76acec6d   Jay Fenlason   firewire: add IPv...
1315
  	ptask->max_payload = max_payload;
48553011c   Stefan Richter   firewire: net: re...
1316
  	ptask->enqueued    = 0;
110f82d7a   Stefan Richter   firewire: net: fi...
1317

f91e3bd84   Stefan Richter   firewire: net: st...
1318
  	fwnet_send_packet(ptask);
c76acec6d   Jay Fenlason   firewire: add IPv...
1319
1320
1321
  	return NETDEV_TX_OK;
  
   fail:
b2268830f   Stefan Richter   firewire: net: th...
1322
  	spin_unlock_irqrestore(&dev->lock, flags);
c76acec6d   Jay Fenlason   firewire: add IPv...
1323
  	if (ptask)
f91e3bd84   Stefan Richter   firewire: net: st...
1324
  		kmem_cache_free(fwnet_packet_task_cache, ptask);
c76acec6d   Jay Fenlason   firewire: add IPv...
1325
1326
1327
  
  	if (skb != NULL)
  		dev_kfree_skb(skb);
f91e3bd84   Stefan Richter   firewire: net: st...
1328
1329
  	net->stats.tx_dropped++;
  	net->stats.tx_errors++;
c76acec6d   Jay Fenlason   firewire: add IPv...
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
  
  	/*
  	 * FIXME: According to a patch from 2003-02-26, "returning non-zero
  	 * causes serious problems" here, allegedly.  Before that patch,
  	 * -ERRNO was returned which is not appropriate under Linux 2.6.
  	 * Perhaps more needs to be done?  Stop the queue in serious
  	 * conditions and restart it elsewhere?
  	 */
  	return NETDEV_TX_OK;
  }
f91e3bd84   Stefan Richter   firewire: net: st...
1340
1341
  static int fwnet_change_mtu(struct net_device *net, int new_mtu)
  {
c76acec6d   Jay Fenlason   firewire: add IPv...
1342
1343
  	if (new_mtu < 68)
  		return -EINVAL;
f91e3bd84   Stefan Richter   firewire: net: st...
1344
  	net->mtu = new_mtu;
c76acec6d   Jay Fenlason   firewire: add IPv...
1345
1346
  	return 0;
  }
18bb36f9f   Maxim Levitsky   firewire: net: ad...
1347
1348
1349
  static const struct ethtool_ops fwnet_ethtool_ops = {
  	.get_link	= ethtool_op_get_link,
  };
f91e3bd84   Stefan Richter   firewire: net: st...
1350
1351
1352
1353
  static const struct net_device_ops fwnet_netdev_ops = {
  	.ndo_open       = fwnet_open,
  	.ndo_stop	= fwnet_stop,
  	.ndo_start_xmit = fwnet_tx,
f91e3bd84   Stefan Richter   firewire: net: st...
1354
  	.ndo_change_mtu = fwnet_change_mtu,
c76acec6d   Jay Fenlason   firewire: add IPv...
1355
  };
f91e3bd84   Stefan Richter   firewire: net: st...
1356
1357
1358
1359
  static void fwnet_init_dev(struct net_device *net)
  {
  	net->header_ops		= &fwnet_header_ops;
  	net->netdev_ops		= &fwnet_netdev_ops;
1337f8535   Stefan Richter   firewire: net: ad...
1360
  	net->watchdog_timeo	= 2 * HZ;
f91e3bd84   Stefan Richter   firewire: net: st...
1361
1362
1363
1364
1365
  	net->flags		= IFF_BROADCAST | IFF_MULTICAST;
  	net->features		= NETIF_F_HIGHDMA;
  	net->addr_len		= FWNET_ALEN;
  	net->hard_header_len	= FWNET_HLEN;
  	net->type		= ARPHRD_IEEE1394;
b2268830f   Stefan Richter   firewire: net: th...
1366
  	net->tx_queue_len	= FWNET_TX_QUEUE_LEN;
18bb36f9f   Maxim Levitsky   firewire: net: ad...
1367
  	net->ethtool_ops	= &fwnet_ethtool_ops;
c76acec6d   Jay Fenlason   firewire: add IPv...
1368
  }
5a124d382   Stefan Richter   firewire: net: al...
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
  /* caller must hold fwnet_device_mutex */
  static struct fwnet_device *fwnet_dev_find(struct fw_card *card)
  {
  	struct fwnet_device *dev;
  
  	list_for_each_entry(dev, &fwnet_device_list, dev_link)
  		if (dev->card == card)
  			return dev;
  
  	return NULL;
  }
  
  static int fwnet_add_peer(struct fwnet_device *dev,
  			  struct fw_unit *unit, struct fw_device *device)
  {
  	struct fwnet_peer *peer;
  
  	peer = kmalloc(sizeof(*peer), GFP_KERNEL);
  	if (!peer)
  		return -ENOMEM;
b01b4babb   Stefan Richter   firewire: net: fi...
1389
  	dev_set_drvdata(&unit->device, peer);
5a124d382   Stefan Richter   firewire: net: al...
1390
1391
1392
  	peer->dev = dev;
  	peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4];
  	peer->fifo = FWNET_NO_FIFO_ADDR;
74a145049   Maxim Levitsky   firewire: net: in...
1393
  	peer->ip = 0;
5a124d382   Stefan Richter   firewire: net: al...
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
  	INIT_LIST_HEAD(&peer->pd_list);
  	peer->pdg_size = 0;
  	peer->datagram_label = 0;
  	peer->speed = device->max_speed;
  	peer->max_payload = fwnet_max_payload(device->max_rec, peer->speed);
  
  	peer->generation = device->generation;
  	smp_rmb();
  	peer->node_id = device->node_id;
  
  	spin_lock_irq(&dev->lock);
  	list_add_tail(&peer->peer_link, &dev->peer_list);
18bb36f9f   Maxim Levitsky   firewire: net: ad...
1406
  	dev->peer_count++;
c16714704   Stefan Richter   firewire: net: se...
1407
  	set_carrier_state(dev);
5a124d382   Stefan Richter   firewire: net: al...
1408
1409
1410
1411
  	spin_unlock_irq(&dev->lock);
  
  	return 0;
  }
f91e3bd84   Stefan Richter   firewire: net: st...
1412
1413
1414
1415
1416
1417
  static int fwnet_probe(struct device *_dev)
  {
  	struct fw_unit *unit = fw_unit(_dev);
  	struct fw_device *device = fw_parent_device(unit);
  	struct fw_card *card = device->card;
  	struct net_device *net;
b01b4babb   Stefan Richter   firewire: net: fi...
1418
  	bool allocated_netdev = false;
f91e3bd84   Stefan Richter   firewire: net: st...
1419
  	struct fwnet_device *dev;
c76acec6d   Jay Fenlason   firewire: add IPv...
1420
  	unsigned max_mtu;
5a124d382   Stefan Richter   firewire: net: al...
1421
  	int ret;
c76acec6d   Jay Fenlason   firewire: add IPv...
1422

5a124d382   Stefan Richter   firewire: net: al...
1423
  	mutex_lock(&fwnet_device_mutex);
c76acec6d   Jay Fenlason   firewire: add IPv...
1424

5a124d382   Stefan Richter   firewire: net: al...
1425
1426
  	dev = fwnet_dev_find(card);
  	if (dev) {
5a124d382   Stefan Richter   firewire: net: al...
1427
1428
  		net = dev->netdev;
  		goto have_dev;
c76acec6d   Jay Fenlason   firewire: add IPv...
1429
  	}
5a124d382   Stefan Richter   firewire: net: al...
1430

f91e3bd84   Stefan Richter   firewire: net: st...
1431
1432
  	net = alloc_netdev(sizeof(*dev), "firewire%d", fwnet_init_dev);
  	if (net == NULL) {
5a124d382   Stefan Richter   firewire: net: al...
1433
  		ret = -ENOMEM;
c76acec6d   Jay Fenlason   firewire: add IPv...
1434
1435
  		goto out;
  	}
b01b4babb   Stefan Richter   firewire: net: fi...
1436
  	allocated_netdev = true;
f91e3bd84   Stefan Richter   firewire: net: st...
1437
1438
  	SET_NETDEV_DEV(net, card->device);
  	dev = netdev_priv(net);
c76acec6d   Jay Fenlason   firewire: add IPv...
1439

f91e3bd84   Stefan Richter   firewire: net: st...
1440
1441
1442
1443
1444
  	spin_lock_init(&dev->lock);
  	dev->broadcast_state = FWNET_BROADCAST_ERROR;
  	dev->broadcast_rcv_context = NULL;
  	dev->broadcast_xmt_max_payload = 0;
  	dev->broadcast_xmt_datagramlabel = 0;
f91e3bd84   Stefan Richter   firewire: net: st...
1445
  	dev->local_fifo = FWNET_NO_FIFO_ADDR;
48553011c   Stefan Richter   firewire: net: re...
1446
  	dev->queued_datagrams = 0;
5a124d382   Stefan Richter   firewire: net: al...
1447
  	INIT_LIST_HEAD(&dev->peer_list);
f91e3bd84   Stefan Richter   firewire: net: st...
1448
  	dev->card = card;
5a124d382   Stefan Richter   firewire: net: al...
1449
  	dev->netdev = net;
c76acec6d   Jay Fenlason   firewire: add IPv...
1450
1451
1452
1453
1454
1455
  
  	/*
  	 * Use the RFC 2734 default 1500 octets or the maximum payload
  	 * as initial MTU
  	 */
  	max_mtu = (1 << (card->max_receive + 1))
f91e3bd84   Stefan Richter   firewire: net: st...
1456
1457
  		  - sizeof(struct rfc2734_header) - IEEE1394_GASP_HDR_SIZE;
  	net->mtu = min(1500U, max_mtu);
c76acec6d   Jay Fenlason   firewire: add IPv...
1458
1459
  
  	/* Set our hardware address while we're at it */
f91e3bd84   Stefan Richter   firewire: net: st...
1460
1461
  	put_unaligned_be64(card->guid, net->dev_addr);
  	put_unaligned_be64(~0ULL, net->broadcast);
5a124d382   Stefan Richter   firewire: net: al...
1462
1463
  	ret = register_netdev(net);
  	if (ret) {
f91e3bd84   Stefan Richter   firewire: net: st...
1464
1465
  		fw_error("Cannot register the driver
  ");
c76acec6d   Jay Fenlason   firewire: add IPv...
1466
1467
  		goto out;
  	}
5a124d382   Stefan Richter   firewire: net: al...
1468
  	list_add_tail(&dev->dev_link, &fwnet_device_list);
f91e3bd84   Stefan Richter   firewire: net: st...
1469
1470
1471
  	fw_notify("%s: IPv4 over FireWire on device %016llx
  ",
  		  net->name, (unsigned long long)card->guid);
5a124d382   Stefan Richter   firewire: net: al...
1472
1473
   have_dev:
  	ret = fwnet_add_peer(dev, unit, device);
b01b4babb   Stefan Richter   firewire: net: fi...
1474
  	if (ret && allocated_netdev) {
5a124d382   Stefan Richter   firewire: net: al...
1475
1476
1477
  		unregister_netdev(net);
  		list_del(&dev->dev_link);
  	}
c76acec6d   Jay Fenlason   firewire: add IPv...
1478
   out:
b01b4babb   Stefan Richter   firewire: net: fi...
1479
  	if (ret && allocated_netdev)
f91e3bd84   Stefan Richter   firewire: net: st...
1480
  		free_netdev(net);
5a124d382   Stefan Richter   firewire: net: al...
1481
1482
1483
1484
  	mutex_unlock(&fwnet_device_mutex);
  
  	return ret;
  }
c16714704   Stefan Richter   firewire: net: se...
1485
  static void fwnet_remove_peer(struct fwnet_peer *peer, struct fwnet_device *dev)
5a124d382   Stefan Richter   firewire: net: al...
1486
1487
  {
  	struct fwnet_partial_datagram *pd, *pd_next;
c16714704   Stefan Richter   firewire: net: se...
1488
  	spin_lock_irq(&dev->lock);
5a124d382   Stefan Richter   firewire: net: al...
1489
  	list_del(&peer->peer_link);
c16714704   Stefan Richter   firewire: net: se...
1490
1491
1492
  	dev->peer_count--;
  	set_carrier_state(dev);
  	spin_unlock_irq(&dev->lock);
5a124d382   Stefan Richter   firewire: net: al...
1493
1494
1495
1496
1497
  
  	list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link)
  		fwnet_pd_delete(pd);
  
  	kfree(peer);
c76acec6d   Jay Fenlason   firewire: add IPv...
1498
  }
f91e3bd84   Stefan Richter   firewire: net: st...
1499
1500
  static int fwnet_remove(struct device *_dev)
  {
b01b4babb   Stefan Richter   firewire: net: fi...
1501
  	struct fwnet_peer *peer = dev_get_drvdata(_dev);
5a124d382   Stefan Richter   firewire: net: al...
1502
  	struct fwnet_device *dev = peer->dev;
f91e3bd84   Stefan Richter   firewire: net: st...
1503
  	struct net_device *net;
48553011c   Stefan Richter   firewire: net: re...
1504
  	int i;
f91e3bd84   Stefan Richter   firewire: net: st...
1505

5a124d382   Stefan Richter   firewire: net: al...
1506
  	mutex_lock(&fwnet_device_mutex);
c76acec6d   Jay Fenlason   firewire: add IPv...
1507

74a145049   Maxim Levitsky   firewire: net: in...
1508
1509
1510
  	net = dev->netdev;
  	if (net && peer->ip)
  		arp_invalidate(net, peer->ip);
c16714704   Stefan Richter   firewire: net: se...
1511
  	fwnet_remove_peer(peer, dev);
18bb36f9f   Maxim Levitsky   firewire: net: ad...
1512

5a124d382   Stefan Richter   firewire: net: al...
1513
  	if (list_empty(&dev->peer_list)) {
f91e3bd84   Stefan Richter   firewire: net: st...
1514
1515
1516
1517
1518
1519
1520
1521
1522
  		unregister_netdev(net);
  
  		if (dev->local_fifo != FWNET_NO_FIFO_ADDR)
  			fw_core_remove_address_handler(&dev->handler);
  		if (dev->broadcast_rcv_context) {
  			fw_iso_context_stop(dev->broadcast_rcv_context);
  			fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer,
  					      dev->card);
  			fw_iso_context_destroy(dev->broadcast_rcv_context);
c76acec6d   Jay Fenlason   firewire: add IPv...
1523
  		}
48553011c   Stefan Richter   firewire: net: re...
1524
1525
1526
  		for (i = 0; dev->queued_datagrams && i < 5; i++)
  			ssleep(1);
  		WARN_ON(dev->queued_datagrams);
b01b4babb   Stefan Richter   firewire: net: fi...
1527
  		list_del(&dev->dev_link);
f91e3bd84   Stefan Richter   firewire: net: st...
1528
  		free_netdev(net);
c76acec6d   Jay Fenlason   firewire: add IPv...
1529
  	}
f91e3bd84   Stefan Richter   firewire: net: st...
1530

5a124d382   Stefan Richter   firewire: net: al...
1531
  	mutex_unlock(&fwnet_device_mutex);
c76acec6d   Jay Fenlason   firewire: add IPv...
1532
1533
  	return 0;
  }
f91e3bd84   Stefan Richter   firewire: net: st...
1534
1535
1536
1537
1538
1539
1540
  /*
   * FIXME abort partially sent fragmented datagrams,
   * discard partially received fragmented datagrams
   */
  static void fwnet_update(struct fw_unit *unit)
  {
  	struct fw_device *device = fw_parent_device(unit);
b01b4babb   Stefan Richter   firewire: net: fi...
1541
  	struct fwnet_peer *peer = dev_get_drvdata(&unit->device);
5a124d382   Stefan Richter   firewire: net: al...
1542
  	int generation;
c76acec6d   Jay Fenlason   firewire: add IPv...
1543

5a124d382   Stefan Richter   firewire: net: al...
1544
1545
1546
1547
1548
1549
  	generation = device->generation;
  
  	spin_lock_irq(&peer->dev->lock);
  	peer->node_id    = device->node_id;
  	peer->generation = generation;
  	spin_unlock_irq(&peer->dev->lock);
c76acec6d   Jay Fenlason   firewire: add IPv...
1550
  }
f91e3bd84   Stefan Richter   firewire: net: st...
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
  static const struct ieee1394_device_id fwnet_id_table[] = {
  	{
  		.match_flags  = IEEE1394_MATCH_SPECIFIER_ID |
  				IEEE1394_MATCH_VERSION,
  		.specifier_id = IANA_SPECIFIER_ID,
  		.version      = RFC2734_SW_VERSION,
  	},
  	{ }
  };
  
  static struct fw_driver fwnet_driver = {
c76acec6d   Jay Fenlason   firewire: add IPv...
1562
  	.driver = {
f91e3bd84   Stefan Richter   firewire: net: st...
1563
1564
1565
1566
1567
  		.owner  = THIS_MODULE,
  		.name   = "net",
  		.bus    = &fw_bus_type,
  		.probe  = fwnet_probe,
  		.remove = fwnet_remove,
c76acec6d   Jay Fenlason   firewire: add IPv...
1568
  	},
f91e3bd84   Stefan Richter   firewire: net: st...
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
  	.update   = fwnet_update,
  	.id_table = fwnet_id_table,
  };
  
  static const u32 rfc2374_unit_directory_data[] = {
  	0x00040000,	/* directory_length		*/
  	0x1200005e,	/* unit_specifier_id: IANA	*/
  	0x81000003,	/* textual descriptor offset	*/
  	0x13000001,	/* unit_sw_version: RFC 2734	*/
  	0x81000005,	/* textual descriptor offset	*/
  	0x00030000,	/* descriptor_length		*/
  	0x00000000,	/* text				*/
  	0x00000000,	/* minimal ASCII, en		*/
  	0x49414e41,	/* I A N A			*/
  	0x00030000,	/* descriptor_length		*/
  	0x00000000,	/* text				*/
  	0x00000000,	/* minimal ASCII, en		*/
  	0x49507634,	/* I P v 4			*/
  };
  
  static struct fw_descriptor rfc2374_unit_directory = {
  	.length = ARRAY_SIZE(rfc2374_unit_directory_data),
  	.key    = (CSR_DIRECTORY | CSR_UNIT) << 24,
  	.data   = rfc2374_unit_directory_data
c76acec6d   Jay Fenlason   firewire: add IPv...
1593
  };
f91e3bd84   Stefan Richter   firewire: net: st...
1594
1595
1596
1597
1598
1599
1600
  static int __init fwnet_init(void)
  {
  	int err;
  
  	err = fw_core_add_descriptor(&rfc2374_unit_directory);
  	if (err)
  		return err;
c76acec6d   Jay Fenlason   firewire: add IPv...
1601

f91e3bd84   Stefan Richter   firewire: net: st...
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
  	fwnet_packet_task_cache = kmem_cache_create("packet_task",
  			sizeof(struct fwnet_packet_task), 0, 0, NULL);
  	if (!fwnet_packet_task_cache) {
  		err = -ENOMEM;
  		goto out;
  	}
  
  	err = driver_register(&fwnet_driver.driver);
  	if (!err)
  		return 0;
  
  	kmem_cache_destroy(fwnet_packet_task_cache);
  out:
  	fw_core_remove_descriptor(&rfc2374_unit_directory);
  
  	return err;
c76acec6d   Jay Fenlason   firewire: add IPv...
1618
  }
f91e3bd84   Stefan Richter   firewire: net: st...
1619
  module_init(fwnet_init);
c76acec6d   Jay Fenlason   firewire: add IPv...
1620

f91e3bd84   Stefan Richter   firewire: net: st...
1621
1622
1623
1624
1625
  static void __exit fwnet_cleanup(void)
  {
  	driver_unregister(&fwnet_driver.driver);
  	kmem_cache_destroy(fwnet_packet_task_cache);
  	fw_core_remove_descriptor(&rfc2374_unit_directory);
c76acec6d   Jay Fenlason   firewire: add IPv...
1626
  }
f91e3bd84   Stefan Richter   firewire: net: st...
1627
  module_exit(fwnet_cleanup);
c76acec6d   Jay Fenlason   firewire: add IPv...
1628

f91e3bd84   Stefan Richter   firewire: net: st...
1629
1630
1631
1632
  MODULE_AUTHOR("Jay Fenlason <fenlason@redhat.com>");
  MODULE_DESCRIPTION("IPv4 over IEEE1394 as per RFC 2734");
  MODULE_LICENSE("GPL");
  MODULE_DEVICE_TABLE(ieee1394, fwnet_id_table);