Blame view

net/irda/af_irda.c 66.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  /*********************************************************************
   *
   * Filename:      af_irda.c
   * Version:       0.9
   * Description:   IrDA sockets implementation
   * Status:        Stable
   * Author:        Dag Brattli <dagb@cs.uit.no>
   * Created at:    Sun May 31 10:12:43 1998
   * Modified at:   Sat Dec 25 21:10:23 1999
   * Modified by:   Dag Brattli <dag@brattli.net>
   * Sources:       af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
   *
   *     Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no>
   *     Copyright (c) 1999-2003 Jean Tourrilhes <jt@hpl.hp.com>
   *     All Rights Reserved.
   *
   *     This program is free software; you can redistribute it and/or
   *     modify it under the terms of the GNU General Public License as
   *     published by the Free Software Foundation; either version 2 of
   *     the License, or (at your option) any later version.
   *
   *     This program is distributed in the hope that it will be useful,
   *     but WITHOUT ANY WARRANTY; without even the implied warranty of
   *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   *     GNU General Public License for more details.
   *
   *     You should have received a copy of the GNU General Public License
d37705092   Jeff Kirsher   net/irda: Fix FSF...
28
   *     along with this program; if not, see <http://www.gnu.org/licenses/>.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
35
36
37
38
39
40
41
   *
   *     Linux-IrDA now supports four different types of IrDA sockets:
   *
   *     o SOCK_STREAM:    TinyTP connections with SAR disabled. The
   *                       max SDU size is 0 for conn. of this type
   *     o SOCK_SEQPACKET: TinyTP connections with SAR enabled. TTP may
   *                       fragment the messages, but will preserve
   *                       the message boundaries
   *     o SOCK_DGRAM:     IRDAPROTO_UNITDATA: TinyTP connections with Unitdata
   *                       (unreliable) transfers
   *                       IRDAPROTO_ULTRA: Connectionless and unreliable data
   *
   ********************************************************************/
4fc268d24   Randy Dunlap   [PATCH] capable/c...
42
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/socket.h>
  #include <linux/sockios.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
47
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
51
52
53
54
55
56
  #include <linux/init.h>
  #include <linux/net.h>
  #include <linux/irda.h>
  #include <linux/poll.h>
  
  #include <asm/ioctls.h>		/* TIOCOUTQ, TIOCINQ */
  #include <asm/uaccess.h>
  
  #include <net/sock.h>
c752f0739   Arnaldo Carvalho de Melo   [TCP]: Move the t...
57
  #include <net/tcp_states.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
  
  #include <net/irda/af_irda.h>
3f378b684   Eric Paris   net: pass kern to...
60
  static int irda_create(struct net *net, struct socket *sock, int protocol, int kern);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61

90ddc4f04   Eric Dumazet   [NET]: move struc...
62
63
64
  static const struct proto_ops irda_stream_ops;
  static const struct proto_ops irda_seqpacket_ops;
  static const struct proto_ops irda_dgram_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
  
  #ifdef CONFIG_IRDA_ULTRA
