Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/irda/irlan/irlan_eth.c
17604 views
1
/*********************************************************************
2
*
3
* Filename: irlan_eth.c
4
* Version:
5
* Description:
6
* Status: Experimental.
7
* Author: Dag Brattli <[email protected]>
8
* Created at: Thu Oct 15 08:37:58 1998
9
* Modified at: Tue Mar 21 09:06:41 2000
10
* Modified by: Dag Brattli <[email protected]>
11
* Sources: skeleton.c by Donald Becker <[email protected]>
12
* slip.c by Laurence Culhane, <[email protected]>
13
* Fred N. van Kempen, <[email protected]>
14
*
15
* Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved.
16
*
17
* This program is free software; you can redistribute it and/or
18
* modify it under the terms of the GNU General Public License as
19
* published by the Free Software Foundation; either version 2 of
20
* the License, or (at your option) any later version.
21
*
22
* Neither Dag Brattli nor University of Tromsø admit liability nor
23
* provide warranty for any of this software. This material is
24
* provided "AS-IS" and at no charge.
25
*
26
********************************************************************/
27
28
#include <linux/netdevice.h>
29
#include <linux/etherdevice.h>
30
#include <linux/inetdevice.h>
31
#include <linux/if_arp.h>
32
#include <linux/module.h>
33
#include <linux/sched.h>
34
#include <net/arp.h>
35
36
#include <net/irda/irda.h>
37
#include <net/irda/irmod.h>
38
#include <net/irda/irlan_common.h>
39
#include <net/irda/irlan_client.h>
40
#include <net/irda/irlan_event.h>
41
#include <net/irda/irlan_eth.h>
42
43
static int irlan_eth_open(struct net_device *dev);
44
static int irlan_eth_close(struct net_device *dev);
45
static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb,
46
struct net_device *dev);
47
static void irlan_eth_set_multicast_list( struct net_device *dev);
48
49
static const struct net_device_ops irlan_eth_netdev_ops = {
50
.ndo_open = irlan_eth_open,
51
.ndo_stop = irlan_eth_close,
52
.ndo_start_xmit = irlan_eth_xmit,
53
.ndo_set_multicast_list = irlan_eth_set_multicast_list,
54
.ndo_change_mtu = eth_change_mtu,
55
.ndo_validate_addr = eth_validate_addr,
56
};
57
58
/*
59
* Function irlan_eth_setup (dev)
60
*
61
* The network device initialization function.
62
*
63
*/
64
static void irlan_eth_setup(struct net_device *dev)
65
{
66
ether_setup(dev);
67
68
dev->netdev_ops = &irlan_eth_netdev_ops;
69
dev->destructor = free_netdev;
70
71
72
/*
73
* Lets do all queueing in IrTTP instead of this device driver.
74
* Queueing here as well can introduce some strange latency
75
* problems, which we will avoid by setting the queue size to 0.
76
*/
77
/*
78
* The bugs in IrTTP and IrLAN that created this latency issue
79
* have now been fixed, and we can propagate flow control properly
80
* to the network layer. However, this requires a minimal queue of
81
* packets for the device.
82
* Without flow control, the Tx Queue is 14 (ttp) + 0 (dev) = 14
83
* With flow control, the Tx Queue is 7 (ttp) + 4 (dev) = 11
84
* See irlan_eth_flow_indication()...
85
* Note : this number was randomly selected and would need to
86
* be adjusted.
87
* Jean II */
88
dev->tx_queue_len = 4;
89
}
90
91
/*
92
* Function alloc_irlandev
93
*
94
* Allocate network device and control block
95
*
96
*/
97
struct net_device *alloc_irlandev(const char *name)
98
{
99
return alloc_netdev(sizeof(struct irlan_cb), name,
100
irlan_eth_setup);
101
}
102
103
/*
104
* Function irlan_eth_open (dev)
105
*
106
* Network device has been opened by user
107
*
108
*/
109
static int irlan_eth_open(struct net_device *dev)
110
{
111
struct irlan_cb *self = netdev_priv(dev);
112
113
IRDA_DEBUG(2, "%s()\n", __func__ );
114
115
/* Ready to play! */
116
netif_stop_queue(dev); /* Wait until data link is ready */
117
118
/* We are now open, so time to do some work */
119
self->disconnect_reason = 0;
120
irlan_client_wakeup(self, self->saddr, self->daddr);
121
122
/* Make sure we have a hardware address before we return,
123
so DHCP clients gets happy */
124
return wait_event_interruptible(self->open_wait,
125
!self->tsap_data->connected);
126
}
127
128
/*
129
* Function irlan_eth_close (dev)
130
*
131
* Stop the ether network device, his function will usually be called by
132
* ifconfig down. We should now disconnect the link, We start the
133
* close timer, so that the instance will be removed if we are unable
134
* to discover the remote device after the disconnect.
135
*/
136
static int irlan_eth_close(struct net_device *dev)
137
{
138
struct irlan_cb *self = netdev_priv(dev);
139
140
IRDA_DEBUG(2, "%s()\n", __func__ );
141
142
/* Stop device */
143
netif_stop_queue(dev);
144
145
irlan_close_data_channel(self);
146
irlan_close_tsaps(self);
147
148
irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
149
irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
150
151
/* Remove frames queued on the control channel */
152
skb_queue_purge(&self->client.txq);
153
154
self->client.tx_busy = 0;
155
156
return 0;
157
}
158
159
/*
160
* Function irlan_eth_tx (skb)
161
*
162
* Transmits ethernet frames over IrDA link.
163
*
164
*/
165
static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb,
166
struct net_device *dev)
167
{
168
struct irlan_cb *self = netdev_priv(dev);
169
int ret;
170
unsigned int len;
171
172
/* skb headroom large enough to contain all IrDA-headers? */
173
if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) {
174
struct sk_buff *new_skb =
175
skb_realloc_headroom(skb, self->max_header_size);
176
177
/* We have to free the original skb anyway */
178
dev_kfree_skb(skb);
179
180
/* Did the realloc succeed? */
181
if (new_skb == NULL)
182
return NETDEV_TX_OK;
183
184
/* Use the new skb instead */
185
skb = new_skb;
186
}
187
188
dev->trans_start = jiffies;
189
190
len = skb->len;
191
/* Now queue the packet in the transport layer */
192
if (self->use_udata)
193
ret = irttp_udata_request(self->tsap_data, skb);
194
else
195
ret = irttp_data_request(self->tsap_data, skb);
196
197
if (ret < 0) {
198
/*
199
* IrTTPs tx queue is full, so we just have to
200
* drop the frame! You might think that we should
201
* just return -1 and don't deallocate the frame,
202
* but that is dangerous since it's possible that
203
* we have replaced the original skb with a new
204
* one with larger headroom, and that would really
205
* confuse do_dev_queue_xmit() in dev.c! I have
206
* tried :-) DB
207
*/
208
/* irttp_data_request already free the packet */
209
dev->stats.tx_dropped++;
210
} else {
211
dev->stats.tx_packets++;
212
dev->stats.tx_bytes += len;
213
}
214
215
return NETDEV_TX_OK;
216
}
217
218
/*
219
* Function irlan_eth_receive (handle, skb)
220
*
221
* This function gets the data that is received on the data channel
222
*
223
*/
224
int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb)
225
{
226
struct irlan_cb *self = instance;
227
struct net_device *dev = self->dev;
228
229
if (skb == NULL) {
230
dev->stats.rx_dropped++;
231
return 0;
232
}
233
if (skb->len < ETH_HLEN) {
234
IRDA_DEBUG(0, "%s() : IrLAN frame too short (%d)\n",
235
__func__, skb->len);
236
dev->stats.rx_dropped++;
237
dev_kfree_skb(skb);
238
return 0;
239
}
240
241
/*
242
* Adopt this frame! Important to set all these fields since they
243
* might have been previously set by the low level IrDA network
244
* device driver
245
*/
246
skb->protocol = eth_type_trans(skb, dev); /* Remove eth header */
247
248
dev->stats.rx_packets++;
249
dev->stats.rx_bytes += skb->len;
250
251
netif_rx(skb); /* Eat it! */
252
253
return 0;
254
}
255
256
/*
257
* Function irlan_eth_flow (status)
258
*
259
* Do flow control between IP/Ethernet and IrLAN/IrTTP. This is done by
260
* controlling the queue stop/start.
261
*
262
* The IrDA link layer has the advantage to have flow control, and
263
* IrTTP now properly handles that. Flow controlling the higher layers
264
* prevent us to drop Tx packets in here (up to 15% for a TCP socket,
265
* more for UDP socket).
266
* Also, this allow us to reduce the overall transmit queue, which means
267
* less latency in case of mixed traffic.
268
* Jean II
269
*/
270
void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
271
{
272
struct irlan_cb *self;
273
struct net_device *dev;
274
275
self = (struct irlan_cb *) instance;
276
277
IRDA_ASSERT(self != NULL, return;);
278
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
279
280
dev = self->dev;
281
282
IRDA_ASSERT(dev != NULL, return;);
283
284
IRDA_DEBUG(0, "%s() : flow %s ; running %d\n", __func__,
285
flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START",
286
netif_running(dev));
287
288
switch (flow) {
289
case FLOW_STOP:
290
/* IrTTP is full, stop higher layers */
291
netif_stop_queue(dev);
292
break;
293
case FLOW_START:
294
default:
295
/* Tell upper layers that its time to transmit frames again */
296
/* Schedule network layer */
297
netif_wake_queue(dev);
298
break;
299
}
300
}
301
302
/*
303
* Function set_multicast_list (dev)
304
*
305
* Configure the filtering of the device
306
*
307
*/
308
#define HW_MAX_ADDRS 4 /* Must query to get it! */
309
static void irlan_eth_set_multicast_list(struct net_device *dev)
310
{
311
struct irlan_cb *self = netdev_priv(dev);
312
313
IRDA_DEBUG(2, "%s()\n", __func__ );
314
315
/* Check if data channel has been connected yet */
316
if (self->client.state != IRLAN_DATA) {
317
IRDA_DEBUG(1, "%s(), delaying!\n", __func__ );
318
return;
319
}
320
321
if (dev->flags & IFF_PROMISC) {
322
/* Enable promiscuous mode */
323
IRDA_WARNING("Promiscuous mode not implemented by IrLAN!\n");
324
}
325
else if ((dev->flags & IFF_ALLMULTI) ||
326
netdev_mc_count(dev) > HW_MAX_ADDRS) {
327
/* Disable promiscuous mode, use normal mode. */
328
IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ );
329
/* hardware_set_filter(NULL); */
330
331
irlan_set_multicast_filter(self, TRUE);
332
}
333
else if (!netdev_mc_empty(dev)) {
334
IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ );
335
/* Walk the address list, and load the filter */
336
/* hardware_set_filter(dev->mc_list); */
337
338
irlan_set_multicast_filter(self, TRUE);
339
}
340
else {
341
IRDA_DEBUG(4, "%s(), Clearing multicast filter\n", __func__ );
342
irlan_set_multicast_filter(self, FALSE);
343
}
344
345
if (dev->flags & IFF_BROADCAST)
346
irlan_set_broadcast_filter(self, TRUE);
347
else
348
irlan_set_broadcast_filter(self, FALSE);
349
}
350
351