90ddc4f04   Eric Dumazet   [NET]: move struc...
67
  static const struct proto_ops irda_ultra_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
  #define ULTRA_MAX_DATA 382
  #endif /* CONFIG_IRDA_ULTRA */
  
  #define IRDA_MAX_HEADER (TTP_MAX_HEADER)
  
  /*
   * Function irda_data_indication (instance, sap, skb)
   *
   *    Received some data from TinyTP. Just queue it on the receive queue
   *
   */
  static int irda_data_indication(void *instance, void *sap, struct sk_buff *skb)
  {
  	struct irda_sock *self;
  	struct sock *sk;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
  	self = instance;
  	sk = instance;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
  
  	err = sock_queue_rcv_skb(sk, skb);
  	if (err) {
955a9d202   Joe Perches   irda: Convert IRD...
89
90
  		pr_debug("%s(), error: no more mem!
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  		self->rx_flow = FLOW_STOP;
  
  		/* When we return error, TTP will need to requeue the skb */
  		return err;
  	}
  
  	return 0;
  }
  
  /*
   * Function irda_disconnect_indication (instance, sap, reason, skb)
   *
   *    Connection has been closed. Check reason to find out why
   *
   */
  static void irda_disconnect_indication(void *instance, void *sap,
  				       LM_REASON reason, struct sk_buff *skb)
  {
  	struct irda_sock *self;
  	struct sock *sk;
  
  	self = instance;
955a9d202   Joe Perches   irda: Convert IRD...
113
114
  	pr_debug("%s(%p)
  ", __func__, self);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
119
120
121
  
  	/* Don't care about it, but let's not leak it */
  	if(skb)
  		dev_kfree_skb(skb);
  
  	sk = instance;
  	if (sk == NULL) {
955a9d202   Joe Perches   irda: Convert IRD...
122
123
124
  		pr_debug("%s(%p) : BUG : sk is NULL
  ",
  			 __func__, self);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
128
  		return;
  	}
  
  	/* Prevent race conditions with irda_release() and irda_shutdown() */
6e66aa15d   Olaf Kirch   [IrDA] af_irda: S...
129
  	bh_lock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
  	if (!sock_flag(sk, SOCK_DEAD) && sk->sk_state != TCP_CLOSE) {
  		sk->sk_state     = TCP_CLOSE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
  		sk->sk_shutdown |= SEND_SHUTDOWN;
  
  		sk->sk_state_change(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  
  		/* Close our TSAP.
  		 * If we leave it open, IrLMP put it back into the list of
  		 * unconnected LSAPs. The problem is that any incoming request
  		 * can then be matched to this socket (and it will be, because
  		 * it is at the head of the list). This would prevent any
  		 * listening socket waiting on the same TSAP to get those
  		 * requests. Some apps forget to close sockets, or hang to it
  		 * a bit too long, so we may stay in this dead state long
  		 * enough to be noticed...
  		 * Note : all socket function do check sk->sk_state, so we are
  		 * safe...
  		 * Jean II
  		 */
  		if (self->tsap) {
  			irttp_close_tsap(self->tsap);
  			self->tsap = NULL;
  		}
6819bc2e1   YOSHIFUJI Hideaki   [NET] IRDA: Fix w...
153
  	}
6e66aa15d   Olaf Kirch   [IrDA] af_irda: S...
154
  	bh_unlock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  
  	/* Note : once we are there, there is not much you want to do
  	 * with the socket anymore, apart from closing it.
  	 * For example, bind() and connect() won't reset sk->sk_err,
  	 * sk->sk_shutdown and sk->sk_flags to valid values...
  	 * Jean II
  	 */
  }
  
  /*
   * Function irda_connect_confirm (instance, sap, qos, max_sdu_size, skb)
   *
   *    Connections has been confirmed by the remote device
   *
   */
  static void irda_connect_confirm(void *instance, void *sap,
  				 struct qos_info *qos,
  				 __u32 max_sdu_size, __u8 max_header_size,
  				 struct sk_buff *skb)
  {
  	struct irda_sock *self;
  	struct sock *sk;
  
  	self = instance;
955a9d202   Joe Perches   irda: Convert IRD...
179
180
  	pr_debug("%s(%p)
  ", __func__, self);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  
  	sk = instance;
  	if (sk == NULL) {
  		dev_kfree_skb(skb);
  		return;
  	}
  
  	dev_kfree_skb(skb);
  	// Should be ??? skb_queue_tail(&sk->sk_receive_queue, skb);
  
  	/* How much header space do we need to reserve */
  	self->max_header_size = max_header_size;
  
  	/* IrTTP max SDU size in transmit direction */
  	self->max_sdu_size_tx = max_sdu_size;
  
  	/* Find out what the largest chunk of data that we can transmit is */
  	switch (sk->sk_type) {
  	case SOCK_STREAM:
  		if (max_sdu_size != 0) {
6c91023dc   Joe Perches   irda: Remove IRDA...
201
202
203
  			net_err_ratelimited("%s: max_sdu_size must be 0
  ",
  					    __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
207
208
209
  			return;
  		}
  		self->max_data_size = irttp_get_max_seg_size(self->tsap);
  		break;
  	case SOCK_SEQPACKET:
  		if (max_sdu_size == 0) {
6c91023dc   Joe Perches   irda: Remove IRDA...
210
211
212
  			net_err_ratelimited("%s: max_sdu_size cannot be 0
  ",
  					    __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
216
217
218
  			return;
  		}
  		self->max_data_size = max_sdu_size;
  		break;
  	default:
  		self->max_data_size = irttp_get_max_seg_size(self->tsap);
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
219
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220

955a9d202   Joe Perches   irda: Convert IRD...
221
222
223
  	pr_debug("%s(), max_data_size=%d
  ", __func__,
  		 self->max_data_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  
  	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
  
  	/* We are now connected! */
  	sk->sk_state = TCP_ESTABLISHED;
  	sk->sk_state_change(sk);
  }
  
  /*
   * Function irda_connect_indication(instance, sap, qos, max_sdu_size, userdata)
   *
   *    Incoming connection
   *
   */
  static void irda_connect_indication(void *instance, void *sap,
  				    struct qos_info *qos, __u32 max_sdu_size,
  				    __u8 max_header_size, struct sk_buff *skb)
  {
  	struct irda_sock *self;
  	struct sock *sk;
  
  	self = instance;
955a9d202   Joe Perches   irda: Convert IRD...
246
247
  	pr_debug("%s(%p)
  ", __func__, self);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  
  	sk = instance;
  	if (sk == NULL) {
  		dev_kfree_skb(skb);
  		return;
  	}
  
  	/* How much header space do we need to reserve */
  	self->max_header_size = max_header_size;
  
  	/* IrTTP max SDU size in transmit direction */
  	self->max_sdu_size_tx = max_sdu_size;
  
  	/* Find out what the largest chunk of data that we can transmit is */
  	switch (sk->sk_type) {
  	case SOCK_STREAM:
  		if (max_sdu_size != 0) {
6c91023dc   Joe Perches   irda: Remove IRDA...
265
266
267
  			net_err_ratelimited("%s: max_sdu_size must be 0
  ",
  					    __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
271
272
273
274
  			kfree_skb(skb);
  			return;
  		}
  		self->max_data_size = irttp_get_max_seg_size(self->tsap);
  		break;
  	case SOCK_SEQPACKET:
  		if (max_sdu_size == 0) {
6c91023dc   Joe Perches   irda: Remove IRDA...
275
276
277
  			net_err_ratelimited("%s: max_sdu_size cannot be 0
  ",
  					    __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
281
282
283
284
  			kfree_skb(skb);
  			return;
  		}
  		self->max_data_size = max_sdu_size;
  		break;
  	default:
  		self->max_data_size = irttp_get_max_seg_size(self->tsap);
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
285
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286

955a9d202   Joe Perches   irda: Convert IRD...
287
288
289
  	pr_debug("%s(), max_data_size=%d
  ", __func__,
  		 self->max_data_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
  
  	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
  
  	skb_queue_tail(&sk->sk_receive_queue, skb);
  	sk->sk_state_change(sk);
  }
  
  /*
   * Function irda_connect_response (handle)
   *
   *    Accept incoming connection
   *
   */
  static void irda_connect_response(struct irda_sock *self)
  {
  	struct sk_buff *skb;
e1e3c806d   Mathias Krause   irda: use GFP_KER...
306
  	skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  	if (skb == NULL) {
955a9d202   Joe Perches   irda: Convert IRD...
308
309
310
  		pr_debug("%s() Unable to allocate sk_buff!
  ",
  			 __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
  		return;
  	}
  
  	/* Reserve space for MUX_CONTROL and LAP header */
  	skb_reserve(skb, IRDA_MAX_HEADER);
  
  	irttp_connect_response(self->tsap, self->max_sdu_size_rx, skb);
  }
  
  /*
   * Function irda_flow_indication (instance, sap, flow)
   *
   *    Used by TinyTP to tell us if it can accept more data or not
   *
   */
  static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
  {
  	struct irda_sock *self;
  	struct sock *sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
  	self = instance;
  	sk = instance;
c3ea9fa27   Samuel Ortiz   [IrDA] af_irda: I...
332
  	BUG_ON(sk == NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
  
  	switch (flow) {
  	case FLOW_STOP:
955a9d202   Joe Perches   irda: Convert IRD...
336
337
338
  		pr_debug("%s(), IrTTP wants us to slow down
  ",
  			 __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
  		self->tx_flow = flow;
  		break;
  	case FLOW_START:
  		self->tx_flow = flow;
955a9d202   Joe Perches   irda: Convert IRD...
343
344
345
  		pr_debug("%s(), IrTTP wants us to start again
  ",
  			 __func__);
aa3951451   Eric Dumazet   net: sk_sleep() h...
346
  		wake_up_interruptible(sk_sleep(sk));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
  		break;
  	default:
955a9d202   Joe Perches   irda: Convert IRD...
349
350
  		pr_debug("%s(), Unknown flow command!
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
  		/* Unknown flow command, better stop */
  		self->tx_flow = flow;
  		break;
  	}
  }
  
  /*
   * Function irda_getvalue_confirm (obj_id, value, priv)
   *
   *    Got answer from remote LM-IAS, just pass object to requester...
   *
   * Note : duplicate from above, but we need our own version that
   * doesn't touch the dtsap_sel and save the full value structure...
   */
  static void irda_getvalue_confirm(int result, __u16 obj_id,
  				  struct ias_value *value, void *priv)
  {
  	struct irda_sock *self;
ea1107338   Joe Perches   net: Remove casts...
369
  	self = priv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  	if (!self) {
6c91023dc   Joe Perches   irda: Remove IRDA...
371
372
  		net_warn_ratelimited("%s: lost myself!
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
  		return;
  	}
955a9d202   Joe Perches   irda: Convert IRD...
375
376
  	pr_debug("%s(%p)
  ", __func__, self);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
381
382
383
  
  	/* We probably don't need to make any more queries */
  	iriap_close(self->iriap);
  	self->iriap = NULL;
  
  	/* Check if request succeeded */
  	if (result != IAS_SUCCESS) {
955a9d202   Joe Perches   irda: Convert IRD...
384
385
386
  		pr_debug("%s(), IAS query failed! (%d)
  ", __func__,
  			 result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  
  		self->errno = result;	/* We really need it later */
  
  		/* Wake up any processes waiting for result */
  		wake_up_interruptible(&self->query_wait);
  
  		return;
  	}
  
  	/* Pass the object to the caller (so the caller must delete it) */
  	self->ias_result = value;
  	self->errno = 0;
  
  	/* Wake up any processes waiting for result */
  	wake_up_interruptible(&self->query_wait);
  }
  
  /*
   * Function irda_selective_discovery_indication (discovery)
   *
   *    Got a selective discovery indication from IrLMP.
   *
   * IrLMP is telling us that this node is new and matching our hint bit
   * filter. Wake up any process waiting for answer...
   */
  static void irda_selective_discovery_indication(discinfo_t *discovery,
  						DISCOVERY_MODE mode,
  						void *priv)
  {
  	struct irda_sock *self;
ea1107338   Joe Perches   net: Remove casts...
417
  	self = priv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  	if (!self) {
6c91023dc   Joe Perches   irda: Remove IRDA...
419
420
  		net_warn_ratelimited("%s: lost myself!
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
  		return;
  	}
  
  	/* Pass parameter to the caller */
  	self->cachedaddr = discovery->daddr;
  
  	/* Wake up process if its waiting for device to be discovered */
  	wake_up_interruptible(&self->query_wait);
  }
  
  /*
   * Function irda_discovery_timeout (priv)
   *
   *    Timeout in the selective discovery process
   *
   * We were waiting for a node to be discovered, but nothing has come up
   * so far. Wake up the user and tell him that we failed...
   */
  static void irda_discovery_timeout(u_long priv)
  {
  	struct irda_sock *self;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  	self = (struct irda_sock *) priv;
c3ea9fa27   Samuel Ortiz   [IrDA] af_irda: I...
443
  	BUG_ON(self == NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
  
  	/* Nothing for the caller */
  	self->cachelog = NULL;
  	self->cachedaddr = 0;
  	self->errno = -ETIME;
  
  	/* Wake up process if its still waiting... */
  	wake_up_interruptible(&self->query_wait);
  }
  
  /*
   * Function irda_open_tsap (self)
   *
   *    Open local Transport Service Access Point (TSAP)
   *
   */
  static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name)
  {
  	notify_t notify;
  
  	if (self->tsap) {
955a9d202   Joe Perches   irda: Convert IRD...
465
466
  		pr_debug("%s: busy!
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
  		return -EBUSY;
  	}
  
  	/* Initialize callbacks to be used by the IrDA stack */
  	irda_notify_init(&notify);
  	notify.connect_confirm       = irda_connect_confirm;
  	notify.connect_indication    = irda_connect_indication;
  	notify.disconnect_indication = irda_disconnect_indication;
  	notify.data_indication       = irda_data_indication;
  	notify.udata_indication	     = irda_data_indication;
  	notify.flow_indication       = irda_flow_indication;
  	notify.instance = self;
  	strncpy(notify.name, name, NOTIFY_MAX_NAME);
  
  	self->tsap = irttp_open_tsap(tsap_sel, DEFAULT_INITIAL_CREDIT,
  				     &notify);
  	if (self->tsap == NULL) {
955a9d202   Joe Perches   irda: Convert IRD...
484
485
486
  		pr_debug("%s(), Unable to allocate TSAP!
  ",
  			 __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
  		return -ENOMEM;
  	}
  	/* Remember which TSAP selector we actually got */
  	self->stsap_sel = self->tsap->stsap_sel;
  
  	return 0;
  }
  
  /*
   * Function irda_open_lsap (self)
   *
   *    Open local Link Service Access Point (LSAP). Used for opening Ultra
   *    sockets
   */
  #ifdef CONFIG_IRDA_ULTRA
  static int irda_open_lsap(struct irda_sock *self, int pid)
  {
  	notify_t notify;
  
  	if (self->lsap) {
6c91023dc   Joe Perches   irda: Remove IRDA...
507
508
  		net_warn_ratelimited("%s(), busy!
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
512
513
514
515
516
517
518
519
  		return -EBUSY;
  	}
  
  	/* Initialize callbacks to be used by the IrDA stack */
  	irda_notify_init(&notify);
  	notify.udata_indication	= irda_data_indication;
  	notify.instance = self;
  	strncpy(notify.name, "Ultra", NOTIFY_MAX_NAME);
  
  	self->lsap = irlmp_open_lsap(LSAP_CONNLESS, &notify, pid);
  	if (self->lsap == NULL) {
955a9d202   Joe Perches   irda: Convert IRD...
520
521
  		pr_debug("%s(), Unable to allocate LSAP!
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
  		return -ENOMEM;
  	}
  
  	return 0;
  }
  #endif /* CONFIG_IRDA_ULTRA */
  
  /*
   * Function irda_find_lsap_sel (self, name)
   *
   *    Try to lookup LSAP selector in remote LM-IAS
   *
   * Basically, we start a IAP query, and then go to sleep. When the query
   * return, irda_getvalue_confirm will wake us up, and we can examine the
   * result of the query...
   * Note that in some case, the query fail even before we go to sleep,
   * creating some races...
   */
  static int irda_find_lsap_sel(struct irda_sock *self, char *name)
  {
955a9d202   Joe Perches   irda: Convert IRD...
542
543
  	pr_debug("%s(%p, %s)
  ", __func__, self, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  	if (self->iriap) {
6c91023dc   Joe Perches   irda: Remove IRDA...
546
547
548
  		net_warn_ratelimited("%s(): busy with a previous query
  ",
  				     __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  		return -EBUSY;
  	}
  
  	self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
  				 irda_getvalue_confirm);
  	if(self->iriap == NULL)
  		return -ENOMEM;
  
  	/* Treat unexpected wakeup as disconnect */
  	self->errno = -EHOSTUNREACH;
  
  	/* Query remote LM-IAS */
  	iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr,
  				      name, "IrDA:TinyTP:LsapSel");
  
  	/* Wait for answer, if not yet finished (or failed) */
  	if (wait_event_interruptible(self->query_wait, (self->iriap==NULL)))
  		/* Treat signals as disconnect */
  		return -EHOSTUNREACH;
  
  	/* Check what happened */
  	if (self->errno)
  	{
  		/* Requested object/attribute doesn't exist */
  		if((self->errno == IAS_CLASS_UNKNOWN) ||
  		   (self->errno == IAS_ATTRIB_UNKNOWN))
a02cec215   Eric Dumazet   net: return opera...
575
  			return -EADDRNOTAVAIL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  		else
a02cec215   Eric Dumazet   net: return opera...
577
  			return -EHOSTUNREACH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
580
581
582
  	}
  
  	/* Get the remote TSAP selector */
  	switch (self->ias_result->type) {
  	case IAS_INTEGER:
955a9d202   Joe Perches   irda: Convert IRD...
583
584
585
  		pr_debug("%s() int=%d
  ",
  			 __func__, self->ias_result->t.integer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
588
589
590
591
592
593
  
  		if (self->ias_result->t.integer != -1)
  			self->dtsap_sel = self->ias_result->t.integer;
  		else
  			self->dtsap_sel = 0;
  		break;
  	default:
  		self->dtsap_sel = 0;
955a9d202   Joe Perches   irda: Convert IRD...
594
595
  		pr_debug("%s(), bad type!
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
  		break;
  	}
  	if (self->ias_result)
  		irias_delete_value(self->ias_result);
  
  	if (self->dtsap_sel)
  		return 0;
  
  	return -EADDRNOTAVAIL;
  }
  
  /*
   * Function irda_discover_daddr_and_lsap_sel (self, name)
   *
   *    This try to find a device with the requested service.
   *
   * It basically look into the discovery log. For each address in the list,
   * it queries the LM-IAS of the device to find if this device offer
   * the requested service.
   * If there is more than one node supporting the service, we complain
   * to the user (it should move devices around).
   * The, we set both the destination address and the lsap selector to point
   * on the service on the unique device we have found.
   *
   * Note : this function fails if there is more than one device in range,
   * because IrLMP doesn't disconnect the LAP when the last LSAP is closed.
   * Moreover, we would need to wait the LAP disconnection...
   */
  static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
  {
  	discinfo_t *discoveries;	/* Copy of the discovery log */
  	int	number;			/* Number of nodes in the log */
  	int	i;
  	int	err = -ENETUNREACH;
  	__u32	daddr = DEV_ADDR_ANY;	/* Address we found the service on */
  	__u8	dtsap_sel = 0x0;	/* TSAP associated with it */
955a9d202   Joe Perches   irda: Convert IRD...
632
633
  	pr_debug("%s(), name=%s
  ", __func__, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
  	/* Ask lmp for the current discovery log
  	 * Note : we have to use irlmp_get_discoveries(), as opposed
  	 * to play with the cachelog directly, because while we are
  	 * making our ias query, le log might change... */
  	discoveries = irlmp_get_discoveries(&number, self->mask.word,
  					    self->nslots);
  	/* Check if the we got some results */
  	if (discoveries == NULL)
  		return -ENETUNREACH;	/* No nodes discovered */
  
  	/*
  	 * Now, check all discovered devices (if any), and connect
  	 * client only about the services that the client is
  	 * interested in...
  	 */
  	for(i = 0; i < number; i++) {
  		/* Try the address in the log */
  		self->daddr = discoveries[i].daddr;
  		self->saddr = 0x0;
955a9d202   Joe Perches   irda: Convert IRD...
654
655
656
  		pr_debug("%s(), trying daddr = %08x
  ",
  			 __func__, self->daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
658
659
660
661
662
663
  
  		/* Query remote LM-IAS for this service */
  		err = irda_find_lsap_sel(self, name);
  		switch (err) {
  		case 0:
  			/* We found the requested service */
  			if(daddr != DEV_ADDR_ANY) {
955a9d202   Joe Perches   irda: Convert IRD...
664
665
666
  				pr_debug("%s(), discovered service ''%s'' in two different devices !!!
  ",
  					 __func__, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
  				self->daddr = DEV_ADDR_ANY;
  				kfree(discoveries);
a02cec215   Eric Dumazet   net: return opera...
669
  				return -ENOTUNIQ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
673
674
675
676
677
678
679
  			}
  			/* First time we found that one, save it ! */
  			daddr = self->daddr;
  			dtsap_sel = self->dtsap_sel;
  			break;
  		case -EADDRNOTAVAIL:
  			/* Requested service simply doesn't exist on this node */
  			break;
  		default:
  			/* Something bad did happen :-( */
955a9d202   Joe Perches   irda: Convert IRD...
680
681
682
  			pr_debug("%s(), unexpected IAS query failure
  ",
  				 __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
  			self->daddr = DEV_ADDR_ANY;
  			kfree(discoveries);
a02cec215   Eric Dumazet   net: return opera...
685
  			return -EHOSTUNREACH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
689
690
691
692
  		}
  	}
  	/* Cleanup our copy of the discovery log */
  	kfree(discoveries);
  
  	/* Check out what we found */
  	if(daddr == DEV_ADDR_ANY) {
955a9d202   Joe Perches   irda: Convert IRD...
693
694
695
  		pr_debug("%s(), cannot discover service ''%s'' in any device !!!
  ",
  			 __func__, name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
  		self->daddr = DEV_ADDR_ANY;
a02cec215   Eric Dumazet   net: return opera...
697
  		return -EADDRNOTAVAIL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
703
  	}
  
  	/* Revert back to discovered device & service */
  	self->daddr = daddr;
  	self->saddr = 0x0;
  	self->dtsap_sel = dtsap_sel;
955a9d202   Joe Perches   irda: Convert IRD...
704
705
706
  	pr_debug("%s(), discovered requested service ''%s'' at address %08x
  ",
  		 __func__, name, self->daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
  
  	return 0;
  }
  
  /*
   * Function irda_getname (sock, uaddr, uaddr_len, peer)
   *
   *    Return the our own, or peers socket address (sockaddr_irda)
   *
   */
  static int irda_getname(struct socket *sock, struct sockaddr *uaddr,
  			int *uaddr_len, int peer)
  {
  	struct sockaddr_irda saddr;
  	struct sock *sk = sock->sk;
  	struct irda_sock *self = irda_sk(sk);
09384dfc7   Eric Dumazet   irda: Fix irda_ge...
723
  	memset(&saddr, 0, sizeof(saddr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
  	if (peer) {
  		if (sk->sk_state != TCP_ESTABLISHED)
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
726
  			return -ENOTCONN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
729
730
731
732
733
734
735
  
  		saddr.sir_family = AF_IRDA;
  		saddr.sir_lsap_sel = self->dtsap_sel;
  		saddr.sir_addr = self->daddr;
  	} else {
  		saddr.sir_family = AF_IRDA;
  		saddr.sir_lsap_sel = self->stsap_sel;
  		saddr.sir_addr = self->saddr;
  	}
955a9d202   Joe Perches   irda: Convert IRD...
736
737
738
739
  	pr_debug("%s(), tsap_sel = %#x
  ", __func__, saddr.sir_lsap_sel);
  	pr_debug("%s(), addr = %08x
  ", __func__, saddr.sir_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
743
  
  	/* uaddr_len come to us uninitialised */
  	*uaddr_len = sizeof (struct sockaddr_irda);
  	memcpy(uaddr, &saddr, *uaddr_len);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
744
745
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
748
749
750
751
752
753
754
755
756
  }
  
  /*
   * Function irda_listen (sock, backlog)
   *
   *    Just move to the listen state
   *
   */
  static int irda_listen(struct socket *sock, int backlog)
  {
  	struct sock *sk = sock->sk;
58a9d7320   Arnd Bergmann   net/irda: push BK...
757
  	int err = -EOPNOTSUPP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758

5b40964ea   Samuel Ortiz   irda: Remove BKL ...
759
  	lock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
  	if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) &&
  	    (sk->sk_type != SOCK_DGRAM))
58a9d7320   Arnd Bergmann   net/irda: push BK...
762
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
765
766
  
  	if (sk->sk_state != TCP_LISTEN) {
  		sk->sk_max_ack_backlog = backlog;
  		sk->sk_state           = TCP_LISTEN;
58a9d7320   Arnd Bergmann   net/irda: push BK...
767
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  	}
58a9d7320   Arnd Bergmann   net/irda: push BK...
769
  out:
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
770
  	release_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771

58a9d7320   Arnd Bergmann   net/irda: push BK...
772
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
775
776
777
778
779
780
781
782
783
784
785
786
  }
  
  /*
   * Function irda_bind (sock, uaddr, addr_len)
   *
   *    Used by servers to register their well known TSAP
   *
   */
  static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
  {
  	struct sock *sk = sock->sk;
  	struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr;
  	struct irda_sock *self = irda_sk(sk);
  	int err;
955a9d202   Joe Perches   irda: Convert IRD...
787
788
  	pr_debug("%s(%p)
  ", __func__, self);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
790
791
  
  	if (addr_len != sizeof(struct sockaddr_irda))
  		return -EINVAL;
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
792
  	lock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
794
795
796
797
  #ifdef CONFIG_IRDA_ULTRA
  	/* Special care for Ultra sockets */
  	if ((sk->sk_type == SOCK_DGRAM) &&
  	    (sk->sk_protocol == IRDAPROTO_ULTRA)) {
  		self->pid = addr->sir_lsap_sel;
58a9d7320   Arnd Bergmann   net/irda: push BK...
798
  		err = -EOPNOTSUPP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
  		if (self->pid & 0x80) {
955a9d202   Joe Perches   irda: Convert IRD...
800
801
802
  			pr_debug("%s(), extension in PID not supp!
  ",
  				 __func__);
58a9d7320   Arnd Bergmann   net/irda: push BK...
803
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
  		}
  		err = irda_open_lsap(self, self->pid);
  		if (err < 0)
58a9d7320   Arnd Bergmann   net/irda: push BK...
807
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
811
  
  		/* Pretend we are connected */
  		sock->state = SS_CONNECTED;
  		sk->sk_state   = TCP_ESTABLISHED;
58a9d7320   Arnd Bergmann   net/irda: push BK...
812
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813

58a9d7320   Arnd Bergmann   net/irda: push BK...
814
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
  	}
  #endif /* CONFIG_IRDA_ULTRA */
61e44b481   Jesper Juhl   [IrDA]: af_irda m...
817
  	self->ias_obj = irias_new_object(addr->sir_name, jiffies);
58a9d7320   Arnd Bergmann   net/irda: push BK...
818
  	err = -ENOMEM;
61e44b481   Jesper Juhl   [IrDA]: af_irda m...
819
  	if (self->ias_obj == NULL)
58a9d7320   Arnd Bergmann   net/irda: push BK...
820
  		goto out;
61e44b481   Jesper Juhl   [IrDA]: af_irda m...
821

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
  	err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name);
61e44b481   Jesper Juhl   [IrDA]: af_irda m...
823
  	if (err < 0) {
628e300cc   David S. Miller   irda: Correctly c...
824
825
  		irias_delete_object(self->ias_obj);
  		self->ias_obj = NULL;
58a9d7320   Arnd Bergmann   net/irda: push BK...
826
  		goto out;
61e44b481   Jesper Juhl   [IrDA]: af_irda m...
827
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
829
  
  	/*  Register with LM-IAS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830
831
832
  	irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel",
  				 self->stsap_sel, IAS_KERNEL_ATTR);
  	irias_insert_object(self->ias_obj);
58a9d7320   Arnd Bergmann   net/irda: push BK...
833
834
  	err = 0;
  out:
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
835
  	release_sock(sk);
58a9d7320   Arnd Bergmann   net/irda: push BK...
836
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
839
840
841
842
843
844
845
846
847
848
849
  }
  
  /*
   * Function irda_accept (sock, newsock, flags)
   *
   *    Wait for incoming connection
   *
   */
  static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
  {
  	struct sock *sk = sock->sk;
  	struct irda_sock *new, *self = irda_sk(sk);
  	struct sock *newsk;
8ab86c00e   phil.turnbull@oracle.com   irda: Free skb on...
850
  	struct sk_buff *skb = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
  	int err;
3f378b684   Eric Paris   net: pass kern to...
852
  	err = irda_create(sock_net(sk), newsock, sk->sk_protocol, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
  	if (err)
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
854
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855

58a9d7320   Arnd Bergmann   net/irda: push BK...
856
  	err = -EINVAL;
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
857
858
  
  	lock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
  	if (sock->state != SS_UNCONNECTED)
58a9d7320   Arnd Bergmann   net/irda: push BK...
860
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861

58a9d7320   Arnd Bergmann   net/irda: push BK...
862
  	err = -EOPNOTSUPP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
  	if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) &&
  	    (sk->sk_type != SOCK_DGRAM))
58a9d7320   Arnd Bergmann   net/irda: push BK...
865
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866

58a9d7320   Arnd Bergmann   net/irda: push BK...
867
  	err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
  	if (sk->sk_state != TCP_LISTEN)
58a9d7320   Arnd Bergmann   net/irda: push BK...
869
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
871
872
873
874
875
876
877
878
879
880
881
882
883
  
  	/*
  	 *	The read queue this time is holding sockets ready to use
  	 *	hooked into the SABM we saved
  	 */
  
  	/*
  	 * We can perform the accept only if there is incoming data
  	 * on the listening socket.
  	 * So, we will block the caller until we receive any data.
  	 * If the caller was waiting on select() or poll() before
  	 * calling us, the data is waiting for us ;-)
  	 * Jean II
  	 */
d7f48d1a9   Samuel Ortiz   [IrDA] af_irda: i...
884
885
886
887
  	while (1) {
  		skb = skb_dequeue(&sk->sk_receive_queue);
  		if (skb)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
889
  
  		/* Non blocking operation */
58a9d7320   Arnd Bergmann   net/irda: push BK...
890
  		err = -EWOULDBLOCK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
  		if (flags & O_NONBLOCK)
58a9d7320   Arnd Bergmann   net/irda: push BK...
892
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893

aa3951451   Eric Dumazet   net: sk_sleep() h...
894
  		err = wait_event_interruptible(*(sk_sleep(sk)),
d7f48d1a9   Samuel Ortiz   [IrDA] af_irda: i...
895
896
  					skb_peek(&sk->sk_receive_queue));
  		if (err)
58a9d7320   Arnd Bergmann   net/irda: push BK...
897
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
900
  	}
  
  	newsk = newsock->sk;
58a9d7320   Arnd Bergmann   net/irda: push BK...
901
  	err = -EIO;
c3ea9fa27   Samuel Ortiz   [IrDA] af_irda: I...
902
  	if (newsk == NULL)
58a9d7320   Arnd Bergmann   net/irda: push BK...
903
  		goto out;
c3ea9fa27   Samuel Ortiz   [IrDA] af_irda: I...
904

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
906
907
  	newsk->sk_state = TCP_ESTABLISHED;
  
  	new = irda_sk(newsk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
  
  	/* Now attach up the new socket */
  	new->tsap = irttp_dup(self->tsap, new);
58a9d7320   Arnd Bergmann   net/irda: push BK...
911
  	err = -EPERM; /* value does not seem to make sense. -arnd */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  	if (!new->tsap) {
955a9d202   Joe Perches   irda: Convert IRD...
913
914
  		pr_debug("%s(), dup failed!
  ", __func__);
58a9d7320   Arnd Bergmann   net/irda: push BK...
915
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
  	}
  
  	new->stsap_sel = new->tsap->stsap_sel;
  	new->dtsap_sel = new->tsap->dtsap_sel;
  	new->saddr = irttp_get_saddr(new->tsap);
  	new->daddr = irttp_get_daddr(new->tsap);
  
  	new->max_sdu_size_tx = self->max_sdu_size_tx;
  	new->max_sdu_size_rx = self->max_sdu_size_rx;
  	new->max_data_size   = self->max_data_size;
  	new->max_header_size = self->max_header_size;
  
  	memcpy(&new->qos_tx, &self->qos_tx, sizeof(struct qos_info));
  
  	/* Clean up the original one to keep it in listen state */
  	irttp_listen(self->tsap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
935
936
  	sk->sk_ack_backlog--;
  
  	newsock->state = SS_CONNECTED;
  
  	irda_connect_response(new);
58a9d7320   Arnd Bergmann   net/irda: push BK...
937
938
  	err = 0;
  out:
8ab86c00e   phil.turnbull@oracle.com   irda: Free skb on...
939
  	kfree_skb(skb);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
940
  	release_sock(sk);
58a9d7320   Arnd Bergmann   net/irda: push BK...
941
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
943
944
945
946
947
948
949
950
951
  }
  
  /*
   * Function irda_connect (sock, uaddr, addr_len, flags)
   *
   *    Connect to a IrDA device
   *
   * The main difference with a "standard" connect is that with IrDA we need
   * to resolve the service name into a TSAP selector (in TCP, port number
   * doesn't have to be resolved).
ad8c94532   Masanari Iida   irda: Fix typo in...
952
   * Because of this service name resolution, we can offer "auto-connect",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
   * where we connect to a service without specifying a destination address.
   *
   * Note : by consulting "errno", the user space caller may learn the cause
   * of the failure. Most of them are visible in the function, others may come
   * from subroutines called and are listed here :
   *	o EBUSY : already processing a connect
   *	o EHOSTUNREACH : bad addr->sir_addr argument
   *	o EADDRNOTAVAIL : bad addr->sir_name argument
   *	o ENOTUNIQ : more than one node has addr->sir_name (auto-connect)
   *	o ENETUNREACH : no node found on the network (auto-connect)
   */
  static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
  			int addr_len, int flags)
  {
  	struct sock *sk = sock->sk;
  	struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr;
  	struct irda_sock *self = irda_sk(sk);
  	int err;
955a9d202   Joe Perches   irda: Convert IRD...
971
972
  	pr_debug("%s(%p)
  ", __func__, self);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
973

5b40964ea   Samuel Ortiz   irda: Remove BKL ...
974
  	lock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
  	/* Don't allow connect for Ultra sockets */
58a9d7320   Arnd Bergmann   net/irda: push BK...
976
  	err = -ESOCKTNOSUPPORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
  	if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA))
58a9d7320   Arnd Bergmann   net/irda: push BK...
978
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
980
981
  
  	if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
  		sock->state = SS_CONNECTED;
58a9d7320   Arnd Bergmann   net/irda: push BK...
982
983
  		err = 0;
  		goto out;   /* Connect completed during a ERESTARTSYS event */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
985
986
987
  	}
  
  	if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {
  		sock->state = SS_UNCONNECTED;
58a9d7320   Arnd Bergmann   net/irda: push BK...
988
989
  		err = -ECONNREFUSED;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
  	}
58a9d7320   Arnd Bergmann   net/irda: push BK...
991
  	err = -EISCONN;      /* No reconnect on a seqpacket socket */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
  	if (sk->sk_state == TCP_ESTABLISHED)
58a9d7320   Arnd Bergmann   net/irda: push BK...
993
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
995
996
  
  	sk->sk_state   = TCP_CLOSE;
  	sock->state = SS_UNCONNECTED;
58a9d7320   Arnd Bergmann   net/irda: push BK...
997
  	err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
  	if (addr_len != sizeof(struct sockaddr_irda))
58a9d7320   Arnd Bergmann   net/irda: push BK...
999
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
1001
1002
1003
1004
1005
  
  	/* Check if user supplied any destination device address */
  	if ((!addr->sir_addr) || (addr->sir_addr == DEV_ADDR_ANY)) {
  		/* Try to find one suitable */
  		err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name);
  		if (err) {
955a9d202   Joe Perches   irda: Convert IRD...
1006
1007
  			pr_debug("%s(), auto-connect failed!
  ", __func__);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1008
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
1010
1011
1012
  		}
  	} else {
  		/* Use the one provided by the user */
  		self->daddr = addr->sir_addr;
955a9d202   Joe Perches   irda: Convert IRD...
1013
1014
  		pr_debug("%s(), daddr = %08x
  ", __func__, self->daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
1016
1017
1018
1019
1020
1021
1022
1023
  
  		/* If we don't have a valid service name, we assume the
  		 * user want to connect on a specific LSAP. Prevent
  		 * the use of invalid LSAPs (IrLMP 1.1 p10). Jean II */
  		if((addr->sir_name[0] != '\0') ||
  		   (addr->sir_lsap_sel >= 0x70)) {
  			/* Query remote LM-IAS using service name */
  			err = irda_find_lsap_sel(self, addr->sir_name);
  			if (err) {
955a9d202   Joe Perches   irda: Convert IRD...
1024
1025
  				pr_debug("%s(), connect failed!
  ", __func__);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1026
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
  			}
  		} else {
  			/* Directly connect to the remote LSAP
  			 * specified by the sir_lsap field.
  			 * Please use with caution, in IrDA LSAPs are
  			 * dynamic and there is no "well-known" LSAP. */
  			self->dtsap_sel = addr->sir_lsap_sel;
  		}
  	}
  
  	/* Check if we have opened a local TSAP */
d3e6952cf   Vegard Nossum   net/irda: fix NUL...
1038
1039
1040
1041
1042
  	if (!self->tsap) {
  		err = irda_open_tsap(self, LSAP_ANY, addr->sir_name);
  		if (err)
  			goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
  
  	/* Move to connecting socket, start sending Connect Requests */
  	sock->state = SS_CONNECTING;
  	sk->sk_state   = TCP_SYN_SENT;
  
  	/* Connect to remote device */
  	err = irttp_connect_request(self->tsap, self->dtsap_sel,
  				    self->saddr, self->daddr, NULL,
  				    self->max_sdu_size_rx, NULL);
  	if (err) {
955a9d202   Joe Perches   irda: Convert IRD...
1053
1054
  		pr_debug("%s(), connect failed!
  ", __func__);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1055
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056
1057
1058
  	}
  
  	/* Now the loop */
58a9d7320   Arnd Bergmann   net/irda: push BK...
1059
  	err = -EINPROGRESS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
  	if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
58a9d7320   Arnd Bergmann   net/irda: push BK...
1061
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062

58a9d7320   Arnd Bergmann   net/irda: push BK...
1063
  	err = -ERESTARTSYS;
aa3951451   Eric Dumazet   net: sk_sleep() h...
1064
  	if (wait_event_interruptible(*(sk_sleep(sk)),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
  				     (sk->sk_state != TCP_SYN_SENT)))
58a9d7320   Arnd Bergmann   net/irda: push BK...
1066
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
1069
  
  	if (sk->sk_state != TCP_ESTABLISHED) {
  		sock->state = SS_UNCONNECTED;
6e66aa15d   Olaf Kirch   [IrDA] af_irda: S...
1070
  		err = sock_error(sk);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1071
1072
1073
  		if (!err)
  			err = -ECONNRESET;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1074
1075
1076
1077
1078
1079
  	}
  
  	sock->state = SS_CONNECTED;
  
  	/* At this point, IrLMP has assigned our source address */
  	self->saddr = irttp_get_saddr(self->tsap);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1080
1081
  	err = 0;
  out:
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1082
  	release_sock(sk);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1083
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
  }
  
  static struct proto irda_proto = {
  	.name	  = "IRDA",
  	.owner	  = THIS_MODULE,
  	.obj_size = sizeof(struct irda_sock),
  };
  
  /*
   * Function irda_create (sock, protocol)
   *
   *    Create IrDA socket
   *
   */
3f378b684   Eric Paris   net: pass kern to...
1098
1099
  static int irda_create(struct net *net, struct socket *sock, int protocol,
  		       int kern)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
1101
1102
  {
  	struct sock *sk;
  	struct irda_sock *self;
79462ad02   Hannes Frederic Sowa   net: add validati...
1103
1104
  	if (protocol < 0 || protocol > SK_PROTOCOL_MAX)
  		return -EINVAL;
1b8d7ae42   Eric W. Biederman   [NET]: Make socke...
1105
1106
  	if (net != &init_net)
  		return -EAFNOSUPPORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
  	/* Check for valid socket type */
  	switch (sock->type) {
  	case SOCK_STREAM:     /* For TTP connections with SAR disabled */
  	case SOCK_SEQPACKET:  /* For TTP connections with SAR enabled */
  	case SOCK_DGRAM:      /* For TTP Unitdata or LMP Ultra transfers */
  		break;
  	default:
  		return -ESOCKTNOSUPPORT;
  	}
  
  	/* Allocate networking socket */
11aa9c28b   Eric W. Biederman   net: Pass kern fr...
1118
  	sk = sk_alloc(net, PF_IRDA, GFP_KERNEL, &irda_proto, kern);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
1120
1121
1122
  	if (sk == NULL)
  		return -ENOMEM;
  
  	self = irda_sk(sk);
955a9d202   Joe Perches   irda: Convert IRD...
1123
1124
  	pr_debug("%s() : self is %p
  ", __func__, self);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1125
1126
  
  	init_waitqueue_head(&self->query_wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
  	switch (sock->type) {
  	case SOCK_STREAM:
  		sock->ops = &irda_stream_ops;
  		self->max_sdu_size_rx = TTP_SAR_DISABLE;
  		break;
  	case SOCK_SEQPACKET:
  		sock->ops = &irda_seqpacket_ops;
  		self->max_sdu_size_rx = TTP_SAR_UNBOUND;
  		break;
  	case SOCK_DGRAM:
  		switch (protocol) {
  #ifdef CONFIG_IRDA_ULTRA
  		case IRDAPROTO_ULTRA:
  			sock->ops = &irda_ultra_ops;
  			/* Initialise now, because we may send on unbound
  			 * sockets. Jean II */
  			self->max_data_size = ULTRA_MAX_DATA - LMP_PID_HEADER;
  			self->max_header_size = IRDA_MAX_HEADER + LMP_PID_HEADER;
  			break;
  #endif /* CONFIG_IRDA_ULTRA */
  		case IRDAPROTO_UNITDATA:
  			sock->ops = &irda_dgram_ops;
  			/* We let Unitdata conn. be like seqpack conn. */
  			self->max_sdu_size_rx = TTP_SAR_UNBOUND;
  			break;
  		default:
9ecad8779   Pavel Emelyanov   irda: Sock leak o...
1153
  			sk_free(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
1155
1156
1157
  			return -ESOCKTNOSUPPORT;
  		}
  		break;
  	default:
9ecad8779   Pavel Emelyanov   irda: Sock leak o...
1158
  		sk_free(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
1160
  		return -ESOCKTNOSUPPORT;
  	}
9ecad8779   Pavel Emelyanov   irda: Sock leak o...
1161
1162
1163
1164
  	/* Initialise networking socket struct */
  	sock_init_data(sock, sk);	/* Note : set sk->sk_refcnt to 1 */
  	sk->sk_family = PF_IRDA;
  	sk->sk_protocol = protocol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
  	/* Register as a client with IrLMP */
  	self->ckey = irlmp_register_client(0, NULL, NULL, NULL);
  	self->mask.word = 0xffff;
  	self->rx_flow = self->tx_flow = FLOW_START;
  	self->nslots = DISCOVERY_DEFAULT_SLOTS;
  	self->daddr = DEV_ADDR_ANY;	/* Until we get connected */
  	self->saddr = 0x0;		/* so IrLMP assign us any link */
  	return 0;
  }
  
  /*
   * Function irda_destroy_socket (self)
   *
   *    Destroy socket
   *
   */
  static void irda_destroy_socket(struct irda_sock *self)
  {
955a9d202   Joe Perches   irda: Convert IRD...
1183
1184
  	pr_debug("%s(%p)
  ", __func__, self);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
  	/* Unregister with IrLMP */
  	irlmp_unregister_client(self->ckey);
  	irlmp_unregister_service(self->skey);
  
  	/* Unregister with LM-IAS */
  	if (self->ias_obj) {
  		irias_delete_object(self->ias_obj);
  		self->ias_obj = NULL;
  	}
  
  	if (self->iriap) {
  		iriap_close(self->iriap);
  		self->iriap = NULL;
  	}
  
  	if (self->tsap) {
  		irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
  		irttp_close_tsap(self->tsap);
  		self->tsap = NULL;
  	}
  #ifdef CONFIG_IRDA_ULTRA
  	if (self->lsap) {
  		irlmp_close_lsap(self->lsap);
  		self->lsap = NULL;
  	}
  #endif /* CONFIG_IRDA_ULTRA */
  }
  
  /*
   * Function irda_release (sock)
   */
  static int irda_release(struct socket *sock)
  {
  	struct sock *sk = sock->sk;
6819bc2e1   YOSHIFUJI Hideaki   [NET] IRDA: Fix w...
1220
  	if (sk == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
  		return 0;
da349f1c2   Samuel Ortiz   [IrDA]: af_irda.c...
1222
  	lock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223
1224
1225
1226
1227
1228
1229
1230
1231
  	sk->sk_state       = TCP_CLOSE;
  	sk->sk_shutdown   |= SEND_SHUTDOWN;
  	sk->sk_state_change(sk);
  
  	/* Destroy IrDA socket */
  	irda_destroy_socket(irda_sk(sk));
  
  	sock_orphan(sk);
  	sock->sk   = NULL;
da349f1c2   Samuel Ortiz   [IrDA]: af_irda.c...
1232
  	release_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
  
  	/* Purge queues (see sock_init_data()) */
  	skb_queue_purge(&sk->sk_receive_queue);
  
  	/* Destroy networking socket if we are the last reference on it,
  	 * i.e. if(sk->sk_refcnt == 0) -> sk_free(sk) */
  	sock_put(sk);
  
  	/* Notes on socket locking and deallocation... - Jean II
  	 * In theory we should put pairs of sock_hold() / sock_put() to
  	 * prevent the socket to be destroyed whenever there is an
  	 * outstanding request or outstanding incoming packet or event.
  	 *
  	 * 1) This may include IAS request, both in connect and getsockopt.
  	 * Unfortunately, the situation is a bit more messy than it looks,
  	 * because we close iriap and kfree(self) above.
  	 *
  	 * 2) This may include selective discovery in getsockopt.
  	 * Same stuff as above, irlmp registration and self are gone.
  	 *
  	 * Probably 1 and 2 may not matter, because it's all triggered
  	 * by a process and the socket layer already prevent the
  	 * socket to go away while a process is holding it, through
  	 * sockfd_put() and fput()...
  	 *
  	 * 3) This may include deferred TSAP closure. In particular,
  	 * we may receive a late irda_disconnect_indication()
  	 * Fortunately, (tsap_cb *)->close_pend should protect us
  	 * from that.
  	 *
  	 * I did some testing on SMP, and it looks solid. And the socket
  	 * memory leak is now gone... - Jean II
  	 */
6819bc2e1   YOSHIFUJI Hideaki   [NET] IRDA: Fix w...
1266
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
1268
1269
  }
  
  /*
1b7841404   Ying Xue   net: Remove iocb ...
1270
   * Function irda_sendmsg (sock, msg, len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271
1272
1273
1274
1275
   *
   *    Send message down to TinyTP. This function is used for both STREAM and
   *    SEQPACK services. This is possible since it forces the client to
   *    fragment the message if necessary
   */
1b7841404   Ying Xue   net: Remove iocb ...
1276
  static int irda_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1277
1278
1279
1280
  {
  	struct sock *sk = sock->sk;
  	struct irda_sock *self;
  	struct sk_buff *skb;
bcb5e0eef   Samuel Ortiz   [IrDA]: MSG_NOSIG...
1281
  	int err = -EPIPE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282

955a9d202   Joe Perches   irda: Convert IRD...
1283
1284
  	pr_debug("%s(), len=%zd
  ", __func__, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
1286
  
  	/* Note : socket.c set MSG_EOR on SEQPACKET sockets */
bcb5e0eef   Samuel Ortiz   [IrDA]: MSG_NOSIG...
1287
  	if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT |
58a9d7320   Arnd Bergmann   net/irda: push BK...
1288
  			       MSG_NOSIGNAL)) {
020318d0d   Dave Jones   irda: fix locking...
1289
  		return -EINVAL;
58a9d7320   Arnd Bergmann   net/irda: push BK...
1290
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1291

5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1292
  	lock_sock(sk);
bcb5e0eef   Samuel Ortiz   [IrDA]: MSG_NOSIG...
1293
1294
  	if (sk->sk_shutdown & SEND_SHUTDOWN)
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1295

58a9d7320   Arnd Bergmann   net/irda: push BK...
1296
1297
1298
1299
  	if (sk->sk_state != TCP_ESTABLISHED) {
  		err = -ENOTCONN;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1300
1301
  
  	self = irda_sk(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302
1303
  
  	/* Check if IrTTP is wants us to slow down */
aa3951451   Eric Dumazet   net: sk_sleep() h...
1304
  	if (wait_event_interruptible(*(sk_sleep(sk)),
58a9d7320   Arnd Bergmann   net/irda: push BK...
1305
1306
1307
1308
  	    (self->tx_flow != FLOW_STOP  ||  sk->sk_state != TCP_ESTABLISHED))) {
  		err = -ERESTARTSYS;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1309
1310
  
  	/* Check if we are still connected */
58a9d7320   Arnd Bergmann   net/irda: push BK...
1311
1312
1313
1314
  	if (sk->sk_state != TCP_ESTABLISHED) {
  		err = -ENOTCONN;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1315

7f927fcc2   Alexey Dobriyan   [PATCH] Typo fixes
1316
  	/* Check that we don't send out too big frames */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317
  	if (len > self->max_data_size) {
955a9d202   Joe Perches   irda: Convert IRD...
1318
1319
1320
  		pr_debug("%s(), Chopping frame from %zd to %d bytes!
  ",
  			 __func__, len, self->max_data_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321
1322
  		len = self->max_data_size;
  	}
6819bc2e1   YOSHIFUJI Hideaki   [NET] IRDA: Fix w...
1323
  	skb = sock_alloc_send_skb(sk, len + self->max_header_size + 16,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1324
1325
  				  msg->msg_flags & MSG_DONTWAIT, &err);
  	if (!skb)
bcb5e0eef   Samuel Ortiz   [IrDA]: MSG_NOSIG...
1326
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327
1328
  
  	skb_reserve(skb, self->max_header_size + 16);
eeeb03745   Arnaldo Carvalho de Melo   [SK_BUFF]: More s...
1329
1330
  	skb_reset_transport_header(skb);
  	skb_put(skb, len);
6ce8e9ce5   Al Viro   new helper: memcp...
1331
  	err = memcpy_from_msg(skb_transport_header(skb), msg, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1332
1333
  	if (err) {
  		kfree_skb(skb);
bcb5e0eef   Samuel Ortiz   [IrDA]: MSG_NOSIG...
1334
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
1336
1337
1338
1339
1340
1341
1342
  	}
  
  	/*
  	 * Just send the message to TinyTP, and let it deal with possible
  	 * errors. No need to duplicate all that here
  	 */
  	err = irttp_data_request(self->tsap, skb);
  	if (err) {
955a9d202   Joe Perches   irda: Convert IRD...
1343
1344
  		pr_debug("%s(), err=%d
  ", __func__, err);
bcb5e0eef   Samuel Ortiz   [IrDA]: MSG_NOSIG...
1345
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1346
  	}
58a9d7320   Arnd Bergmann   net/irda: push BK...
1347

5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1348
  	release_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349
1350
  	/* Tell client how much data we actually sent */
  	return len;
bcb5e0eef   Samuel Ortiz   [IrDA]: MSG_NOSIG...
1351

58a9d7320   Arnd Bergmann   net/irda: push BK...
1352
1353
1354
  out_err:
  	err = sk_stream_error(sk, msg->msg_flags, err);
  out:
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1355
  	release_sock(sk);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1356
  	return err;
bcb5e0eef   Samuel Ortiz   [IrDA]: MSG_NOSIG...
1357

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
1359
1360
  }
  
  /*
1b7841404   Ying Xue   net: Remove iocb ...
1361
   * Function irda_recvmsg_dgram (sock, msg, size, flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
1363
1364
1365
   *
   *    Try to receive message and copy it to user. The frame is discarded
   *    after being read, regardless of how much the user actually read
   */
1b7841404   Ying Xue   net: Remove iocb ...
1366
1367
  static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg,
  			      size_t size, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1368
1369
1370
1371
1372
1373
  {
  	struct sock *sk = sock->sk;
  	struct irda_sock *self = irda_sk(sk);
  	struct sk_buff *skb;
  	size_t copied;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
1375
1376
  	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
  				flags & MSG_DONTWAIT, &err);
  	if (!skb)
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1377
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378

badff6d01   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1379
1380
  	skb_reset_transport_header(skb);
  	copied = skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1381
1382
  
  	if (copied > size) {
955a9d202   Joe Perches   irda: Convert IRD...
1383
1384
1385
  		pr_debug("%s(), Received truncated frame (%zd < %zd)!
  ",
  			 __func__, copied, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1386
1387
1388
  		copied = size;
  		msg->msg_flags |= MSG_TRUNC;
  	}
51f3d02b9   David S. Miller   net: Add and use ...
1389
  	skb_copy_datagram_msg(skb, 0, msg, copied);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
  
  	skb_free_datagram(sk, skb);
  
  	/*
  	 *  Check if we have previously stopped IrTTP and we know
  	 *  have more free space in our rx_queue. If so tell IrTTP
  	 *  to start delivering frames again before our rx_queue gets
  	 *  empty
  	 */
  	if (self->rx_flow == FLOW_STOP) {
  		if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) {
955a9d202   Joe Perches   irda: Convert IRD...
1401
1402
  			pr_debug("%s(), Starting IrTTP
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
1404
1405
1406
  			self->rx_flow = FLOW_START;
  			irttp_flow_request(self->tsap, FLOW_START);
  		}
  	}
58a9d7320   Arnd Bergmann   net/irda: push BK...
1407

5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1408
  	return copied;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
1410
1411
  }
  
  /*
1b7841404   Ying Xue   net: Remove iocb ...
1412
   * Function irda_recvmsg_stream (sock, msg, size, flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1413
   */
1b7841404   Ying Xue   net: Remove iocb ...
1414
1415
  static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg,
  			       size_t size, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1416
1417
1418
1419
1420
  {
  	struct sock *sk = sock->sk;
  	struct irda_sock *self = irda_sk(sk);
  	int noblock = flags & MSG_DONTWAIT;
  	size_t copied = 0;
6e66aa15d   Olaf Kirch   [IrDA] af_irda: S...
1421
  	int target, err;
305f2aa18   Olaf Kirch   [IrDA] af_irda: i...
1422
  	long timeo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1423

6e66aa15d   Olaf Kirch   [IrDA] af_irda: S...
1424
  	if ((err = sock_error(sk)) < 0)
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1425
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1426
1427
  
  	if (sock->flags & __SO_ACCEPTCON)
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1428
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1429

58a9d7320   Arnd Bergmann   net/irda: push BK...
1430
  	err =-EOPNOTSUPP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
  	if (flags & MSG_OOB)
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1432
  		return -EOPNOTSUPP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1433

58a9d7320   Arnd Bergmann   net/irda: push BK...
1434
  	err = 0;
305f2aa18   Olaf Kirch   [IrDA] af_irda: i...
1435
1436
  	target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
  	timeo = sock_rcvtimeo(sk, noblock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1437

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1438
1439
1440
  	do {
  		int chunk;
  		struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue);
305f2aa18   Olaf Kirch   [IrDA] af_irda: i...
1441
1442
  		if (skb == NULL) {
  			DEFINE_WAIT(wait);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1443
  			err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1444
1445
1446
  
  			if (copied >= target)
  				break;
aa3951451   Eric Dumazet   net: sk_sleep() h...
1447
  			prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1448
1449
1450
1451
  
  			/*
  			 *	POSIX 1003.1g mandates this order.
  			 */
58a9d7320   Arnd Bergmann   net/irda: push BK...
1452
1453
  			err = sock_error(sk);
  			if (err)
bfb6709d0   Olaf Kirch   [IrDA]: Correctly...
1454
  				;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1455
1456
1457
  			else if (sk->sk_shutdown & RCV_SHUTDOWN)
  				;
  			else if (noblock)
58a9d7320   Arnd Bergmann   net/irda: push BK...
1458
  				err = -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1459
  			else if (signal_pending(current))
58a9d7320   Arnd Bergmann   net/irda: push BK...
1460
  				err = sock_intr_errno(timeo);
305f2aa18   Olaf Kirch   [IrDA] af_irda: i...
1461
  			else if (sk->sk_state != TCP_ESTABLISHED)
58a9d7320   Arnd Bergmann   net/irda: push BK...
1462
  				err = -ENOTCONN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1463
1464
1465
  			else if (skb_peek(&sk->sk_receive_queue) == NULL)
  				/* Wait process until data arrives */
  				schedule();
aa3951451   Eric Dumazet   net: sk_sleep() h...
1466
  			finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1467

58a9d7320   Arnd Bergmann   net/irda: push BK...
1468
  			if (err)
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1469
  				return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1470
1471
1472
1473
1474
1475
1476
  			if (sk->sk_shutdown & RCV_SHUTDOWN)
  				break;
  
  			continue;
  		}
  
  		chunk = min_t(unsigned int, skb->len, size);
7eab8d9e8   Al Viro   new helper: memcp...
1477
  		if (memcpy_to_msg(msg, skb->data, chunk)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
  			skb_queue_head(&sk->sk_receive_queue, skb);
  			if (copied == 0)
  				copied = -EFAULT;
  			break;
  		}
  		copied += chunk;
  		size -= chunk;
  
  		/* Mark read part of skb as used */
  		if (!(flags & MSG_PEEK)) {
  			skb_pull(skb, chunk);
  
  			/* put the skb back if we didn't use it up.. */
  			if (skb->len) {
955a9d202   Joe Perches   irda: Convert IRD...
1492
1493
1494
  				pr_debug("%s(), back on q!
  ",
  					 __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1495
1496
1497
1498
1499
1500
  				skb_queue_head(&sk->sk_receive_queue, skb);
  				break;
  			}
  
  			kfree_skb(skb);
  		} else {
955a9d202   Joe Perches   irda: Convert IRD...
1501
1502
  			pr_debug("%s() questionable!?
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
  
  			/* put message back and return */
  			skb_queue_head(&sk->sk_receive_queue, skb);
  			break;
  		}
  	} while (size);
  
  	/*
  	 *  Check if we have previously stopped IrTTP and we know
  	 *  have more free space in our rx_queue. If so tell IrTTP
  	 *  to start delivering frames again before our rx_queue gets
  	 *  empty
  	 */
  	if (self->rx_flow == FLOW_STOP) {
  		if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) {
955a9d202   Joe Perches   irda: Convert IRD...
1518
1519
  			pr_debug("%s(), Starting IrTTP
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1520
1521
1522
1523
  			self->rx_flow = FLOW_START;
  			irttp_flow_request(self->tsap, FLOW_START);
  		}
  	}
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1524
  	return copied;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1525
1526
1527
  }
  
  /*
1b7841404   Ying Xue   net: Remove iocb ...
1528
   * Function irda_sendmsg_dgram (sock, msg, len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1529
1530
1531
1532
1533
   *
   *    Send message down to TinyTP for the unreliable sequenced
   *    packet service...
   *
   */
1b7841404   Ying Xue   net: Remove iocb ...
1534
1535
  static int irda_sendmsg_dgram(struct socket *sock, struct msghdr *msg,
  			      size_t len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1536
1537
1538
1539
  {
  	struct sock *sk = sock->sk;
  	struct irda_sock *self;
  	struct sk_buff *skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1540
  	int err;
955a9d202   Joe Perches   irda: Convert IRD...
1541
1542
  	pr_debug("%s(), len=%zd
  ", __func__, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1543
1544
  
  	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1545
1546
1547
  		return -EINVAL;
  
  	lock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1548
1549
1550
  
  	if (sk->sk_shutdown & SEND_SHUTDOWN) {
  		send_sig(SIGPIPE, current, 0);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1551
1552
  		err = -EPIPE;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1553
  	}
58a9d7320   Arnd Bergmann   net/irda: push BK...
1554
  	err = -ENOTCONN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1555
  	if (sk->sk_state != TCP_ESTABLISHED)
58a9d7320   Arnd Bergmann   net/irda: push BK...
1556
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1557
1558
  
  	self = irda_sk(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
1560
  
  	/*
7f927fcc2   Alexey Dobriyan   [PATCH] Typo fixes
1561
  	 * Check that we don't send out too big frames. This is an unreliable
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1562
1563
1564
  	 * service, so we have no fragmentation and no coalescence
  	 */
  	if (len > self->max_data_size) {
955a9d202   Joe Perches   irda: Convert IRD...
1565
1566
1567
  		pr_debug("%s(), Warning too much data! Chopping frame from %zd to %d bytes!
  ",
  			 __func__, len, self->max_data_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1568
1569
1570
1571
1572
  		len = self->max_data_size;
  	}
  
  	skb = sock_alloc_send_skb(sk, len + self->max_header_size,
  				  msg->msg_flags & MSG_DONTWAIT, &err);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1573
  	err = -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1574
  	if (!skb)
58a9d7320   Arnd Bergmann   net/irda: push BK...
1575
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1576
1577
  
  	skb_reserve(skb, self->max_header_size);
eeeb03745   Arnaldo Carvalho de Melo   [SK_BUFF]: More s...
1578
  	skb_reset_transport_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1579

955a9d202   Joe Perches   irda: Convert IRD...
1580
1581
  	pr_debug("%s(), appending user data
  ", __func__);
eeeb03745   Arnaldo Carvalho de Melo   [SK_BUFF]: More s...
1582
  	skb_put(skb, len);
6ce8e9ce5   Al Viro   new helper: memcp...
1583
  	err = memcpy_from_msg(skb_transport_header(skb), msg, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1584
1585
  	if (err) {
  		kfree_skb(skb);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1586
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1587
1588
1589
1590
1591
1592
1593
1594
  	}
  
  	/*
  	 * Just send the message to TinyTP, and let it deal with possible
  	 * errors. No need to duplicate all that here
  	 */
  	err = irttp_udata_request(self->tsap, skb);
  	if (err) {
955a9d202   Joe Perches   irda: Convert IRD...
1595
1596
  		pr_debug("%s(), err=%d
  ", __func__, err);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1597
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1598
  	}
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1599
1600
  
  	release_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1601
  	return len;
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1602

58a9d7320   Arnd Bergmann   net/irda: push BK...
1603
  out:
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1604
  	release_sock(sk);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1605
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1606
1607
1608
  }
  
  /*
1b7841404   Ying Xue   net: Remove iocb ...
1609
   * Function irda_sendmsg_ultra (sock, msg, len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1610
1611
1612
1613
1614
   *
   *    Send message down to IrLMP for the unreliable Ultra
   *    packet service...
   */
  #ifdef CONFIG_IRDA_ULTRA
1b7841404   Ying Xue   net: Remove iocb ...
1615
1616
  static int irda_sendmsg_ultra(struct socket *sock, struct msghdr *msg,
  			      size_t len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1617
1618
1619
1620
1621
1622
  {
  	struct sock *sk = sock->sk;
  	struct irda_sock *self;
  	__u8 pid = 0;
  	int bound = 0;
  	struct sk_buff *skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1623
  	int err;
955a9d202   Joe Perches   irda: Convert IRD...
1624
1625
  	pr_debug("%s(), len=%zd
  ", __func__, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1626

58a9d7320   Arnd Bergmann   net/irda: push BK...
1627
  	err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1628
  	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1629
1630
1631
  		return -EINVAL;
  
  	lock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1632

58a9d7320   Arnd Bergmann   net/irda: push BK...
1633
  	err = -EPIPE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1634
1635
  	if (sk->sk_shutdown & SEND_SHUTDOWN) {
  		send_sig(SIGPIPE, current, 0);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1636
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1637
1638
1639
  	}
  
  	self = irda_sk(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1640
1641
1642
  
  	/* Check if an address was specified with sendto. Jean II */
  	if (msg->msg_name) {
342dfc306   Steffen Hurrle   net: add build-ti...
1643
  		DECLARE_SOCKADDR(struct sockaddr_irda *, addr, msg->msg_name);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1644
  		err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1645
1646
  		/* Check address, extract pid. Jean II */
  		if (msg->msg_namelen < sizeof(*addr))
58a9d7320   Arnd Bergmann   net/irda: push BK...
1647
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1648
  		if (addr->sir_family != AF_IRDA)
58a9d7320   Arnd Bergmann   net/irda: push BK...
1649
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1650
1651
1652
  
  		pid = addr->sir_lsap_sel;
  		if (pid & 0x80) {
955a9d202   Joe Perches   irda: Convert IRD...
1653
1654
1655
  			pr_debug("%s(), extension in PID not supp!
  ",
  				 __func__);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1656
1657
  			err = -EOPNOTSUPP;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1658
1659
1660
1661
1662
1663
  		}
  	} else {
  		/* Check that the socket is properly bound to an Ultra
  		 * port. Jean II */
  		if ((self->lsap == NULL) ||
  		    (sk->sk_state != TCP_ESTABLISHED)) {
955a9d202   Joe Perches   irda: Convert IRD...
1664
1665
1666
  			pr_debug("%s(), socket not bound to Ultra PID.
  ",
  				 __func__);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1667
1668
  			err = -ENOTCONN;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1669
1670
1671
1672
1673
1674
  		}
  		/* Use PID from socket */
  		bound = 1;
  	}
  
  	/*
7f927fcc2   Alexey Dobriyan   [PATCH] Typo fixes
1675
  	 * Check that we don't send out too big frames. This is an unreliable
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1676
1677
1678
  	 * service, so we have no fragmentation and no coalescence
  	 */
  	if (len > self->max_data_size) {
955a9d202   Joe Perches   irda: Convert IRD...
1679
1680
1681
  		pr_debug("%s(), Warning too much data! Chopping frame from %zd to %d bytes!
  ",
  			 __func__, len, self->max_data_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1682
1683
1684
1685
1686
  		len = self->max_data_size;
  	}
  
  	skb = sock_alloc_send_skb(sk, len + self->max_header_size,
  				  msg->msg_flags & MSG_DONTWAIT, &err);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1687
  	err = -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688
  	if (!skb)
58a9d7320   Arnd Bergmann   net/irda: push BK...
1689
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1690
1691
  
  	skb_reserve(skb, self->max_header_size);
eeeb03745   Arnaldo Carvalho de Melo   [SK_BUFF]: More s...
1692
  	skb_reset_transport_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1693

955a9d202   Joe Perches   irda: Convert IRD...
1694
1695
  	pr_debug("%s(), appending user data
  ", __func__);
eeeb03745   Arnaldo Carvalho de Melo   [SK_BUFF]: More s...
1696
  	skb_put(skb, len);
6ce8e9ce5   Al Viro   new helper: memcp...
1697
  	err = memcpy_from_msg(skb_transport_header(skb), msg, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1698
1699
  	if (err) {
  		kfree_skb(skb);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1700
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1701
1702
1703
1704
  	}
  
  	err = irlmp_connless_data_request((bound ? self->lsap : NULL),
  					  skb, pid);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1705
  	if (err)
955a9d202   Joe Perches   irda: Convert IRD...
1706
1707
  		pr_debug("%s(), err=%d
  ", __func__, err);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1708
  out:
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1709
  	release_sock(sk);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1710
  	return err ? : len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
  }
  #endif /* CONFIG_IRDA_ULTRA */
  
  /*
   * Function irda_shutdown (sk, how)
   */
  static int irda_shutdown(struct socket *sock, int how)
  {
  	struct sock *sk = sock->sk;
  	struct irda_sock *self = irda_sk(sk);
955a9d202   Joe Perches   irda: Convert IRD...
1721
1722
  	pr_debug("%s(%p)
  ", __func__, self);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1723

5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1724
  	lock_sock(sk);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1725

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
  	sk->sk_state       = TCP_CLOSE;
  	sk->sk_shutdown   |= SEND_SHUTDOWN;
  	sk->sk_state_change(sk);
  
  	if (self->iriap) {
  		iriap_close(self->iriap);
  		self->iriap = NULL;
  	}
  
  	if (self->tsap) {
  		irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
  		irttp_close_tsap(self->tsap);
  		self->tsap = NULL;
  	}
  
  	/* A few cleanup so the socket look as good as new... */
  	self->rx_flow = self->tx_flow = FLOW_START;	/* needed ??? */
  	self->daddr = DEV_ADDR_ANY;	/* Until we get re-connected */
  	self->saddr = 0x0;		/* so IrLMP assign us any link */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1745
  	release_sock(sk);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1746

6819bc2e1   YOSHIFUJI Hideaki   [NET] IRDA: Fix w...
1747
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
  }
  
  /*
   * Function irda_poll (file, sock, wait)
   */
  static unsigned int irda_poll(struct file * file, struct socket *sock,
  			      poll_table *wait)
  {
  	struct sock *sk = sock->sk;
  	struct irda_sock *self = irda_sk(sk);
  	unsigned int mask;
aa3951451   Eric Dumazet   net: sk_sleep() h...
1759
  	poll_wait(file, sk_sleep(sk), wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1760
1761
1762
1763
1764
1765
  	mask = 0;
  
  	/* Exceptional events? */
  	if (sk->sk_err)
  		mask |= POLLERR;
  	if (sk->sk_shutdown & RCV_SHUTDOWN) {
955a9d202   Joe Perches   irda: Convert IRD...
1766
1767
  		pr_debug("%s(), POLLHUP
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1768
1769
1770
1771
1772
  		mask |= POLLHUP;
  	}
  
  	/* Readable? */
  	if (!skb_queue_empty(&sk->sk_receive_queue)) {
955a9d202   Joe Perches   irda: Convert IRD...
1773
1774
  		pr_debug("Socket is readable
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1775
1776
1777
1778
1779
1780
1781
  		mask |= POLLIN | POLLRDNORM;
  	}
  
  	/* Connection-based need to check for termination and startup */
  	switch (sk->sk_type) {
  	case SOCK_STREAM:
  		if (sk->sk_state == TCP_CLOSE) {
955a9d202   Joe Perches   irda: Convert IRD...
1782
1783
  			pr_debug("%s(), POLLHUP
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
  			mask |= POLLHUP;
  		}
  
  		if (sk->sk_state == TCP_ESTABLISHED) {
  			if ((self->tx_flow == FLOW_START) &&
  			    sock_writeable(sk))
  			{
  				mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
  			}
  		}
  		break;
  	case SOCK_SEQPACKET:
  		if ((self->tx_flow == FLOW_START) &&
  		    sock_writeable(sk))
  		{
  			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
  		}
  		break;
  	case SOCK_DGRAM:
  		if (sock_writeable(sk))
  			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
  		break;
  	default:
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1809

5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1810
  	return mask;
58a9d7320   Arnd Bergmann   net/irda: push BK...
1811
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1812
1813
1814
1815
1816
1817
  /*
   * Function irda_ioctl (sock, cmd, arg)
   */
  static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
  {
  	struct sock *sk = sock->sk;
58a9d7320   Arnd Bergmann   net/irda: push BK...
1818
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1819

955a9d202   Joe Perches   irda: Convert IRD...
1820
1821
  	pr_debug("%s(), cmd=%#x
  ", __func__, cmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1822

58a9d7320   Arnd Bergmann   net/irda: push BK...
1823
  	err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1824
1825
1826
  	switch (cmd) {
  	case TIOCOUTQ: {
  		long amount;
31e6d363a   Eric Dumazet   net: correct off-...
1827
1828
  
  		amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1829
1830
  		if (amount < 0)
  			amount = 0;
58a9d7320   Arnd Bergmann   net/irda: push BK...
1831
1832
  		err = put_user(amount, (unsigned int __user *)arg);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1833
1834
1835
1836
1837
1838
1839
1840
  	}
  
  	case TIOCINQ: {
  		struct sk_buff *skb;
  		long amount = 0L;
  		/* These two are safe on a single CPU system as only user tasks fiddle here */
  		if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
  			amount = skb->len;
58a9d7320   Arnd Bergmann   net/irda: push BK...
1841
1842
  		err = put_user(amount, (unsigned int __user *)arg);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1843
1844
1845
1846
  	}
  
  	case SIOCGSTAMP:
  		if (sk != NULL)
58a9d7320   Arnd Bergmann   net/irda: push BK...
1847
1848
  			err = sock_get_timestamp(sk, (struct timeval __user *)arg);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
  
  	case SIOCGIFADDR:
  	case SIOCSIFADDR:
  	case SIOCGIFDSTADDR:
  	case SIOCSIFDSTADDR:
  	case SIOCGIFBRDADDR:
  	case SIOCSIFBRDADDR:
  	case SIOCGIFNETMASK:
  	case SIOCSIFNETMASK:
  	case SIOCGIFMETRIC:
  	case SIOCSIFMETRIC:
58a9d7320   Arnd Bergmann   net/irda: push BK...
1860
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1861
  	default:
955a9d202   Joe Perches   irda: Convert IRD...
1862
1863
  		pr_debug("%s(), doing device ioctl!
  ", __func__);
58a9d7320   Arnd Bergmann   net/irda: push BK...
1864
  		err = -ENOIOCTLCMD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1865
  	}
58a9d7320   Arnd Bergmann   net/irda: push BK...
1866
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1867
  }
f6c90b71a   Petr Vandrovec   [NET]: Fix ipx/ec...
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
  #ifdef CONFIG_COMPAT
  /*
   * Function irda_ioctl (sock, cmd, arg)
   */
  static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
  {
  	/*
  	 * All IRDA's ioctl are standard ones.
  	 */
  	return -ENOIOCTLCMD;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1880
1881
1882
1883
1884
1885
  /*
   * Function irda_setsockopt (sock, level, optname, optval, optlen)
   *
   *    Set some options for the socket
   *
   */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1886
  static int irda_setsockopt(struct socket *sock, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
1887
  			   char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1888
1889
1890
1891
1892
1893
  {
  	struct sock *sk = sock->sk;
  	struct irda_sock *self = irda_sk(sk);
  	struct irda_ias_set    *ias_opt;
  	struct ias_object      *ias_obj;
  	struct ias_attrib *	ias_attr;	/* Attribute in IAS object */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1894
  	int opt, free_ias = 0, err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1895

955a9d202   Joe Perches   irda: Convert IRD...
1896
1897
  	pr_debug("%s(%p)
  ", __func__, self);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1898
1899
1900
  
  	if (level != SOL_IRLMP)
  		return -ENOPROTOOPT;
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1901
  	lock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1902
1903
1904
1905
1906
1907
1908
1909
  	switch (optname) {
  	case IRLMP_IAS_SET:
  		/* The user want to add an attribute to an existing IAS object
  		 * (in the IAS database) or to create a new object with this
  		 * attribute.
  		 * We first query IAS to know if the object exist, and then
  		 * create the right attribute...
  		 */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1910
1911
1912
1913
  		if (optlen != sizeof(struct irda_ias_set)) {
  			err = -EINVAL;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1914
1915
  
  		ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1916
1917
1918
1919
  		if (ias_opt == NULL) {
  			err = -ENOMEM;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1920
1921
1922
1923
  
  		/* Copy query to the driver. */
  		if (copy_from_user(ias_opt, optval, optlen)) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1924
1925
  			err = -EFAULT;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1926
1927
1928
1929
1930
1931
1932
1933
1934
  		}
  
  		/* Find the object we target.
  		 * If the user gives us an empty string, we use the object
  		 * associated with this socket. This will workaround
  		 * duplicated class name - Jean II */
  		if(ias_opt->irda_class_name[0] == '\0') {
  			if(self->ias_obj == NULL) {
  				kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1935
1936
  				err = -EINVAL;
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
  			}
  			ias_obj = self->ias_obj;
  		} else
  			ias_obj = irias_find_object(ias_opt->irda_class_name);
  
  		/* Only ROOT can mess with the global IAS database.
  		 * Users can only add attributes to the object associated
  		 * with the socket they own - Jean II */
  		if((!capable(CAP_NET_ADMIN)) &&
  		   ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1948
1949
  			err = -EPERM;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1950
1951
1952
1953
1954
1955
1956
  		}
  
  		/* If the object doesn't exist, create it */
  		if(ias_obj == (struct ias_object *) NULL) {
  			/* Create a new object */
  			ias_obj = irias_new_object(ias_opt->irda_class_name,
  						   jiffies);
61e44b481   Jesper Juhl   [IrDA]: af_irda m...
1957
1958
  			if (ias_obj == NULL) {
  				kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1959
1960
  				err = -ENOMEM;
  				goto out;
61e44b481   Jesper Juhl   [IrDA]: af_irda m...
1961
1962
  			}
  			free_ias = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1963
1964
1965
1966
1967
  		}
  
  		/* Do we have the attribute already ? */
  		if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) {
  			kfree(ias_opt);
61e44b481   Jesper Juhl   [IrDA]: af_irda m...
1968
1969
1970
1971
  			if (free_ias) {
  				kfree(ias_obj->name);
  				kfree(ias_obj);
  			}
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1972
1973
  			err = -EINVAL;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
  		}
  
  		/* Look at the type */
  		switch(ias_opt->irda_attrib_type) {
  		case IAS_INTEGER:
  			/* Add an integer attribute */
  			irias_add_integer_attrib(
  				ias_obj,
  				ias_opt->irda_attrib_name,
  				ias_opt->attribute.irda_attrib_int,
  				IAS_USER_ATTR);
  			break;
  		case IAS_OCT_SEQ:
  			/* Check length */
  			if(ias_opt->attribute.irda_attrib_octet_seq.len >
  			   IAS_MAX_OCTET_STRING) {
  				kfree(ias_opt);
61e44b481   Jesper Juhl   [IrDA]: af_irda m...
1991
1992
1993
1994
  				if (free_ias) {
  					kfree(ias_obj->name);
  					kfree(ias_obj);
  				}
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
1995
1996
  				err = -EINVAL;
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
  			}
  			/* Add an octet sequence attribute */
  			irias_add_octseq_attrib(
  			      ias_obj,
  			      ias_opt->irda_attrib_name,
  			      ias_opt->attribute.irda_attrib_octet_seq.octet_seq,
  			      ias_opt->attribute.irda_attrib_octet_seq.len,
  			      IAS_USER_ATTR);
  			break;
  		case IAS_STRING:
  			/* Should check charset & co */
  			/* Check length */
  			/* The length is encoded in a __u8, and
  			 * IAS_MAX_STRING == 256, so there is no way
  			 * userspace can pass us a string too large.
  			 * Jean II */
  			/* NULL terminate the string (avoid troubles) */
  			ias_opt->attribute.irda_attrib_string.string[ias_opt->attribute.irda_attrib_string.len] = '\0';
  			/* Add a string attribute */
  			irias_add_string_attrib(
  				ias_obj,
  				ias_opt->irda_attrib_name,
  				ias_opt->attribute.irda_attrib_string.string,
  				IAS_USER_ATTR);
  			break;
  		default :
  			kfree(ias_opt);
61e44b481   Jesper Juhl   [IrDA]: af_irda m...
2024
2025
2026
2027
  			if (free_ias) {
  				kfree(ias_obj->name);
  				kfree(ias_obj);
  			}
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2028
2029
  			err = -EINVAL;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2030
2031
2032
2033
2034
2035
2036
2037
2038
  		}
  		irias_insert_object(ias_obj);
  		kfree(ias_opt);
  		break;
  	case IRLMP_IAS_DEL:
  		/* The user want to delete an object from our local IAS
  		 * database. We just need to query the IAS, check is the
  		 * object is not owned by the kernel and delete it.
  		 */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2039
2040
2041
2042
  		if (optlen != sizeof(struct irda_ias_set)) {
  			err = -EINVAL;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2043
2044
  
  		ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2045
2046
2047
2048
  		if (ias_opt == NULL) {
  			err = -ENOMEM;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2049
2050
2051
2052
  
  		/* Copy query to the driver. */
  		if (copy_from_user(ias_opt, optval, optlen)) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2053
2054
  			err = -EFAULT;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
  		}
  
  		/* Find the object we target.
  		 * If the user gives us an empty string, we use the object
  		 * associated with this socket. This will workaround
  		 * duplicated class name - Jean II */
  		if(ias_opt->irda_class_name[0] == '\0')
  			ias_obj = self->ias_obj;
  		else
  			ias_obj = irias_find_object(ias_opt->irda_class_name);
  		if(ias_obj == (struct ias_object *) NULL) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2067
2068
  			err = -EINVAL;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069
2070
2071
2072
2073
2074
2075
2076
  		}
  
  		/* Only ROOT can mess with the global IAS database.
  		 * Users can only del attributes from the object associated
  		 * with the socket they own - Jean II */
  		if((!capable(CAP_NET_ADMIN)) &&
  		   ((ias_obj == NULL) || (ias_obj != self->ias_obj))) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2077
2078
  			err = -EPERM;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2079
2080
2081
2082
2083
2084
2085
  		}
  
  		/* Find the attribute (in the object) we target */
  		ias_attr = irias_find_attrib(ias_obj,
  					     ias_opt->irda_attrib_name);
  		if(ias_attr == (struct ias_attrib *) NULL) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2086
2087
  			err = -EINVAL;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2088
2089
2090
2091
  		}
  
  		/* Check is the user space own the object */
  		if(ias_attr->value->owner != IAS_USER_ATTR) {
955a9d202   Joe Perches   irda: Convert IRD...
2092
2093
2094
  			pr_debug("%s(), attempting to delete a kernel attribute
  ",
  				 __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2095
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2096
2097
  			err = -EPERM;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2098
2099
2100
2101
2102
2103
2104
  		}
  
  		/* Remove the attribute (and maybe the object) */
  		irias_delete_attrib(ias_obj, ias_attr, 1);
  		kfree(ias_opt);
  		break;
  	case IRLMP_MAX_SDU_SIZE:
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2105
2106
2107
2108
  		if (optlen < sizeof(int)) {
  			err = -EINVAL;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2109

5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2110
2111
2112
2113
  		if (get_user(opt, (int __user *)optval)) {
  			err = -EFAULT;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2114
2115
2116
  
  		/* Only possible for a seqpacket service (TTP with SAR) */
  		if (sk->sk_type != SOCK_SEQPACKET) {
955a9d202   Joe Perches   irda: Convert IRD...
2117
2118
2119
  			pr_debug("%s(), setting max_sdu_size = %d
  ",
  				 __func__, opt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2120
2121
  			self->max_sdu_size_rx = opt;
  		} else {
6c91023dc   Joe Perches   irda: Remove IRDA...
2122
2123
2124
  			net_warn_ratelimited("%s: not allowed to set MAXSDUSIZE for this socket type!
  ",
  					     __func__);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2125
2126
  			err = -ENOPROTOOPT;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2127
2128
2129
  		}
  		break;
  	case IRLMP_HINTS_SET:
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2130
2131
2132
2133
  		if (optlen < sizeof(int)) {
  			err = -EINVAL;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2134
2135
  
  		/* The input is really a (__u8 hints[2]), easier as an int */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2136
2137
2138
2139
  		if (get_user(opt, (int __user *)optval)) {
  			err = -EFAULT;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2140
2141
  
  		/* Unregister any old registration */
37b8e1ca0   Markus Elfring   irda: Delete an u...
2142
  		irlmp_unregister_service(self->skey);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2143
2144
2145
2146
2147
2148
2149
2150
2151
  
  		self->skey = irlmp_register_service((__u16) opt);
  		break;
  	case IRLMP_HINT_MASK_SET:
  		/* As opposed to the previous case which set the hint bits
  		 * that we advertise, this one set the filter we use when
  		 * making a discovery (nodes which don't match any hint
  		 * bit in the mask are not reported).
  		 */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2152
2153
2154
2155
  		if (optlen < sizeof(int)) {
  			err = -EINVAL;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2156
2157
  
  		/* The input is really a (__u8 hints[2]), easier as an int */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2158
2159
2160
2161
  		if (get_user(opt, (int __user *)optval)) {
  			err = -EFAULT;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
  
  		/* Set the new hint mask */
  		self->mask.word = (__u16) opt;
  		/* Mask out extension bits */
  		self->mask.word &= 0x7f7f;
  		/* Check if no bits */
  		if(!self->mask.word)
  			self->mask.word = 0xFFFF;
  
  		break;
  	default:
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2173
2174
  		err = -ENOPROTOOPT;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2175
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2176

5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2177
2178
  out:
  	release_sock(sk);
58a9d7320   Arnd Bergmann   net/irda: push BK...
2179
2180
2181
  
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
  /*
   * Function irda_extract_ias_value(ias_opt, ias_value)
   *
   *    Translate internal IAS value structure to the user space representation
   *
   * The external representation of IAS values, as we exchange them with
   * user space program is quite different from the internal representation,
   * as stored in the IAS database (because we need a flat structure for
   * crossing kernel boundary).
   * This function transform the former in the latter. We also check
   * that the value type is valid.
   */
  static int irda_extract_ias_value(struct irda_ias_set *ias_opt,
  				  struct ias_value *ias_value)
  {
  	/* Look at the type */
  	switch (ias_value->type) {
  	case IAS_INTEGER:
  		/* Copy the integer */
  		ias_opt->attribute.irda_attrib_int = ias_value->t.integer;
  		break;
  	case IAS_OCT_SEQ:
  		/* Set length */
  		ias_opt->attribute.irda_attrib_octet_seq.len = ias_value->len;
  		/* Copy over */
  		memcpy(ias_opt->attribute.irda_attrib_octet_seq.octet_seq,
  		       ias_value->t.oct_seq, ias_value->len);
  		break;
  	case IAS_STRING:
  		/* Set length */
  		ias_opt->attribute.irda_attrib_string.len = ias_value->len;
  		ias_opt->attribute.irda_attrib_string.charset = ias_value->charset;
  		/* Copy over */
  		memcpy(ias_opt->attribute.irda_attrib_string.string,
  		       ias_value->t.string, ias_value->len);
  		/* NULL terminate the string (avoid troubles) */
  		ias_opt->attribute.irda_attrib_string.string[ias_value->len] = '\0';
  		break;
  	case IAS_MISSING:
  	default :
  		return -EINVAL;
  	}
  
  	/* Copy type over */
  	ias_opt->irda_attrib_type = ias_value->type;
  
  	return 0;
  }
  
  /*
   * Function irda_getsockopt (sock, level, optname, optval, optlen)
   */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2234
  static int irda_getsockopt(struct socket *sock, int level, int optname,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
  			   char __user *optval, int __user *optlen)
  {
  	struct sock *sk = sock->sk;
  	struct irda_sock *self = irda_sk(sk);
  	struct irda_device_list list;
  	struct irda_device_info *discoveries;
  	struct irda_ias_set *	ias_opt;	/* IAS get/query params */
  	struct ias_object *	ias_obj;	/* Object in IAS */
  	struct ias_attrib *	ias_attr;	/* Attribute in IAS object */
  	int daddr = DEV_ADDR_ANY;	/* Dest address for IAS queries */
  	int val = 0;
  	int len = 0;
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2247
  	int err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2248
  	int offset, total;
955a9d202   Joe Perches   irda: Convert IRD...
2249
2250
  	pr_debug("%s(%p)
  ", __func__, self);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2251
2252
2253
2254
2255
2256
2257
2258
2259
  
  	if (level != SOL_IRLMP)
  		return -ENOPROTOOPT;
  
  	if (get_user(len, optlen))
  		return -EFAULT;
  
  	if(len < 0)
  		return -EINVAL;
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2260
  	lock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2261
2262
  	switch (optname) {
  	case IRLMP_ENUMDEVICES:
fdac1e069   Dan Rosenberg   irda: prevent int...
2263
2264
2265
2266
2267
2268
2269
2270
2271
  
  		/* Offset to first device entry */
  		offset = sizeof(struct irda_device_list) -
  			sizeof(struct irda_device_info);
  
  		if (len < offset) {
  			err = -EINVAL;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2272
2273
2274
2275
  		/* Ask lmp for the current discovery log */
  		discoveries = irlmp_get_discoveries(&list.len, self->mask.word,
  						    self->nslots);
  		/* Check if the we got some results */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2276
2277
2278
2279
  		if (discoveries == NULL) {
  			err = -EAGAIN;
  			goto out;		/* Didn't find any devices */
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2280
2281
  
  		/* Write total list length back to client */
fdac1e069   Dan Rosenberg   irda: prevent int...
2282
  		if (copy_to_user(optval, &list, offset))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2283
  			err = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2284
  		/* Copy the list itself - watch for overflow */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2285
  		if (list.len > 2048) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
  			err = -EINVAL;
  			goto bed;
  		}
  		total = offset + (list.len * sizeof(struct irda_device_info));
  		if (total > len)
  			total = len;
  		if (copy_to_user(optval+offset, discoveries, total - offset))
  			err = -EFAULT;
  
  		/* Write total number of bytes used back to client */
  		if (put_user(total, optlen))
  			err = -EFAULT;
  bed:
  		/* Free up our buffer */
  		kfree(discoveries);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2301
2302
2303
2304
  		break;
  	case IRLMP_MAX_SDU_SIZE:
  		val = self->max_data_size;
  		len = sizeof(int);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2305
2306
2307
2308
2309
2310
2311
2312
2313
  		if (put_user(len, optlen)) {
  			err = -EFAULT;
  			goto out;
  		}
  
  		if (copy_to_user(optval, &val, len)) {
  			err = -EFAULT;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2314

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2315
2316
2317
2318
2319
2320
2321
  		break;
  	case IRLMP_IAS_GET:
  		/* The user want an object from our local IAS database.
  		 * We just need to query the IAS and return the value
  		 * that we found */
  
  		/* Check that the user has allocated the right space for us */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2322
2323
2324
2325
  		if (len != sizeof(struct irda_ias_set)) {
  			err = -EINVAL;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2326
2327
  
  		ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2328
2329
2330
2331
  		if (ias_opt == NULL) {
  			err = -ENOMEM;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2332
2333
2334
2335
  
  		/* Copy query to the driver. */
  		if (copy_from_user(ias_opt, optval, len)) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2336
2337
  			err = -EFAULT;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
  		}
  
  		/* Find the object we target.
  		 * If the user gives us an empty string, we use the object
  		 * associated with this socket. This will workaround
  		 * duplicated class name - Jean II */
  		if(ias_opt->irda_class_name[0] == '\0')
  			ias_obj = self->ias_obj;
  		else
  			ias_obj = irias_find_object(ias_opt->irda_class_name);
  		if(ias_obj == (struct ias_object *) NULL) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2350
2351
  			err = -EINVAL;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2352
2353
2354
2355
2356
2357
2358
  		}
  
  		/* Find the attribute (in the object) we target */
  		ias_attr = irias_find_attrib(ias_obj,
  					     ias_opt->irda_attrib_name);
  		if(ias_attr == (struct ias_attrib *) NULL) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2359
2360
  			err = -EINVAL;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2361
2362
2363
2364
2365
2366
  		}
  
  		/* Translate from internal to user structure */
  		err = irda_extract_ias_value(ias_opt, ias_attr->value);
  		if(err) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2367
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2368
2369
2370
2371
2372
2373
  		}
  
  		/* Copy reply to the user */
  		if (copy_to_user(optval, ias_opt,
  				 sizeof(struct irda_ias_set))) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2374
2375
  			err = -EFAULT;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
  		}
  		/* Note : don't need to put optlen, we checked it */
  		kfree(ias_opt);
  		break;
  	case IRLMP_IAS_QUERY:
  		/* The user want an object from a remote IAS database.
  		 * We need to use IAP to query the remote database and
  		 * then wait for the answer to come back. */
  
  		/* Check that the user has allocated the right space for us */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2386
2387
2388
2389
  		if (len != sizeof(struct irda_ias_set)) {
  			err = -EINVAL;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2390
2391
  
  		ias_opt = kmalloc(sizeof(struct irda_ias_set), GFP_ATOMIC);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2392
2393
2394
2395
  		if (ias_opt == NULL) {
  			err = -ENOMEM;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2396
2397
2398
2399
  
  		/* Copy query to the driver. */
  		if (copy_from_user(ias_opt, optval, len)) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2400
2401
  			err = -EFAULT;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
  		}
  
  		/* At this point, there are two cases...
  		 * 1) the socket is connected - that's the easy case, we
  		 *	just query the device we are connected to...
  		 * 2) the socket is not connected - the user doesn't want
  		 *	to connect and/or may not have a valid service name
  		 *	(so can't create a fake connection). In this case,
  		 *	we assume that the user pass us a valid destination
  		 *	address in the requesting structure...
  		 */
  		if(self->daddr != DEV_ADDR_ANY) {
  			/* We are connected - reuse known daddr */
  			daddr = self->daddr;
  		} else {
  			/* We are not connected, we must specify a valid
  			 * destination address */
  			daddr = ias_opt->daddr;
  			if((!daddr) || (daddr == DEV_ADDR_ANY)) {
  				kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2422
2423
  				err = -EINVAL;
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2424
2425
2426
2427
2428
  			}
  		}
  
  		/* Check that we can proceed with IAP */
  		if (self->iriap) {
6c91023dc   Joe Perches   irda: Remove IRDA...
2429
2430
2431
  			net_warn_ratelimited("%s: busy with a previous query
  ",
  					     __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2432
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2433
2434
  			err = -EBUSY;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2435
2436
2437
2438
2439
2440
2441
  		}
  
  		self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
  					 irda_getvalue_confirm);
  
  		if (self->iriap == NULL) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2442
2443
  			err = -ENOMEM;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
  		}
  
  		/* Treat unexpected wakeup as disconnect */
  		self->errno = -EHOSTUNREACH;
  
  		/* Query remote LM-IAS */
  		iriap_getvaluebyclass_request(self->iriap,
  					      self->saddr, daddr,
  					      ias_opt->irda_class_name,
  					      ias_opt->irda_attrib_name);
  
  		/* Wait for answer, if not yet finished (or failed) */
  		if (wait_event_interruptible(self->query_wait,
  					     (self->iriap == NULL))) {
  			/* pending request uses copy of ias_opt-content
  			 * we can free it regardless! */
  			kfree(ias_opt);
  			/* Treat signals as disconnect */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2462
2463
  			err = -EHOSTUNREACH;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2464
2465
2466
2467
2468
2469
2470
2471
2472
  		}
  
  		/* Check what happened */
  		if (self->errno)
  		{
  			kfree(ias_opt);
  			/* Requested object/attribute doesn't exist */
  			if((self->errno == IAS_CLASS_UNKNOWN) ||
  			   (self->errno == IAS_ATTRIB_UNKNOWN))
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2473
  				err = -EADDRNOTAVAIL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2474
  			else
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2475
2476
2477
  				err = -EHOSTUNREACH;
  
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2478
2479
2480
2481
2482
2483
2484
2485
  		}
  
  		/* Translate from internal to user structure */
  		err = irda_extract_ias_value(ias_opt, self->ias_result);
  		if (self->ias_result)
  			irias_delete_value(self->ias_result);
  		if (err) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2486
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2487
2488
2489
2490
2491
2492
  		}
  
  		/* Copy reply to the user */
  		if (copy_to_user(optval, ias_opt,
  				 sizeof(struct irda_ias_set))) {
  			kfree(ias_opt);
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2493
2494
  			err = -EFAULT;
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
  		}
  		/* Note : don't need to put optlen, we checked it */
  		kfree(ias_opt);
  		break;
  	case IRLMP_WAITDEVICE:
  		/* This function is just another way of seeing life ;-)
  		 * IRLMP_ENUMDEVICES assumes that you have a static network,
  		 * and that you just want to pick one of the devices present.
  		 * On the other hand, in here we assume that no device is
  		 * present and that at some point in the future a device will
  		 * come into range. When this device arrive, we just wake
  		 * up the caller, so that he has time to connect to it before
  		 * the device goes away...
  		 * Note : once the node has been discovered for more than a
  		 * few second, it won't trigger this function, unless it
  		 * goes away and come back changes its hint bits (so we
  		 * might call it IRLMP_WAITNEWDEVICE).
  		 */
  
  		/* Check that the user is passing us an int */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2515
2516
2517
2518
  		if (len != sizeof(int)) {
  			err = -EINVAL;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2519
  		/* Get timeout in ms (max time we block the caller) */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2520
2521
2522
2523
  		if (get_user(val, (int __user *)optval)) {
  			err = -EFAULT;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
  
  		/* Tell IrLMP we want to be notified */
  		irlmp_update_client(self->ckey, self->mask.word,
  				    irda_selective_discovery_indication,
  				    NULL, (void *) self);
  
  		/* Do some discovery (and also return cached results) */
  		irlmp_discovery_request(self->nslots);
  
  		/* Wait until a node is discovered */
  		if (!self->cachedaddr) {
955a9d202   Joe Perches   irda: Convert IRD...
2535
2536
2537
  			pr_debug("%s(), nothing discovered yet, going to sleep...
  ",
  				 __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2538
2539
2540
  
  			/* Set watchdog timer to expire in <val> ms. */
  			self->errno = 0;
b24b8a247   Pavel Emelyanov   [NET]: Convert in...
2541
2542
  			setup_timer(&self->watchdog, irda_discovery_timeout,
  					(unsigned long)self);
7d6c429b2   Xi Wang   irda: use msecs_t...
2543
2544
  			mod_timer(&self->watchdog,
  				  jiffies + msecs_to_jiffies(val));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2545
2546
  
  			/* Wait for IR-LMP to call us back */
35a2af94c   Peter Zijlstra   sched/wait: Make ...
2547
2548
  			err = __wait_event_interruptible(self->query_wait,
  			      (self->cachedaddr != 0 || self->errno == -ETIME));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2549
2550
  
  			/* If watchdog is still activated, kill it! */
25cc4ae91   Ying Xue   net: remove redun...
2551
  			del_timer(&(self->watchdog));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2552

955a9d202   Joe Perches   irda: Convert IRD...
2553
2554
  			pr_debug("%s(), ...waking up !
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2555

5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2556
2557
  			if (err != 0)
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2558
2559
  		}
  		else
955a9d202   Joe Perches   irda: Convert IRD...
2560
2561
2562
  			pr_debug("%s(), found immediately !
  ",
  				 __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2563
2564
2565
2566
2567
2568
  
  		/* Tell IrLMP that we have been notified */
  		irlmp_update_client(self->ckey, self->mask.word,
  				    NULL, NULL, NULL);
  
  		/* Check if the we got some results */
896ee0eee   Kees Cook   net/irda: add mis...
2569
2570
2571
2572
  		if (!self->cachedaddr) {
  			err = -EAGAIN;		/* Didn't find any devices */
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
  		daddr = self->cachedaddr;
  		/* Cleanup */
  		self->cachedaddr = 0;
  
  		/* We return the daddr of the device that trigger the
  		 * wakeup. As irlmp pass us only the new devices, we
  		 * are sure that it's not an old device.
  		 * If the user want more details, he should query
  		 * the whole discovery log and pick one device...
  		 */
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2583
2584
2585
2586
  		if (put_user(daddr, (int __user *)optval)) {
  			err = -EFAULT;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2587
2588
2589
  
  		break;
  	default:
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2590
  		err = -ENOPROTOOPT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2591
  	}
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2592
  out:
58a9d7320   Arnd Bergmann   net/irda: push BK...
2593

5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2594
  	release_sock(sk);
58a9d7320   Arnd Bergmann   net/irda: push BK...
2595
2596
2597
  
  	return err;
  }
ec1b4cf74   Stephen Hemminger   net: mark net_pro...
2598
  static const struct net_proto_family irda_family_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2599
2600
2601
2602
  	.family = PF_IRDA,
  	.create = irda_create,
  	.owner	= THIS_MODULE,
  };
58a9d7320   Arnd Bergmann   net/irda: push BK...
2603
  static const struct proto_ops irda_stream_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
  	.family =	PF_IRDA,
  	.owner =	THIS_MODULE,
  	.release =	irda_release,
  	.bind =		irda_bind,
  	.connect =	irda_connect,
  	.socketpair =	sock_no_socketpair,
  	.accept =	irda_accept,
  	.getname =	irda_getname,
  	.poll =		irda_poll,
  	.ioctl =	irda_ioctl,
f6c90b71a   Petr Vandrovec   [NET]: Fix ipx/ec...
2614
2615
2616
  #ifdef CONFIG_COMPAT
  	.compat_ioctl =	irda_compat_ioctl,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2617
2618
2619
2620
2621
2622
2623
2624
2625
  	.listen =	irda_listen,
  	.shutdown =	irda_shutdown,
  	.setsockopt =	irda_setsockopt,
  	.getsockopt =	irda_getsockopt,
  	.sendmsg =	irda_sendmsg,
  	.recvmsg =	irda_recvmsg_stream,
  	.mmap =		sock_no_mmap,
  	.sendpage =	sock_no_sendpage,
  };
58a9d7320   Arnd Bergmann   net/irda: push BK...
2626
  static const struct proto_ops irda_seqpacket_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2627
2628
2629
2630
2631
2632
2633
2634
  	.family =	PF_IRDA,
  	.owner =	THIS_MODULE,
  	.release =	irda_release,
  	.bind =		irda_bind,
  	.connect =	irda_connect,
  	.socketpair =	sock_no_socketpair,
  	.accept =	irda_accept,
  	.getname =	irda_getname,
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2635
  	.poll =		datagram_poll,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2636
  	.ioctl =	irda_ioctl,
f6c90b71a   Petr Vandrovec   [NET]: Fix ipx/ec...
2637
2638
2639
  #ifdef CONFIG_COMPAT
  	.compat_ioctl =	irda_compat_ioctl,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2640
2641
2642
2643
2644
2645
2646
2647
2648
  	.listen =	irda_listen,
  	.shutdown =	irda_shutdown,
  	.setsockopt =	irda_setsockopt,
  	.getsockopt =	irda_getsockopt,
  	.sendmsg =	irda_sendmsg,
  	.recvmsg =	irda_recvmsg_dgram,
  	.mmap =		sock_no_mmap,
  	.sendpage =	sock_no_sendpage,
  };
58a9d7320   Arnd Bergmann   net/irda: push BK...
2649
  static const struct proto_ops irda_dgram_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2650
2651
2652
2653
2654
2655
2656
2657
  	.family =	PF_IRDA,
  	.owner =	THIS_MODULE,
  	.release =	irda_release,
  	.bind =		irda_bind,
  	.connect =	irda_connect,
  	.socketpair =	sock_no_socketpair,
  	.accept =	irda_accept,
  	.getname =	irda_getname,
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2658
  	.poll =		datagram_poll,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2659
  	.ioctl =	irda_ioctl,
f6c90b71a   Petr Vandrovec   [NET]: Fix ipx/ec...
2660
2661
2662
  #ifdef CONFIG_COMPAT
  	.compat_ioctl =	irda_compat_ioctl,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
  	.listen =	irda_listen,
  	.shutdown =	irda_shutdown,
  	.setsockopt =	irda_setsockopt,
  	.getsockopt =	irda_getsockopt,
  	.sendmsg =	irda_sendmsg_dgram,
  	.recvmsg =	irda_recvmsg_dgram,
  	.mmap =		sock_no_mmap,
  	.sendpage =	sock_no_sendpage,
  };
  
  #ifdef CONFIG_IRDA_ULTRA
58a9d7320   Arnd Bergmann   net/irda: push BK...
2674
  static const struct proto_ops irda_ultra_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2675
2676
2677
2678
2679
2680
2681
2682
  	.family =	PF_IRDA,
  	.owner =	THIS_MODULE,
  	.release =	irda_release,
  	.bind =		irda_bind,
  	.connect =	sock_no_connect,
  	.socketpair =	sock_no_socketpair,
  	.accept =	sock_no_accept,
  	.getname =	irda_getname,
5b40964ea   Samuel Ortiz   irda: Remove BKL ...
2683
  	.poll =		datagram_poll,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2684
  	.ioctl =	irda_ioctl,
f6c90b71a   Petr Vandrovec   [NET]: Fix ipx/ec...
2685
2686
2687
  #ifdef CONFIG_COMPAT
  	.compat_ioctl =	irda_compat_ioctl,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
  	.listen =	sock_no_listen,
  	.shutdown =	irda_shutdown,
  	.setsockopt =	irda_setsockopt,
  	.getsockopt =	irda_getsockopt,
  	.sendmsg =	irda_sendmsg_ultra,
  	.recvmsg =	irda_recvmsg_dgram,
  	.mmap =		sock_no_mmap,
  	.sendpage =	sock_no_sendpage,
  };
  #endif /* CONFIG_IRDA_ULTRA */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
  /*
   * Function irsock_init (pro)
   *
   *    Initialize IrDA protocol
   *
   */
  int __init irsock_init(void)
  {
  	int rc = proto_register(&irda_proto, 0);
  
  	if (rc == 0)
  		rc = sock_register(&irda_family_ops);
  
  	return rc;
  }
  
  /*
   * Function irsock_cleanup (void)
   *
   *    Remove IrDA protocol
   *
   */
75a69ac6d   Samuel Ortiz   [IrDA]: Fix IrDA ...
2720
  void irsock_cleanup(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2721
2722
2723
2724
  {
  	sock_unregister(PF_IRDA);
  	proto_unregister(&irda_proto);
  }