diff options
Diffstat (limited to 'net/irda/irnet')
-rw-r--r-- | net/irda/irnet/Kconfig | 13 | ||||
-rw-r--r-- | net/irda/irnet/Makefile | 7 | ||||
-rw-r--r-- | net/irda/irnet/irnet.h | 529 | ||||
-rw-r--r-- | net/irda/irnet/irnet_irda.c | 1866 | ||||
-rw-r--r-- | net/irda/irnet/irnet_irda.h | 186 | ||||
-rw-r--r-- | net/irda/irnet/irnet_ppp.c | 1142 | ||||
-rw-r--r-- | net/irda/irnet/irnet_ppp.h | 119 |
7 files changed, 3862 insertions, 0 deletions
diff --git a/net/irda/irnet/Kconfig b/net/irda/irnet/Kconfig new file mode 100644 index 000000000000..28c557f0fdd2 --- /dev/null +++ b/net/irda/irnet/Kconfig | |||
@@ -0,0 +1,13 @@ | |||
1 | config IRNET | ||
2 | tristate "IrNET protocol" | ||
3 | depends on IRDA && PPP | ||
4 | help | ||
5 | Say Y here if you want to build support for the IrNET protocol. | ||
6 | To compile it as a module, choose M here: the module will be | ||
7 | called irnet. IrNET is a PPP driver, so you will also need a | ||
8 | working PPP subsystem (driver, daemon and config)... | ||
9 | |||
10 | IrNET is an alternate way to transfer TCP/IP traffic over IrDA. It | ||
11 | uses synchronous PPP over a set of point to point IrDA sockets. You | ||
12 | can use it between Linux machine or with W2k. | ||
13 | |||
diff --git a/net/irda/irnet/Makefile b/net/irda/irnet/Makefile new file mode 100644 index 000000000000..b3ee01e0def3 --- /dev/null +++ b/net/irda/irnet/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for the Linux IrDA IrNET protocol layer. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_IRNET) += irnet.o | ||
6 | |||
7 | irnet-objs := irnet_ppp.o irnet_irda.o | ||
diff --git a/net/irda/irnet/irnet.h b/net/irda/irnet/irnet.h new file mode 100644 index 000000000000..9004f7349a76 --- /dev/null +++ b/net/irda/irnet/irnet.h | |||
@@ -0,0 +1,529 @@ | |||
1 | /* | ||
2 | * IrNET protocol module : Synchronous PPP over an IrDA socket. | ||
3 | * | ||
4 | * Jean II - HPL `00 - <jt@hpl.hp.com> | ||
5 | * | ||
6 | * This file contains definitions and declarations global to the IrNET module, | ||
7 | * all grouped in one place... | ||
8 | * This file is a *private* header, so other modules don't want to know | ||
9 | * what's in there... | ||
10 | * | ||
11 | * Note : as most part of the Linux kernel, this module is available | ||
12 | * under the GNU General Public License (GPL). | ||
13 | */ | ||
14 | |||
15 | #ifndef IRNET_H | ||
16 | #define IRNET_H | ||
17 | |||
18 | /************************** DOCUMENTATION ***************************/ | ||
19 | /* | ||
20 | * What is IrNET | ||
21 | * ------------- | ||
22 | * IrNET is a protocol allowing to carry TCP/IP traffic between two | ||
23 | * IrDA peers in an efficient fashion. It is a thin layer, passing PPP | ||
24 | * packets to IrTTP and vice versa. It uses PPP in synchronous mode, | ||
25 | * because IrTTP offer a reliable sequenced packet service (as opposed | ||
26 | * to a byte stream). In fact, you could see IrNET as carrying TCP/IP | ||
27 | * in a IrDA socket, using PPP to provide the glue. | ||
28 | * | ||
29 | * The main difference with traditional PPP over IrCOMM is that we | ||
30 | * avoid the framing and serial emulation which are a performance | ||
31 | * bottleneck. It also allows multipoint communications in a sensible | ||
32 | * fashion. | ||
33 | * | ||
34 | * The main difference with IrLAN is that we use PPP for the link | ||
35 | * management, which is more standard, interoperable and flexible than | ||
36 | * the IrLAN protocol. For example, PPP adds authentication, | ||
37 | * encryption, compression, header compression and automated routing | ||
38 | * setup. And, as IrNET let PPP do the hard work, the implementation | ||
39 | * is much simpler than IrLAN. | ||
40 | * | ||
41 | * The Linux implementation | ||
42 | * ------------------------ | ||
43 | * IrNET is written on top of the Linux-IrDA stack, and interface with | ||
44 | * the generic Linux PPP driver. Because IrNET depend on recent | ||
45 | * changes of the PPP driver interface, IrNET will work only with very | ||
46 | * recent kernel (2.3.99-pre6 and up). | ||
47 | * | ||
48 | * The present implementation offer the following features : | ||
49 | * o simple user interface using pppd | ||
50 | * o efficient implementation (interface directly to PPP and IrTTP) | ||
51 | * o addressing (you can specify the name of the IrNET recipient) | ||
52 | * o multipoint operation (limited by IrLAP specification) | ||
53 | * o information in /proc/net/irda/irnet | ||
54 | * o IrNET events on /dev/irnet (for user space daemon) | ||
55 | * o IrNET daemon (irnetd) to automatically handle incoming requests | ||
56 | * o Windows 2000 compatibility (tested, but need more work) | ||
57 | * Currently missing : | ||
58 | * o Lot's of testing (that's your job) | ||
59 | * o Connection retries (may be too hard to do) | ||
60 | * o Check pppd persist mode | ||
61 | * o User space daemon (to automatically handle incoming requests) | ||
62 | * | ||
63 | * The setup is not currently the most easy, but this should get much | ||
64 | * better when everything will get integrated... | ||
65 | * | ||
66 | * Acknowledgements | ||
67 | * ---------------- | ||
68 | * This module is based on : | ||
69 | * o The PPP driver (ppp_synctty/ppp_generic) by Paul Mackerras | ||
70 | * o The IrLAN protocol (irlan_common/XXX) by Dag Brattli | ||
71 | * o The IrSock interface (af_irda) by Dag Brattli | ||
72 | * o Some other bits from the kernel and my drivers... | ||
73 | * Infinite thanks to those brave souls for providing the infrastructure | ||
74 | * upon which IrNET is built. | ||
75 | * | ||
76 | * Thanks to all my collegues in HP for helping me. In particular, | ||
77 | * thanks to Salil Pradhan and Bill Serra for W2k testing... | ||
78 | * Thanks to Luiz Magalhaes for irnetd and much testing... | ||
79 | * | ||
80 | * Thanks to Alan Cox for answering lot's of my stupid questions, and | ||
81 | * to Paul Mackerras answering my questions on how to best integrate | ||
82 | * IrNET and pppd. | ||
83 | * | ||
84 | * Jean II | ||
85 | * | ||
86 | * Note on some implementations choices... | ||
87 | * ------------------------------------ | ||
88 | * 1) Direct interface vs tty/socket | ||
89 | * I could have used a tty interface to hook to ppp and use the full | ||
90 | * socket API to connect to IrDA. The code would have been easier to | ||
91 | * maintain, and maybe the code would have been smaller... | ||
92 | * Instead, we hook directly to ppp_generic and to IrTTP, which make | ||
93 | * things more complicated... | ||
94 | * | ||
95 | * The first reason is flexibility : this allow us to create IrNET | ||
96 | * instances on demand (no /dev/ircommX crap) and to allow linkname | ||
97 | * specification on pppd command line... | ||
98 | * | ||
99 | * Second reason is speed optimisation. If you look closely at the | ||
100 | * transmit and receive paths, you will notice that they are "super lean" | ||
101 | * (that's why they look ugly), with no function calls and as little data | ||
102 | * copy and modification as I could... | ||
103 | * | ||
104 | * 2) irnetd in user space | ||
105 | * irnetd is implemented in user space, which is necessary to call pppd. | ||
106 | * This also give maximum benefits in term of flexibility and customability, | ||
107 | * and allow to offer the event channel, useful for other stuff like debug. | ||
108 | * | ||
109 | * On the other hand, this require a loose coordination between the | ||
110 | * present module and irnetd. One critical area is how incoming request | ||
111 | * are handled. | ||
112 | * When irnet receive an incoming request, it send an event to irnetd and | ||
113 | * drop the incoming IrNET socket. | ||
114 | * irnetd start a pppd instance, which create a new IrNET socket. This new | ||
115 | * socket is then connected in the originating node to the pppd instance. | ||
116 | * At this point, in the originating node, the first socket is closed. | ||
117 | * | ||
118 | * I admit, this is a bit messy and waste some resources. The alternative | ||
119 | * is caching incoming socket, and that's also quite messy and waste | ||
120 | * resources. | ||
121 | * We also make connection time slower. For example, on a 115 kb/s link it | ||
122 | * adds 60ms to the connection time (770 ms). However, this is slower than | ||
123 | * the time it takes to fire up pppd on my P133... | ||
124 | * | ||
125 | * | ||
126 | * History : | ||
127 | * ------- | ||
128 | * | ||
129 | * v1 - 15.5.00 - Jean II | ||
130 | * o Basic IrNET (hook to ppp_generic & IrTTP - incl. multipoint) | ||
131 | * o control channel on /dev/irnet (set name/address) | ||
132 | * o event channel on /dev/irnet (for user space daemon) | ||
133 | * | ||
134 | * v2 - 5.6.00 - Jean II | ||
135 | * o Enable DROP_NOT_READY to avoid PPP timeouts & other weirdness... | ||
136 | * o Add DISCONNECT_TO event and rename DISCONNECT_FROM. | ||
137 | * o Set official device number alloaction on /dev/irnet | ||
138 | * | ||
139 | * v3 - 30.8.00 - Jean II | ||
140 | * o Update to latest Linux-IrDA changes : | ||
141 | * - queue_t => irda_queue_t | ||
142 | * o Update to ppp-2.4.0 : | ||
143 | * - move irda_irnet_connect from PPPIOCATTACH to TIOCSETD | ||
144 | * o Add EXPIRE event (depend on new IrDA-Linux patch) | ||
145 | * o Switch from `hashbin_remove' to `hashbin_remove_this' to fix | ||
146 | * a multilink bug... (depend on new IrDA-Linux patch) | ||
147 | * o fix a self->daddr to self->raddr in irda_irnet_connect to fix | ||
148 | * another multilink bug (darn !) | ||
149 | * o Remove LINKNAME_IOCTL cruft | ||
150 | * | ||
151 | * v3b - 31.8.00 - Jean II | ||
152 | * o Dump discovery log at event channel startup | ||
153 | * | ||
154 | * v4 - 28.9.00 - Jean II | ||
155 | * o Fix interaction between poll/select and dump discovery log | ||
156 | * o Add IRNET_BLOCKED_LINK event (depend on new IrDA-Linux patch) | ||
157 | * o Add IRNET_NOANSWER_FROM event (mostly to help support) | ||
158 | * o Release flow control in disconnect_indication | ||
159 | * o Block packets while connecting (speed up connections) | ||
160 | * | ||
161 | * v5 - 11.01.01 - Jean II | ||
162 | * o Init self->max_header_size, just in case... | ||
163 | * o Set up ap->chan.hdrlen, to get zero copy on tx side working. | ||
164 | * o avoid tx->ttp->flow->ppp->tx->... loop, by checking flow state | ||
165 | * Thanks to Christian Gennerat for finding this bug ! | ||
166 | * --- | ||
167 | * o Declare the proper MTU/MRU that we can support | ||
168 | * (but PPP doesn't read the MTU value :-() | ||
169 | * o Declare hashbin HB_NOLOCK instead of HB_LOCAL to avoid | ||
170 | * disabling and enabling irq twice | ||
171 | * | ||
172 | * v6 - 31.05.01 - Jean II | ||
173 | * o Print source address in Found, Discovery, Expiry & Request events | ||
174 | * o Print requested source address in /proc/net/irnet | ||
175 | * o Change control channel input. Allow multiple commands in one line. | ||
176 | * o Add saddr command to change ap->rsaddr (and use that in IrDA) | ||
177 | * --- | ||
178 | * o Make the IrDA connection procedure totally asynchronous. | ||
179 | * Heavy rewrite of the IAS query code and the whole connection | ||
180 | * procedure. Now, irnet_connect() no longer need to be called from | ||
181 | * a process context... | ||
182 | * o Enable IrDA connect retries in ppp_irnet_send(). The good thing | ||
183 | * is that IrDA connect retries are directly driven by PPP LCP | ||
184 | * retries (we retry for each LCP packet), so that everything | ||
185 | * is transparently controlled from pppd lcp-max-configure. | ||
186 | * o Add ttp_connect flag to prevent rentry on the connect procedure | ||
187 | * o Test and fixups to eliminate side effects of retries | ||
188 | * | ||
189 | * v7 - 22.08.01 - Jean II | ||
190 | * o Cleanup : Change "saddr = 0x0" to "saddr = DEV_ADDR_ANY" | ||
191 | * o Fix bug in BLOCK_WHEN_CONNECT introduced in v6 : due to the | ||
192 | * asynchronous IAS query, self->tsap is NULL when PPP send the | ||
193 | * first packet. This was preventing "connect-delay 0" to work. | ||
194 | * Change the test in ppp_irnet_send() to self->ttp_connect. | ||
195 | * | ||
196 | * v8 - 1.11.01 - Jean II | ||
197 | * o Tighten the use of self->ttp_connect and self->ttp_open to | ||
198 | * prevent various race conditions. | ||
199 | * o Avoid leaking discovery log and skb | ||
200 | * o Replace "self" with "server" in irnet_connect_indication() to | ||
201 | * better detect cut'n'paste error ;-) | ||
202 | * | ||
203 | * v9 - 29.11.01 - Jean II | ||
204 | * o Fix event generation in disconnect indication that I broke in v8 | ||
205 | * It was always generation "No-Answer" because I was testing ttp_open | ||
206 | * just after clearing it. *blush*. | ||
207 | * o Use newly created irttp_listen() to fix potential crash when LAP | ||
208 | * destroyed before irnet module removed. | ||
209 | * | ||
210 | * v10 - 4.3.2 - Jean II | ||
211 | * o When receiving a disconnect indication, don't reenable the | ||
212 | * PPP Tx queue, this will trigger a reconnect. Instead, close | ||
213 | * the channel, which will kill pppd... | ||
214 | * | ||
215 | * v11 - 20.3.02 - Jean II | ||
216 | * o Oops ! v10 fix disabled IrNET retries and passive behaviour. | ||
217 | * Better fix in irnet_disconnect_indication() : | ||
218 | * - if connected, kill pppd via hangup. | ||
219 | * - if not connected, reenable ppp Tx, which trigger IrNET retry. | ||
220 | * | ||
221 | * v12 - 10.4.02 - Jean II | ||
222 | * o Fix race condition in irnet_connect_indication(). | ||
223 | * If the socket was already trying to connect, drop old connection | ||
224 | * and use new one only if acting as primary. See comments. | ||
225 | * | ||
226 | * v13 - 30.5.02 - Jean II | ||
227 | * o Update module init code | ||
228 | * | ||
229 | * v14 - 20.2.03 - Jean II | ||
230 | * o Add discovery hint bits in the control channel. | ||
231 | * o Remove obsolete MOD_INC/DEC_USE_COUNT in favor of .owner | ||
232 | * | ||
233 | * v15 - 7.4.03 - Jean II | ||
234 | * o Replace spin_lock_irqsave() with spin_lock_bh() so that we can | ||
235 | * use ppp_unit_number(). It's probably also better overall... | ||
236 | * o Disable call to ppp_unregister_channel(), because we can't do it. | ||
237 | */ | ||
238 | |||
239 | /***************************** INCLUDES *****************************/ | ||
240 | |||
241 | #include <linux/module.h> | ||
242 | |||
243 | #include <linux/kernel.h> | ||
244 | #include <linux/skbuff.h> | ||
245 | #include <linux/tty.h> | ||
246 | #include <linux/proc_fs.h> | ||
247 | #include <linux/devfs_fs_kernel.h> | ||
248 | #include <linux/netdevice.h> | ||
249 | #include <linux/miscdevice.h> | ||
250 | #include <linux/poll.h> | ||
251 | #include <linux/config.h> | ||
252 | #include <linux/ctype.h> /* isspace() */ | ||
253 | #include <asm/uaccess.h> | ||
254 | #include <linux/init.h> | ||
255 | |||
256 | #include <linux/ppp_defs.h> | ||
257 | #include <linux/if_ppp.h> | ||
258 | #include <linux/ppp_channel.h> | ||
259 | |||
260 | #include <net/irda/irda.h> | ||
261 | #include <net/irda/iriap.h> | ||
262 | #include <net/irda/irias_object.h> | ||
263 | #include <net/irda/irlmp.h> | ||
264 | #include <net/irda/irttp.h> | ||
265 | #include <net/irda/discovery.h> | ||
266 | |||
267 | /***************************** OPTIONS *****************************/ | ||
268 | /* | ||
269 | * Define or undefine to compile or not some optional part of the | ||
270 | * IrNET driver... | ||
271 | * Note : the present defaults make sense, play with that at your | ||
272 | * own risk... | ||
273 | */ | ||
274 | /* IrDA side of the business... */ | ||
275 | #define DISCOVERY_NOMASK /* To enable W2k compatibility... */ | ||
276 | #define ADVERTISE_HINT /* Advertise IrLAN hint bit */ | ||
277 | #define ALLOW_SIMULT_CONNECT /* This seem to work, cross fingers... */ | ||
278 | #define DISCOVERY_EVENTS /* Query the discovery log to post events */ | ||
279 | #define INITIAL_DISCOVERY /* Dump current discovery log as events */ | ||
280 | #undef STREAM_COMPAT /* Not needed - potentially messy */ | ||
281 | #undef CONNECT_INDIC_KICK /* Might mess IrDA, not needed */ | ||
282 | #undef FAIL_SEND_DISCONNECT /* Might mess IrDA, not needed */ | ||
283 | #undef PASS_CONNECT_PACKETS /* Not needed ? Safe */ | ||
284 | #undef MISSING_PPP_API /* Stuff I wish I could do */ | ||
285 | |||
286 | /* PPP side of the business */ | ||
287 | #define BLOCK_WHEN_CONNECT /* Block packets when connecting */ | ||
288 | #define CONNECT_IN_SEND /* Retry IrDA connection procedure */ | ||
289 | #undef FLUSH_TO_PPP /* Not sure about this one, let's play safe */ | ||
290 | #undef SECURE_DEVIRNET /* Bah... */ | ||
291 | |||
292 | /****************************** DEBUG ******************************/ | ||
293 | |||
294 | /* | ||
295 | * This set of flags enable and disable all the various warning, | ||
296 | * error and debug message of this driver. | ||
297 | * Each section can be enabled and disabled independently | ||
298 | */ | ||
299 | /* In the PPP part */ | ||
300 | #define DEBUG_CTRL_TRACE 0 /* Control channel */ | ||
301 | #define DEBUG_CTRL_INFO 0 /* various info */ | ||
302 | #define DEBUG_CTRL_ERROR 1 /* problems */ | ||
303 | #define DEBUG_FS_TRACE 0 /* filesystem callbacks */ | ||
304 | #define DEBUG_FS_INFO 0 /* various info */ | ||
305 | #define DEBUG_FS_ERROR 1 /* problems */ | ||
306 | #define DEBUG_PPP_TRACE 0 /* PPP related functions */ | ||
307 | #define DEBUG_PPP_INFO 0 /* various info */ | ||
308 | #define DEBUG_PPP_ERROR 1 /* problems */ | ||
309 | #define DEBUG_MODULE_TRACE 0 /* module insertion/removal */ | ||
310 | #define DEBUG_MODULE_ERROR 1 /* problems */ | ||
311 | |||
312 | /* In the IrDA part */ | ||
313 | #define DEBUG_IRDA_SR_TRACE 0 /* IRDA subroutines */ | ||
314 | #define DEBUG_IRDA_SR_INFO 0 /* various info */ | ||
315 | #define DEBUG_IRDA_SR_ERROR 1 /* problems */ | ||
316 | #define DEBUG_IRDA_SOCK_TRACE 0 /* IRDA main socket functions */ | ||
317 | #define DEBUG_IRDA_SOCK_INFO 0 /* various info */ | ||
318 | #define DEBUG_IRDA_SOCK_ERROR 1 /* problems */ | ||
319 | #define DEBUG_IRDA_SERV_TRACE 0 /* The IrNET server */ | ||
320 | #define DEBUG_IRDA_SERV_INFO 0 /* various info */ | ||
321 | #define DEBUG_IRDA_SERV_ERROR 1 /* problems */ | ||
322 | #define DEBUG_IRDA_TCB_TRACE 0 /* IRDA IrTTP callbacks */ | ||
323 | #define DEBUG_IRDA_CB_INFO 0 /* various info */ | ||
324 | #define DEBUG_IRDA_CB_ERROR 1 /* problems */ | ||
325 | #define DEBUG_IRDA_OCB_TRACE 0 /* IRDA other callbacks */ | ||
326 | #define DEBUG_IRDA_OCB_INFO 0 /* various info */ | ||
327 | #define DEBUG_IRDA_OCB_ERROR 1 /* problems */ | ||
328 | |||
329 | #define DEBUG_ASSERT 0 /* Verify all assertions */ | ||
330 | |||
331 | /* | ||
332 | * These are the macros we are using to actually print the debug | ||
333 | * statements. Don't look at it, it's ugly... | ||
334 | * | ||
335 | * One of the trick is that, as the DEBUG_XXX are constant, the | ||
336 | * compiler will optimise away the if() in all cases. | ||
337 | */ | ||
338 | /* All error messages (will show up in the normal logs) */ | ||
339 | #define DERROR(dbg, format, args...) \ | ||
340 | {if(DEBUG_##dbg) \ | ||
341 | printk(KERN_INFO "irnet: %s(): " format, __FUNCTION__ , ##args);} | ||
342 | |||
343 | /* Normal debug message (will show up in /var/log/debug) */ | ||
344 | #define DEBUG(dbg, format, args...) \ | ||
345 | {if(DEBUG_##dbg) \ | ||
346 | printk(KERN_DEBUG "irnet: %s(): " format, __FUNCTION__ , ##args);} | ||
347 | |||
348 | /* Entering a function (trace) */ | ||
349 | #define DENTER(dbg, format, args...) \ | ||
350 | {if(DEBUG_##dbg) \ | ||
351 | printk(KERN_DEBUG "irnet: -> %s" format, __FUNCTION__ , ##args);} | ||
352 | |||
353 | /* Entering and exiting a function in one go (trace) */ | ||
354 | #define DPASS(dbg, format, args...) \ | ||
355 | {if(DEBUG_##dbg) \ | ||
356 | printk(KERN_DEBUG "irnet: <>%s" format, __FUNCTION__ , ##args);} | ||
357 | |||
358 | /* Exiting a function (trace) */ | ||
359 | #define DEXIT(dbg, format, args...) \ | ||
360 | {if(DEBUG_##dbg) \ | ||
361 | printk(KERN_DEBUG "irnet: <-%s()" format, __FUNCTION__ , ##args);} | ||
362 | |||
363 | /* Exit a function with debug */ | ||
364 | #define DRETURN(ret, dbg, args...) \ | ||
365 | {DEXIT(dbg, ": " args);\ | ||
366 | return ret; } | ||
367 | |||
368 | /* Exit a function on failed condition */ | ||
369 | #define DABORT(cond, ret, dbg, args...) \ | ||
370 | {if(cond) {\ | ||
371 | DERROR(dbg, args);\ | ||
372 | return ret; }} | ||
373 | |||
374 | /* Invalid assertion, print out an error and exit... */ | ||
375 | #define DASSERT(cond, ret, dbg, args...) \ | ||
376 | {if((DEBUG_ASSERT) && !(cond)) {\ | ||
377 | DERROR(dbg, "Invalid assertion: " args);\ | ||
378 | return ret; }} | ||
379 | |||
380 | /************************ CONSTANTS & MACROS ************************/ | ||
381 | |||
382 | /* Paranoia */ | ||
383 | #define IRNET_MAGIC 0xB00754 | ||
384 | |||
385 | /* Number of control events in the control channel buffer... */ | ||
386 | #define IRNET_MAX_EVENTS 8 /* Should be more than enough... */ | ||
387 | |||
388 | /****************************** TYPES ******************************/ | ||
389 | |||
390 | /* | ||
391 | * This is the main structure where we store all the data pertaining to | ||
392 | * one instance of irnet. | ||
393 | * Note : in irnet functions, a pointer this structure is usually called | ||
394 | * "ap" or "self". If the code is borrowed from the IrDA stack, it tend | ||
395 | * to be called "self", and if it is borrowed from the PPP driver it is | ||
396 | * "ap". Apart from that, it's exactly the same structure ;-) | ||
397 | */ | ||
398 | typedef struct irnet_socket | ||
399 | { | ||
400 | /* ------------------- Instance management ------------------- */ | ||
401 | /* We manage a linked list of IrNET socket instances */ | ||
402 | irda_queue_t q; /* Must be first - for hasbin */ | ||
403 | int magic; /* Paranoia */ | ||
404 | |||
405 | /* --------------------- FileSystem part --------------------- */ | ||
406 | /* "pppd" interact directly with us on a /dev/ file */ | ||
407 | struct file * file; /* File descriptor of this instance */ | ||
408 | /* TTY stuff - to keep "pppd" happy */ | ||
409 | struct termios termios; /* Various tty flags */ | ||
410 | /* Stuff for the control channel */ | ||
411 | int event_index; /* Last read in the event log */ | ||
412 | |||
413 | /* ------------------------- PPP part ------------------------- */ | ||
414 | /* We interface directly to the ppp_generic driver in the kernel */ | ||
415 | int ppp_open; /* registered with ppp_generic */ | ||
416 | struct ppp_channel chan; /* Interface to generic ppp layer */ | ||
417 | |||
418 | int mru; /* Max size of PPP payload */ | ||
419 | u32 xaccm[8]; /* Asynchronous character map (just */ | ||
420 | u32 raccm; /* to please pppd - dummy) */ | ||
421 | unsigned int flags; /* PPP flags (compression, ...) */ | ||
422 | unsigned int rbits; /* Unused receive flags ??? */ | ||
423 | |||
424 | /* ------------------------ IrTTP part ------------------------ */ | ||
425 | /* We create a pseudo "socket" over the IrDA tranport */ | ||
426 | unsigned long ttp_open; /* Set when IrTTP is ready */ | ||
427 | unsigned long ttp_connect; /* Set when IrTTP is connecting */ | ||
428 | struct tsap_cb * tsap; /* IrTTP instance (the connection) */ | ||
429 | |||
430 | char rname[NICKNAME_MAX_LEN + 1]; | ||
431 | /* IrDA nickname of destination */ | ||
432 | __u32 rdaddr; /* Requested peer IrDA address */ | ||
433 | __u32 rsaddr; /* Requested local IrDA address */ | ||
434 | __u32 daddr; /* actual peer IrDA address */ | ||
435 | __u32 saddr; /* my local IrDA address */ | ||
436 | __u8 dtsap_sel; /* Remote TSAP selector */ | ||
437 | __u8 stsap_sel; /* Local TSAP selector */ | ||
438 | |||
439 | __u32 max_sdu_size_rx;/* Socket parameters used for IrTTP */ | ||
440 | __u32 max_sdu_size_tx; | ||
441 | __u32 max_data_size; | ||
442 | __u8 max_header_size; | ||
443 | LOCAL_FLOW tx_flow; /* State of the Tx path in IrTTP */ | ||
444 | |||
445 | /* ------------------- IrLMP and IrIAS part ------------------- */ | ||
446 | /* Used for IrDA Discovery and socket name resolution */ | ||
447 | void * ckey; /* IrLMP client handle */ | ||
448 | __u16 mask; /* Hint bits mask (filter discov.)*/ | ||
449 | int nslots; /* Number of slots for discovery */ | ||
450 | |||
451 | struct iriap_cb * iriap; /* Used to query remote IAS */ | ||
452 | int errno; /* status of the IAS query */ | ||
453 | |||
454 | /* -------------------- Discovery log part -------------------- */ | ||
455 | /* Used by initial discovery on the control channel | ||
456 | * and by irnet_discover_daddr_and_lsap_sel() */ | ||
457 | struct irda_device_info *discoveries; /* Copy of the discovery log */ | ||
458 | int disco_index; /* Last read in the discovery log */ | ||
459 | int disco_number; /* Size of the discovery log */ | ||
460 | |||
461 | } irnet_socket; | ||
462 | |||
463 | /* | ||
464 | * This is the various event that we will generate on the control channel | ||
465 | */ | ||
466 | typedef enum irnet_event | ||
467 | { | ||
468 | IRNET_DISCOVER, /* New IrNET node discovered */ | ||
469 | IRNET_EXPIRE, /* IrNET node expired */ | ||
470 | IRNET_CONNECT_TO, /* IrNET socket has connected to other node */ | ||
471 | IRNET_CONNECT_FROM, /* Other node has connected to IrNET socket */ | ||
472 | IRNET_REQUEST_FROM, /* Non satisfied connection request */ | ||
473 | IRNET_NOANSWER_FROM, /* Failed connection request */ | ||
474 | IRNET_BLOCKED_LINK, /* Link (IrLAP) is blocked for > 3s */ | ||
475 | IRNET_DISCONNECT_FROM, /* IrNET socket has disconnected */ | ||
476 | IRNET_DISCONNECT_TO /* Closing IrNET socket */ | ||
477 | } irnet_event; | ||
478 | |||
479 | /* | ||
480 | * This is the storage for an event and its arguments | ||
481 | */ | ||
482 | typedef struct irnet_log | ||
483 | { | ||
484 | irnet_event event; | ||
485 | int unit; | ||
486 | __u32 saddr; | ||
487 | __u32 daddr; | ||
488 | char name[NICKNAME_MAX_LEN + 1]; /* 21 + 1 */ | ||
489 | __u16_host_order hints; /* Discovery hint bits */ | ||
490 | } irnet_log; | ||
491 | |||
492 | /* | ||
493 | * This is the storage for all events and related stuff... | ||
494 | */ | ||
495 | typedef struct irnet_ctrl_channel | ||
496 | { | ||
497 | irnet_log log[IRNET_MAX_EVENTS]; /* Event log */ | ||
498 | int index; /* Current index in log */ | ||
499 | spinlock_t spinlock; /* Serialize access to the event log */ | ||
500 | wait_queue_head_t rwait; /* processes blocked on read (or poll) */ | ||
501 | } irnet_ctrl_channel; | ||
502 | |||
503 | /**************************** PROTOTYPES ****************************/ | ||
504 | /* | ||
505 | * Global functions of the IrNET module | ||
506 | * Note : we list here also functions called from one file to the other. | ||
507 | */ | ||
508 | |||
509 | /* -------------------------- IRDA PART -------------------------- */ | ||
510 | extern int | ||
511 | irda_irnet_create(irnet_socket *); /* Initialise a IrNET socket */ | ||
512 | extern int | ||
513 | irda_irnet_connect(irnet_socket *); /* Try to connect over IrDA */ | ||
514 | extern void | ||
515 | irda_irnet_destroy(irnet_socket *); /* Teardown a IrNET socket */ | ||
516 | extern int | ||
517 | irda_irnet_init(void); /* Initialise IrDA part of IrNET */ | ||
518 | extern void | ||
519 | irda_irnet_cleanup(void); /* Teardown IrDA part of IrNET */ | ||
520 | /* ---------------------------- MODULE ---------------------------- */ | ||
521 | extern int | ||
522 | irnet_init(void); /* Initialise IrNET module */ | ||
523 | |||
524 | /**************************** VARIABLES ****************************/ | ||
525 | |||
526 | /* Control channel stuff - allocated in irnet_irda.h */ | ||
527 | extern struct irnet_ctrl_channel irnet_events; | ||
528 | |||
529 | #endif /* IRNET_H */ | ||
diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c new file mode 100644 index 000000000000..07ec326c71f5 --- /dev/null +++ b/net/irda/irnet/irnet_irda.c | |||
@@ -0,0 +1,1866 @@ | |||
1 | /* | ||
2 | * IrNET protocol module : Synchronous PPP over an IrDA socket. | ||
3 | * | ||
4 | * Jean II - HPL `00 - <jt@hpl.hp.com> | ||
5 | * | ||
6 | * This file implement the IRDA interface of IrNET. | ||
7 | * Basically, we sit on top of IrTTP. We set up IrTTP, IrIAS properly, | ||
8 | * and exchange frames with IrTTP. | ||
9 | */ | ||
10 | |||
11 | #include "irnet_irda.h" /* Private header */ | ||
12 | |||
13 | /************************* CONTROL CHANNEL *************************/ | ||
14 | /* | ||
15 | * When ppp is not active, /dev/irnet act as a control channel. | ||
16 | * Writing allow to set up the IrDA destination of the IrNET channel, | ||
17 | * and any application may be read events happening on IrNET... | ||
18 | */ | ||
19 | |||
20 | /*------------------------------------------------------------------*/ | ||
21 | /* | ||
22 | * Post an event to the control channel... | ||
23 | * Put the event in the log, and then wait all process blocked on read | ||
24 | * so they can read the log... | ||
25 | */ | ||
26 | static void | ||
27 | irnet_post_event(irnet_socket * ap, | ||
28 | irnet_event event, | ||
29 | __u32 saddr, | ||
30 | __u32 daddr, | ||
31 | char * name, | ||
32 | __u16 hints) | ||
33 | { | ||
34 | int index; /* In the log */ | ||
35 | |||
36 | DENTER(CTRL_TRACE, "(ap=0x%p, event=%d, daddr=%08x, name=``%s'')\n", | ||
37 | ap, event, daddr, name); | ||
38 | |||
39 | /* Protect this section via spinlock. | ||
40 | * Note : as we are the only event producer, we only need to exclude | ||
41 | * ourself when touching the log, which is nice and easy. | ||
42 | */ | ||
43 | spin_lock_bh(&irnet_events.spinlock); | ||
44 | |||
45 | /* Copy the event in the log */ | ||
46 | index = irnet_events.index; | ||
47 | irnet_events.log[index].event = event; | ||
48 | irnet_events.log[index].daddr = daddr; | ||
49 | irnet_events.log[index].saddr = saddr; | ||
50 | /* Try to copy IrDA nickname */ | ||
51 | if(name) | ||
52 | strcpy(irnet_events.log[index].name, name); | ||
53 | else | ||
54 | irnet_events.log[index].name[0] = '\0'; | ||
55 | /* Copy hints */ | ||
56 | irnet_events.log[index].hints.word = hints; | ||
57 | /* Try to get ppp unit number */ | ||
58 | if((ap != (irnet_socket *) NULL) && (ap->ppp_open)) | ||
59 | irnet_events.log[index].unit = ppp_unit_number(&ap->chan); | ||
60 | else | ||
61 | irnet_events.log[index].unit = -1; | ||
62 | |||
63 | /* Increment the index | ||
64 | * Note that we increment the index only after the event is written, | ||
65 | * to make sure that the readers don't get garbage... */ | ||
66 | irnet_events.index = (index + 1) % IRNET_MAX_EVENTS; | ||
67 | |||
68 | DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index); | ||
69 | |||
70 | /* Spin lock end */ | ||
71 | spin_unlock_bh(&irnet_events.spinlock); | ||
72 | |||
73 | /* Now : wake up everybody waiting for events... */ | ||
74 | wake_up_interruptible_all(&irnet_events.rwait); | ||
75 | |||
76 | DEXIT(CTRL_TRACE, "\n"); | ||
77 | } | ||
78 | |||
79 | /************************* IRDA SUBROUTINES *************************/ | ||
80 | /* | ||
81 | * These are a bunch of subroutines called from other functions | ||
82 | * down there, mostly common code or to improve readability... | ||
83 | * | ||
84 | * Note : we duplicate quite heavily some routines of af_irda.c, | ||
85 | * because our input structure (self) is quite different | ||
86 | * (struct irnet instead of struct irda_sock), which make sharing | ||
87 | * the same code impossible (at least, without templates). | ||
88 | */ | ||
89 | |||
90 | /*------------------------------------------------------------------*/ | ||
91 | /* | ||
92 | * Function irda_open_tsap (self) | ||
93 | * | ||
94 | * Open local Transport Service Access Point (TSAP) | ||
95 | * | ||
96 | * Create a IrTTP instance for us and set all the IrTTP callbacks. | ||
97 | */ | ||
98 | static inline int | ||
99 | irnet_open_tsap(irnet_socket * self) | ||
100 | { | ||
101 | notify_t notify; /* Callback structure */ | ||
102 | |||
103 | DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); | ||
104 | |||
105 | DABORT(self->tsap != NULL, -EBUSY, IRDA_SR_ERROR, "Already busy !\n"); | ||
106 | |||
107 | /* Initialize IrTTP callbacks to be used by the IrDA stack */ | ||
108 | irda_notify_init(¬ify); | ||
109 | notify.connect_confirm = irnet_connect_confirm; | ||
110 | notify.connect_indication = irnet_connect_indication; | ||
111 | notify.disconnect_indication = irnet_disconnect_indication; | ||
112 | notify.data_indication = irnet_data_indication; | ||
113 | /*notify.udata_indication = NULL;*/ | ||
114 | notify.flow_indication = irnet_flow_indication; | ||
115 | notify.status_indication = irnet_status_indication; | ||
116 | notify.instance = self; | ||
117 | strlcpy(notify.name, IRNET_NOTIFY_NAME, sizeof(notify.name)); | ||
118 | |||
119 | /* Open an IrTTP instance */ | ||
120 | self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, | ||
121 | ¬ify); | ||
122 | DABORT(self->tsap == NULL, -ENOMEM, | ||
123 | IRDA_SR_ERROR, "Unable to allocate TSAP !\n"); | ||
124 | |||
125 | /* Remember which TSAP selector we actually got */ | ||
126 | self->stsap_sel = self->tsap->stsap_sel; | ||
127 | |||
128 | DEXIT(IRDA_SR_TRACE, " - tsap=0x%p, sel=0x%X\n", | ||
129 | self->tsap, self->stsap_sel); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | /*------------------------------------------------------------------*/ | ||
134 | /* | ||
135 | * Function irnet_ias_to_tsap (self, result, value) | ||
136 | * | ||
137 | * Examine an IAS object and extract TSAP | ||
138 | * | ||
139 | * We do an IAP query to find the TSAP associated with the IrNET service. | ||
140 | * When IrIAP pass us the result of the query, this function look at | ||
141 | * the return values to check for failures and extract the TSAP if | ||
142 | * possible. | ||
143 | * Also deallocate value | ||
144 | * The failure is in self->errno | ||
145 | * Return TSAP or -1 | ||
146 | */ | ||
147 | static inline __u8 | ||
148 | irnet_ias_to_tsap(irnet_socket * self, | ||
149 | int result, | ||
150 | struct ias_value * value) | ||
151 | { | ||
152 | __u8 dtsap_sel = 0; /* TSAP we are looking for */ | ||
153 | |||
154 | DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); | ||
155 | |||
156 | /* By default, no error */ | ||
157 | self->errno = 0; | ||
158 | |||
159 | /* Check if request succeeded */ | ||
160 | switch(result) | ||
161 | { | ||
162 | /* Standard errors : service not available */ | ||
163 | case IAS_CLASS_UNKNOWN: | ||
164 | case IAS_ATTRIB_UNKNOWN: | ||
165 | DEBUG(IRDA_SR_INFO, "IAS object doesn't exist ! (%d)\n", result); | ||
166 | self->errno = -EADDRNOTAVAIL; | ||
167 | break; | ||
168 | |||
169 | /* Other errors, most likely IrDA stack failure */ | ||
170 | default : | ||
171 | DEBUG(IRDA_SR_INFO, "IAS query failed ! (%d)\n", result); | ||
172 | self->errno = -EHOSTUNREACH; | ||
173 | break; | ||
174 | |||
175 | /* Success : we got what we wanted */ | ||
176 | case IAS_SUCCESS: | ||
177 | break; | ||
178 | } | ||
179 | |||
180 | /* Check what was returned to us */ | ||
181 | if(value != NULL) | ||
182 | { | ||
183 | /* What type of argument have we got ? */ | ||
184 | switch(value->type) | ||
185 | { | ||
186 | case IAS_INTEGER: | ||
187 | DEBUG(IRDA_SR_INFO, "result=%d\n", value->t.integer); | ||
188 | if(value->t.integer != -1) | ||
189 | /* Get the remote TSAP selector */ | ||
190 | dtsap_sel = value->t.integer; | ||
191 | else | ||
192 | self->errno = -EADDRNOTAVAIL; | ||
193 | break; | ||
194 | default: | ||
195 | self->errno = -EADDRNOTAVAIL; | ||
196 | DERROR(IRDA_SR_ERROR, "bad type ! (0x%X)\n", value->type); | ||
197 | break; | ||
198 | } | ||
199 | |||
200 | /* Cleanup */ | ||
201 | irias_delete_value(value); | ||
202 | } | ||
203 | else /* value == NULL */ | ||
204 | { | ||
205 | /* Nothing returned to us - usually result != SUCCESS */ | ||
206 | if(!(self->errno)) | ||
207 | { | ||
208 | DERROR(IRDA_SR_ERROR, | ||
209 | "IrDA bug : result == SUCCESS && value == NULL\n"); | ||
210 | self->errno = -EHOSTUNREACH; | ||
211 | } | ||
212 | } | ||
213 | DEXIT(IRDA_SR_TRACE, "\n"); | ||
214 | |||
215 | /* Return the TSAP */ | ||
216 | return(dtsap_sel); | ||
217 | } | ||
218 | |||
219 | /*------------------------------------------------------------------*/ | ||
220 | /* | ||
221 | * Function irnet_find_lsap_sel (self) | ||
222 | * | ||
223 | * Try to lookup LSAP selector in remote LM-IAS | ||
224 | * | ||
225 | * Basically, we start a IAP query, and then go to sleep. When the query | ||
226 | * return, irnet_getvalue_confirm will wake us up, and we can examine the | ||
227 | * result of the query... | ||
228 | * Note that in some case, the query fail even before we go to sleep, | ||
229 | * creating some races... | ||
230 | */ | ||
231 | static inline int | ||
232 | irnet_find_lsap_sel(irnet_socket * self) | ||
233 | { | ||
234 | DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); | ||
235 | |||
236 | /* This should not happen */ | ||
237 | DABORT(self->iriap, -EBUSY, IRDA_SR_ERROR, "busy with a previous query.\n"); | ||
238 | |||
239 | /* Create an IAP instance, will be closed in irnet_getvalue_confirm() */ | ||
240 | self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, | ||
241 | irnet_getvalue_confirm); | ||
242 | |||
243 | /* Treat unexpected signals as disconnect */ | ||
244 | self->errno = -EHOSTUNREACH; | ||
245 | |||
246 | /* Query remote LM-IAS */ | ||
247 | iriap_getvaluebyclass_request(self->iriap, self->rsaddr, self->daddr, | ||
248 | IRNET_SERVICE_NAME, IRNET_IAS_VALUE); | ||
249 | |||
250 | /* The above request is non-blocking. | ||
251 | * After a while, IrDA will call us back in irnet_getvalue_confirm() | ||
252 | * We will then call irnet_ias_to_tsap() and finish the | ||
253 | * connection procedure */ | ||
254 | |||
255 | DEXIT(IRDA_SR_TRACE, "\n"); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | /*------------------------------------------------------------------*/ | ||
260 | /* | ||
261 | * Function irnet_connect_tsap (self) | ||
262 | * | ||
263 | * Initialise the TTP socket and initiate TTP connection | ||
264 | * | ||
265 | */ | ||
266 | static inline int | ||
267 | irnet_connect_tsap(irnet_socket * self) | ||
268 | { | ||
269 | int err; | ||
270 | |||
271 | DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); | ||
272 | |||
273 | /* Open a local TSAP (an IrTTP instance) */ | ||
274 | err = irnet_open_tsap(self); | ||
275 | if(err != 0) | ||
276 | { | ||
277 | clear_bit(0, &self->ttp_connect); | ||
278 | DERROR(IRDA_SR_ERROR, "connect aborted!\n"); | ||
279 | return(err); | ||
280 | } | ||
281 | |||
282 | /* Connect to remote device */ | ||
283 | err = irttp_connect_request(self->tsap, self->dtsap_sel, | ||
284 | self->rsaddr, self->daddr, NULL, | ||
285 | self->max_sdu_size_rx, NULL); | ||
286 | if(err != 0) | ||
287 | { | ||
288 | clear_bit(0, &self->ttp_connect); | ||
289 | DERROR(IRDA_SR_ERROR, "connect aborted!\n"); | ||
290 | return(err); | ||
291 | } | ||
292 | |||
293 | /* The above call is non-blocking. | ||
294 | * After a while, the IrDA stack will either call us back in | ||
295 | * irnet_connect_confirm() or irnet_disconnect_indication() | ||
296 | * See you there ;-) */ | ||
297 | |||
298 | DEXIT(IRDA_SR_TRACE, "\n"); | ||
299 | return(err); | ||
300 | } | ||
301 | |||
302 | /*------------------------------------------------------------------*/ | ||
303 | /* | ||
304 | * Function irnet_discover_next_daddr (self) | ||
305 | * | ||
306 | * Query the IrNET TSAP of the next device in the log. | ||
307 | * | ||
308 | * Used in the TSAP discovery procedure. | ||
309 | */ | ||
310 | static inline int | ||
311 | irnet_discover_next_daddr(irnet_socket * self) | ||
312 | { | ||
313 | /* Close the last instance of IrIAP, and open a new one. | ||
314 | * We can't reuse the IrIAP instance in the IrIAP callback */ | ||
315 | if(self->iriap) | ||
316 | { | ||
317 | iriap_close(self->iriap); | ||
318 | self->iriap = NULL; | ||
319 | } | ||
320 | /* Create a new IAP instance */ | ||
321 | self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, | ||
322 | irnet_discovervalue_confirm); | ||
323 | if(self->iriap == NULL) | ||
324 | return -ENOMEM; | ||
325 | |||
326 | /* Next discovery - before the call to avoid races */ | ||
327 | self->disco_index++; | ||
328 | |||
329 | /* Check if we have one more address to try */ | ||
330 | if(self->disco_index < self->disco_number) | ||
331 | { | ||
332 | /* Query remote LM-IAS */ | ||
333 | iriap_getvaluebyclass_request(self->iriap, | ||
334 | self->discoveries[self->disco_index].saddr, | ||
335 | self->discoveries[self->disco_index].daddr, | ||
336 | IRNET_SERVICE_NAME, IRNET_IAS_VALUE); | ||
337 | /* The above request is non-blocking. | ||
338 | * After a while, IrDA will call us back in irnet_discovervalue_confirm() | ||
339 | * We will then call irnet_ias_to_tsap() and come back here again... */ | ||
340 | return(0); | ||
341 | } | ||
342 | else | ||
343 | return(1); | ||
344 | } | ||
345 | |||
346 | /*------------------------------------------------------------------*/ | ||
347 | /* | ||
348 | * Function irnet_discover_daddr_and_lsap_sel (self) | ||
349 | * | ||
350 | * This try to find a device with the requested service. | ||
351 | * | ||
352 | * Initiate a TSAP discovery procedure. | ||
353 | * It basically look into the discovery log. For each address in the list, | ||
354 | * it queries the LM-IAS of the device to find if this device offer | ||
355 | * the requested service. | ||
356 | * If there is more than one node supporting the service, we complain | ||
357 | * to the user (it should move devices around). | ||
358 | * If we find one node which have the requested TSAP, we connect to it. | ||
359 | * | ||
360 | * This function just start the whole procedure. It request the discovery | ||
361 | * log and submit the first IAS query. | ||
362 | * The bulk of the job is handled in irnet_discovervalue_confirm() | ||
363 | * | ||
364 | * Note : this procedure fails if there is more than one device in range | ||
365 | * on the same dongle, because IrLMP doesn't disconnect the LAP when the | ||
366 | * last LSAP is closed. Moreover, we would need to wait the LAP | ||
367 | * disconnection... | ||
368 | */ | ||
369 | static inline int | ||
370 | irnet_discover_daddr_and_lsap_sel(irnet_socket * self) | ||
371 | { | ||
372 | int ret; | ||
373 | |||
374 | DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); | ||
375 | |||
376 | /* Ask lmp for the current discovery log */ | ||
377 | self->discoveries = irlmp_get_discoveries(&self->disco_number, self->mask, | ||
378 | DISCOVERY_DEFAULT_SLOTS); | ||
379 | |||
380 | /* Check if the we got some results */ | ||
381 | if(self->discoveries == NULL) | ||
382 | { | ||
383 | self->disco_number = -1; | ||
384 | clear_bit(0, &self->ttp_connect); | ||
385 | DRETURN(-ENETUNREACH, IRDA_SR_INFO, "No Cachelog...\n"); | ||
386 | } | ||
387 | DEBUG(IRDA_SR_INFO, "Got the log (0x%p), size is %d\n", | ||
388 | self->discoveries, self->disco_number); | ||
389 | |||
390 | /* Start with the first discovery */ | ||
391 | self->disco_index = -1; | ||
392 | self->daddr = DEV_ADDR_ANY; | ||
393 | |||
394 | /* This will fail if the log is empty - this is non-blocking */ | ||
395 | ret = irnet_discover_next_daddr(self); | ||
396 | if(ret) | ||
397 | { | ||
398 | /* Close IAP */ | ||
399 | if(self->iriap) | ||
400 | iriap_close(self->iriap); | ||
401 | self->iriap = NULL; | ||
402 | |||
403 | /* Cleanup our copy of the discovery log */ | ||
404 | kfree(self->discoveries); | ||
405 | self->discoveries = NULL; | ||
406 | |||
407 | clear_bit(0, &self->ttp_connect); | ||
408 | DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n"); | ||
409 | } | ||
410 | |||
411 | /* Follow me in irnet_discovervalue_confirm() */ | ||
412 | |||
413 | DEXIT(IRDA_SR_TRACE, "\n"); | ||
414 | return(0); | ||
415 | } | ||
416 | |||
417 | /*------------------------------------------------------------------*/ | ||
418 | /* | ||
419 | * Function irnet_dname_to_daddr (self) | ||
420 | * | ||
421 | * Convert an IrDA nickname to a valid IrDA address | ||
422 | * | ||
423 | * It basically look into the discovery log until there is a match. | ||
424 | */ | ||
425 | static inline int | ||
426 | irnet_dname_to_daddr(irnet_socket * self) | ||
427 | { | ||
428 | struct irda_device_info *discoveries; /* Copy of the discovery log */ | ||
429 | int number; /* Number of nodes in the log */ | ||
430 | int i; | ||
431 | |||
432 | DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); | ||
433 | |||
434 | /* Ask lmp for the current discovery log */ | ||
435 | discoveries = irlmp_get_discoveries(&number, 0xffff, | ||
436 | DISCOVERY_DEFAULT_SLOTS); | ||
437 | /* Check if the we got some results */ | ||
438 | if(discoveries == NULL) | ||
439 | DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n"); | ||
440 | |||
441 | /* | ||
442 | * Now, check all discovered devices (if any), and connect | ||
443 | * client only about the services that the client is | ||
444 | * interested in... | ||
445 | */ | ||
446 | for(i = 0; i < number; i++) | ||
447 | { | ||
448 | /* Does the name match ? */ | ||
449 | if(!strncmp(discoveries[i].info, self->rname, NICKNAME_MAX_LEN)) | ||
450 | { | ||
451 | /* Yes !!! Get it.. */ | ||
452 | self->daddr = discoveries[i].daddr; | ||
453 | DEBUG(IRDA_SR_INFO, "discovered device ``%s'' at address 0x%08x.\n", | ||
454 | self->rname, self->daddr); | ||
455 | kfree(discoveries); | ||
456 | DEXIT(IRDA_SR_TRACE, "\n"); | ||
457 | return 0; | ||
458 | } | ||
459 | } | ||
460 | /* No luck ! */ | ||
461 | DEBUG(IRDA_SR_INFO, "cannot discover device ``%s'' !!!\n", self->rname); | ||
462 | kfree(discoveries); | ||
463 | return(-EADDRNOTAVAIL); | ||
464 | } | ||
465 | |||
466 | |||
467 | /************************* SOCKET ROUTINES *************************/ | ||
468 | /* | ||
469 | * This are the main operations on IrNET sockets, basically to create | ||
470 | * and destroy IrNET sockets. These are called from the PPP part... | ||
471 | */ | ||
472 | |||
473 | /*------------------------------------------------------------------*/ | ||
474 | /* | ||
475 | * Create a IrNET instance : just initialise some parameters... | ||
476 | */ | ||
477 | int | ||
478 | irda_irnet_create(irnet_socket * self) | ||
479 | { | ||
480 | DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); | ||
481 | |||
482 | self->magic = IRNET_MAGIC; /* Paranoia */ | ||
483 | |||
484 | self->ttp_open = 0; /* Prevent higher layer from accessing IrTTP */ | ||
485 | self->ttp_connect = 0; /* Not connecting yet */ | ||
486 | self->rname[0] = '\0'; /* May be set via control channel */ | ||
487 | self->rdaddr = DEV_ADDR_ANY; /* May be set via control channel */ | ||
488 | self->rsaddr = DEV_ADDR_ANY; /* May be set via control channel */ | ||
489 | self->daddr = DEV_ADDR_ANY; /* Until we get connected */ | ||
490 | self->saddr = DEV_ADDR_ANY; /* Until we get connected */ | ||
491 | self->max_sdu_size_rx = TTP_SAR_UNBOUND; | ||
492 | |||
493 | /* Register as a client with IrLMP */ | ||
494 | self->ckey = irlmp_register_client(0, NULL, NULL, NULL); | ||
495 | #ifdef DISCOVERY_NOMASK | ||
496 | self->mask = 0xffff; /* For W2k compatibility */ | ||
497 | #else /* DISCOVERY_NOMASK */ | ||
498 | self->mask = irlmp_service_to_hint(S_LAN); | ||
499 | #endif /* DISCOVERY_NOMASK */ | ||
500 | self->tx_flow = FLOW_START; /* Flow control from IrTTP */ | ||
501 | |||
502 | DEXIT(IRDA_SOCK_TRACE, "\n"); | ||
503 | return(0); | ||
504 | } | ||
505 | |||
506 | /*------------------------------------------------------------------*/ | ||
507 | /* | ||
508 | * Connect to the other side : | ||
509 | * o convert device name to an address | ||
510 | * o find the socket number (dlsap) | ||
511 | * o Establish the connection | ||
512 | * | ||
513 | * Note : We no longer mimic af_irda. The IAS query for finding the TSAP | ||
514 | * is done asynchronously, like the TTP connection. This allow us to | ||
515 | * call this function from any context (not only process). | ||
516 | * The downside is that following what's happening in there is tricky | ||
517 | * because it involve various functions all over the place... | ||
518 | */ | ||
519 | int | ||
520 | irda_irnet_connect(irnet_socket * self) | ||
521 | { | ||
522 | int err; | ||
523 | |||
524 | DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); | ||
525 | |||
526 | /* Check if we are already trying to connect. | ||
527 | * Because irda_irnet_connect() can be called directly by pppd plus | ||
528 | * packet retries in ppp_generic and connect may take time, plus we may | ||
529 | * race with irnet_connect_indication(), we need to be careful there... */ | ||
530 | if(test_and_set_bit(0, &self->ttp_connect)) | ||
531 | DRETURN(-EBUSY, IRDA_SOCK_INFO, "Already connecting...\n"); | ||
532 | if((self->iriap != NULL) || (self->tsap != NULL)) | ||
533 | DERROR(IRDA_SOCK_ERROR, "Socket not cleaned up...\n"); | ||
534 | |||
535 | /* Insert ourselves in the hashbin so that the IrNET server can find us. | ||
536 | * Notes : 4th arg is string of 32 char max and must be null terminated | ||
537 | * When 4th arg is used (string), 3rd arg isn't (int) | ||
538 | * Can't re-insert (MUST remove first) so check for that... */ | ||
539 | if((irnet_server.running) && (self->q.q_next == NULL)) | ||
540 | { | ||
541 | spin_lock_bh(&irnet_server.spinlock); | ||
542 | hashbin_insert(irnet_server.list, (irda_queue_t *) self, 0, self->rname); | ||
543 | spin_unlock_bh(&irnet_server.spinlock); | ||
544 | DEBUG(IRDA_SOCK_INFO, "Inserted ``%s'' in hashbin...\n", self->rname); | ||
545 | } | ||
546 | |||
547 | /* If we don't have anything (no address, no name) */ | ||
548 | if((self->rdaddr == DEV_ADDR_ANY) && (self->rname[0] == '\0')) | ||
549 | { | ||
550 | /* Try to find a suitable address */ | ||
551 | if((err = irnet_discover_daddr_and_lsap_sel(self)) != 0) | ||
552 | DRETURN(err, IRDA_SOCK_INFO, "auto-connect failed!\n"); | ||
553 | /* In most cases, the call above is non-blocking */ | ||
554 | } | ||
555 | else | ||
556 | { | ||
557 | /* If we have only the name (no address), try to get an address */ | ||
558 | if(self->rdaddr == DEV_ADDR_ANY) | ||
559 | { | ||
560 | if((err = irnet_dname_to_daddr(self)) != 0) | ||
561 | DRETURN(err, IRDA_SOCK_INFO, "name connect failed!\n"); | ||
562 | } | ||
563 | else | ||
564 | /* Use the requested destination address */ | ||
565 | self->daddr = self->rdaddr; | ||
566 | |||
567 | /* Query remote LM-IAS to find LSAP selector */ | ||
568 | irnet_find_lsap_sel(self); | ||
569 | /* The above call is non blocking */ | ||
570 | } | ||
571 | |||
572 | /* At this point, we are waiting for the IrDA stack to call us back, | ||
573 | * or we have already failed. | ||
574 | * We will finish the connection procedure in irnet_connect_tsap(). | ||
575 | */ | ||
576 | DEXIT(IRDA_SOCK_TRACE, "\n"); | ||
577 | return(0); | ||
578 | } | ||
579 | |||
580 | /*------------------------------------------------------------------*/ | ||
581 | /* | ||
582 | * Function irda_irnet_destroy(self) | ||
583 | * | ||
584 | * Destroy irnet instance | ||
585 | * | ||
586 | * Note : this need to be called from a process context. | ||
587 | */ | ||
588 | void | ||
589 | irda_irnet_destroy(irnet_socket * self) | ||
590 | { | ||
591 | DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); | ||
592 | if(self == NULL) | ||
593 | return; | ||
594 | |||
595 | /* Remove ourselves from hashbin (if we are queued in hashbin) | ||
596 | * Note : `irnet_server.running' protect us from calls in hashbin_delete() */ | ||
597 | if((irnet_server.running) && (self->q.q_next != NULL)) | ||
598 | { | ||
599 | struct irnet_socket * entry; | ||
600 | DEBUG(IRDA_SOCK_INFO, "Removing from hash..\n"); | ||
601 | spin_lock_bh(&irnet_server.spinlock); | ||
602 | entry = hashbin_remove_this(irnet_server.list, (irda_queue_t *) self); | ||
603 | self->q.q_next = NULL; | ||
604 | spin_unlock_bh(&irnet_server.spinlock); | ||
605 | DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n"); | ||
606 | } | ||
607 | |||
608 | /* If we were connected, post a message */ | ||
609 | if(test_bit(0, &self->ttp_open)) | ||
610 | { | ||
611 | /* Note : as the disconnect comes from ppp_generic, the unit number | ||
612 | * doesn't exist anymore when we post the event, so we need to pass | ||
613 | * NULL as the first arg... */ | ||
614 | irnet_post_event(NULL, IRNET_DISCONNECT_TO, | ||
615 | self->saddr, self->daddr, self->rname, 0); | ||
616 | } | ||
617 | |||
618 | /* Prevent various IrDA callbacks from messing up things | ||
619 | * Need to be first */ | ||
620 | clear_bit(0, &self->ttp_connect); | ||
621 | |||
622 | /* Prevent higher layer from accessing IrTTP */ | ||
623 | clear_bit(0, &self->ttp_open); | ||
624 | |||
625 | /* Unregister with IrLMP */ | ||
626 | irlmp_unregister_client(self->ckey); | ||
627 | |||
628 | /* Unregister with LM-IAS */ | ||
629 | if(self->iriap) | ||
630 | { | ||
631 | iriap_close(self->iriap); | ||
632 | self->iriap = NULL; | ||
633 | } | ||
634 | |||
635 | /* Cleanup eventual discoveries from connection attempt or control channel */ | ||
636 | if(self->discoveries != NULL) | ||
637 | { | ||
638 | /* Cleanup our copy of the discovery log */ | ||
639 | kfree(self->discoveries); | ||
640 | self->discoveries = NULL; | ||
641 | } | ||
642 | |||
643 | /* Close our IrTTP connection */ | ||
644 | if(self->tsap) | ||
645 | { | ||
646 | DEBUG(IRDA_SOCK_INFO, "Closing our TTP connection.\n"); | ||
647 | irttp_disconnect_request(self->tsap, NULL, P_NORMAL); | ||
648 | irttp_close_tsap(self->tsap); | ||
649 | self->tsap = NULL; | ||
650 | } | ||
651 | self->stsap_sel = 0; | ||
652 | |||
653 | DEXIT(IRDA_SOCK_TRACE, "\n"); | ||
654 | return; | ||
655 | } | ||
656 | |||
657 | |||
658 | /************************** SERVER SOCKET **************************/ | ||
659 | /* | ||
660 | * The IrNET service is composed of one server socket and a variable | ||
661 | * number of regular IrNET sockets. The server socket is supposed to | ||
662 | * handle incoming connections and redirect them to one IrNET sockets. | ||
663 | * It's a superset of the regular IrNET socket, but has a very distinct | ||
664 | * behaviour... | ||
665 | */ | ||
666 | |||
667 | /*------------------------------------------------------------------*/ | ||
668 | /* | ||
669 | * Function irnet_daddr_to_dname (self) | ||
670 | * | ||
671 | * Convert an IrDA address to a IrDA nickname | ||
672 | * | ||
673 | * It basically look into the discovery log until there is a match. | ||
674 | */ | ||
675 | static inline int | ||
676 | irnet_daddr_to_dname(irnet_socket * self) | ||
677 | { | ||
678 | struct irda_device_info *discoveries; /* Copy of the discovery log */ | ||
679 | int number; /* Number of nodes in the log */ | ||
680 | int i; | ||
681 | |||
682 | DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); | ||
683 | |||
684 | /* Ask lmp for the current discovery log */ | ||
685 | discoveries = irlmp_get_discoveries(&number, 0xffff, | ||
686 | DISCOVERY_DEFAULT_SLOTS); | ||
687 | /* Check if the we got some results */ | ||
688 | if (discoveries == NULL) | ||
689 | DRETURN(-ENETUNREACH, IRDA_SERV_INFO, "Cachelog empty...\n"); | ||
690 | |||
691 | /* Now, check all discovered devices (if any) */ | ||
692 | for(i = 0; i < number; i++) | ||
693 | { | ||
694 | /* Does the name match ? */ | ||
695 | if(discoveries[i].daddr == self->daddr) | ||
696 | { | ||
697 | /* Yes !!! Get it.. */ | ||
698 | strlcpy(self->rname, discoveries[i].info, sizeof(self->rname)); | ||
699 | self->rname[NICKNAME_MAX_LEN + 1] = '\0'; | ||
700 | DEBUG(IRDA_SERV_INFO, "Device 0x%08x is in fact ``%s''.\n", | ||
701 | self->daddr, self->rname); | ||
702 | kfree(discoveries); | ||
703 | DEXIT(IRDA_SERV_TRACE, "\n"); | ||
704 | return 0; | ||
705 | } | ||
706 | } | ||
707 | /* No luck ! */ | ||
708 | DEXIT(IRDA_SERV_INFO, ": cannot discover device 0x%08x !!!\n", self->daddr); | ||
709 | kfree(discoveries); | ||
710 | return(-EADDRNOTAVAIL); | ||
711 | } | ||
712 | |||
713 | /*------------------------------------------------------------------*/ | ||
714 | /* | ||
715 | * Function irda_find_socket (self) | ||
716 | * | ||
717 | * Find the correct IrNET socket | ||
718 | * | ||
719 | * Look into the list of IrNET sockets and finds one with the right | ||
720 | * properties... | ||
721 | */ | ||
722 | static inline irnet_socket * | ||
723 | irnet_find_socket(irnet_socket * self) | ||
724 | { | ||
725 | irnet_socket * new = (irnet_socket *) NULL; | ||
726 | int err; | ||
727 | |||
728 | DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); | ||
729 | |||
730 | /* Get the addresses of the requester */ | ||
731 | self->daddr = irttp_get_daddr(self->tsap); | ||
732 | self->saddr = irttp_get_saddr(self->tsap); | ||
733 | |||
734 | /* Try to get the IrDA nickname of the requester */ | ||
735 | err = irnet_daddr_to_dname(self); | ||
736 | |||
737 | /* Protect access to the instance list */ | ||
738 | spin_lock_bh(&irnet_server.spinlock); | ||
739 | |||
740 | /* So now, try to get an socket having specifically | ||
741 | * requested that nickname */ | ||
742 | if(err == 0) | ||
743 | { | ||
744 | new = (irnet_socket *) hashbin_find(irnet_server.list, | ||
745 | 0, self->rname); | ||
746 | if(new) | ||
747 | DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches rname ``%s''.\n", | ||
748 | new, new->rname); | ||
749 | } | ||
750 | |||
751 | /* If no name matches, try to find an socket by the destination address */ | ||
752 | /* It can be either the requested destination address (set via the | ||
753 | * control channel), or the current destination address if the | ||
754 | * socket is in the middle of a connection request */ | ||
755 | if(new == (irnet_socket *) NULL) | ||
756 | { | ||
757 | new = (irnet_socket *) hashbin_get_first(irnet_server.list); | ||
758 | while(new !=(irnet_socket *) NULL) | ||
759 | { | ||
760 | /* Does it have the same address ? */ | ||
761 | if((new->rdaddr == self->daddr) || (new->daddr == self->daddr)) | ||
762 | { | ||
763 | /* Yes !!! Get it.. */ | ||
764 | DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches daddr %#08x.\n", | ||
765 | new, self->daddr); | ||
766 | break; | ||
767 | } | ||
768 | new = (irnet_socket *) hashbin_get_next(irnet_server.list); | ||
769 | } | ||
770 | } | ||
771 | |||
772 | /* If we don't have any socket, get the first unconnected socket */ | ||
773 | if(new == (irnet_socket *) NULL) | ||
774 | { | ||
775 | new = (irnet_socket *) hashbin_get_first(irnet_server.list); | ||
776 | while(new !=(irnet_socket *) NULL) | ||
777 | { | ||
778 | /* Is it available ? */ | ||
779 | if(!(test_bit(0, &new->ttp_open)) && (new->rdaddr == DEV_ADDR_ANY) && | ||
780 | (new->rname[0] == '\0') && (new->ppp_open)) | ||
781 | { | ||
782 | /* Yes !!! Get it.. */ | ||
783 | DEBUG(IRDA_SERV_INFO, "Socket 0x%p is free.\n", | ||
784 | new); | ||
785 | break; | ||
786 | } | ||
787 | new = (irnet_socket *) hashbin_get_next(irnet_server.list); | ||
788 | } | ||
789 | } | ||
790 | |||
791 | /* Spin lock end */ | ||
792 | spin_unlock_bh(&irnet_server.spinlock); | ||
793 | |||
794 | DEXIT(IRDA_SERV_TRACE, " - new = 0x%p\n", new); | ||
795 | return new; | ||
796 | } | ||
797 | |||
798 | /*------------------------------------------------------------------*/ | ||
799 | /* | ||
800 | * Function irda_connect_socket (self) | ||
801 | * | ||
802 | * Connect an incoming connection to the socket | ||
803 | * | ||
804 | */ | ||
805 | static inline int | ||
806 | irnet_connect_socket(irnet_socket * server, | ||
807 | irnet_socket * new, | ||
808 | struct qos_info * qos, | ||
809 | __u32 max_sdu_size, | ||
810 | __u8 max_header_size) | ||
811 | { | ||
812 | DENTER(IRDA_SERV_TRACE, "(server=0x%p, new=0x%p)\n", | ||
813 | server, new); | ||
814 | |||
815 | /* Now attach up the new socket */ | ||
816 | new->tsap = irttp_dup(server->tsap, new); | ||
817 | DABORT(new->tsap == NULL, -1, IRDA_SERV_ERROR, "dup failed!\n"); | ||
818 | |||
819 | /* Set up all the relevant parameters on the new socket */ | ||
820 | new->stsap_sel = new->tsap->stsap_sel; | ||
821 | new->dtsap_sel = new->tsap->dtsap_sel; | ||
822 | new->saddr = irttp_get_saddr(new->tsap); | ||
823 | new->daddr = irttp_get_daddr(new->tsap); | ||
824 | |||
825 | new->max_header_size = max_header_size; | ||
826 | new->max_sdu_size_tx = max_sdu_size; | ||
827 | new->max_data_size = max_sdu_size; | ||
828 | #ifdef STREAM_COMPAT | ||
829 | /* If we want to receive "stream sockets" */ | ||
830 | if(max_sdu_size == 0) | ||
831 | new->max_data_size = irttp_get_max_seg_size(new->tsap); | ||
832 | #endif /* STREAM_COMPAT */ | ||
833 | |||
834 | /* Clean up the original one to keep it in listen state */ | ||
835 | irttp_listen(server->tsap); | ||
836 | |||
837 | /* Send a connection response on the new socket */ | ||
838 | irttp_connect_response(new->tsap, new->max_sdu_size_rx, NULL); | ||
839 | |||
840 | /* Allow PPP to send its junk over the new socket... */ | ||
841 | set_bit(0, &new->ttp_open); | ||
842 | |||
843 | /* Not connecting anymore, and clean up last possible remains | ||
844 | * of connection attempts on the socket */ | ||
845 | clear_bit(0, &new->ttp_connect); | ||
846 | if(new->iriap) | ||
847 | { | ||
848 | iriap_close(new->iriap); | ||
849 | new->iriap = NULL; | ||
850 | } | ||
851 | if(new->discoveries != NULL) | ||
852 | { | ||
853 | kfree(new->discoveries); | ||
854 | new->discoveries = NULL; | ||
855 | } | ||
856 | |||
857 | #ifdef CONNECT_INDIC_KICK | ||
858 | /* As currently we don't block packets in ppp_irnet_send() while passive, | ||
859 | * this is not really needed... | ||
860 | * Also, not doing it give IrDA a chance to finish the setup properly | ||
861 | * before being swamped with packets... */ | ||
862 | ppp_output_wakeup(&new->chan); | ||
863 | #endif /* CONNECT_INDIC_KICK */ | ||
864 | |||
865 | /* Notify the control channel */ | ||
866 | irnet_post_event(new, IRNET_CONNECT_FROM, | ||
867 | new->saddr, new->daddr, server->rname, 0); | ||
868 | |||
869 | DEXIT(IRDA_SERV_TRACE, "\n"); | ||
870 | return 0; | ||
871 | } | ||
872 | |||
873 | /*------------------------------------------------------------------*/ | ||
874 | /* | ||
875 | * Function irda_disconnect_server (self) | ||
876 | * | ||
877 | * Cleanup the server socket when the incoming connection abort | ||
878 | * | ||
879 | */ | ||
880 | static inline void | ||
881 | irnet_disconnect_server(irnet_socket * self, | ||
882 | struct sk_buff *skb) | ||
883 | { | ||
884 | DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); | ||
885 | |||
886 | /* Put the received packet in the black hole */ | ||
887 | kfree_skb(skb); | ||
888 | |||
889 | #ifdef FAIL_SEND_DISCONNECT | ||
890 | /* Tell the other party we don't want to be connected */ | ||
891 | /* Hum... Is it the right thing to do ? And do we need to send | ||
892 | * a connect response before ? It looks ok without this... */ | ||
893 | irttp_disconnect_request(self->tsap, NULL, P_NORMAL); | ||
894 | #endif /* FAIL_SEND_DISCONNECT */ | ||
895 | |||
896 | /* Notify the control channel (see irnet_find_socket()) */ | ||
897 | irnet_post_event(NULL, IRNET_REQUEST_FROM, | ||
898 | self->saddr, self->daddr, self->rname, 0); | ||
899 | |||
900 | /* Clean up the server to keep it in listen state */ | ||
901 | irttp_listen(self->tsap); | ||
902 | |||
903 | DEXIT(IRDA_SERV_TRACE, "\n"); | ||
904 | return; | ||
905 | } | ||
906 | |||
907 | /*------------------------------------------------------------------*/ | ||
908 | /* | ||
909 | * Function irda_setup_server (self) | ||
910 | * | ||
911 | * Create a IrTTP server and set it up... | ||
912 | * | ||
913 | * Register the IrLAN hint bit, create a IrTTP instance for us, | ||
914 | * set all the IrTTP callbacks and create an IrIAS entry... | ||
915 | */ | ||
916 | static inline int | ||
917 | irnet_setup_server(void) | ||
918 | { | ||
919 | __u16 hints; | ||
920 | |||
921 | DENTER(IRDA_SERV_TRACE, "()\n"); | ||
922 | |||
923 | /* Initialise the regular socket part of the server */ | ||
924 | irda_irnet_create(&irnet_server.s); | ||
925 | |||
926 | /* Open a local TSAP (an IrTTP instance) for the server */ | ||
927 | irnet_open_tsap(&irnet_server.s); | ||
928 | |||
929 | /* PPP part setup */ | ||
930 | irnet_server.s.ppp_open = 0; | ||
931 | irnet_server.s.chan.private = NULL; | ||
932 | irnet_server.s.file = NULL; | ||
933 | |||
934 | /* Get the hint bit corresponding to IrLAN */ | ||
935 | /* Note : we overload the IrLAN hint bit. As it is only a "hint", and as | ||
936 | * we provide roughly the same functionality as IrLAN, this is ok. | ||
937 | * In fact, the situation is similar as JetSend overloading the Obex hint | ||
938 | */ | ||
939 | hints = irlmp_service_to_hint(S_LAN); | ||
940 | |||
941 | #ifdef ADVERTISE_HINT | ||
942 | /* Register with IrLMP as a service (advertise our hint bit) */ | ||
943 | irnet_server.skey = irlmp_register_service(hints); | ||
944 | #endif /* ADVERTISE_HINT */ | ||
945 | |||
946 | /* Register with LM-IAS (so that people can connect to us) */ | ||
947 | irnet_server.ias_obj = irias_new_object(IRNET_SERVICE_NAME, jiffies); | ||
948 | irias_add_integer_attrib(irnet_server.ias_obj, IRNET_IAS_VALUE, | ||
949 | irnet_server.s.stsap_sel, IAS_KERNEL_ATTR); | ||
950 | irias_insert_object(irnet_server.ias_obj); | ||
951 | |||
952 | #ifdef DISCOVERY_EVENTS | ||
953 | /* Tell IrLMP we want to be notified of newly discovered nodes */ | ||
954 | irlmp_update_client(irnet_server.s.ckey, hints, | ||
955 | irnet_discovery_indication, irnet_expiry_indication, | ||
956 | (void *) &irnet_server.s); | ||
957 | #endif | ||
958 | |||
959 | DEXIT(IRDA_SERV_TRACE, " - self=0x%p\n", &irnet_server.s); | ||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | /*------------------------------------------------------------------*/ | ||
964 | /* | ||
965 | * Function irda_destroy_server (self) | ||
966 | * | ||
967 | * Destroy the IrTTP server... | ||
968 | * | ||
969 | * Reverse of the previous function... | ||
970 | */ | ||
971 | static inline void | ||
972 | irnet_destroy_server(void) | ||
973 | { | ||
974 | DENTER(IRDA_SERV_TRACE, "()\n"); | ||
975 | |||
976 | #ifdef ADVERTISE_HINT | ||
977 | /* Unregister with IrLMP */ | ||
978 | irlmp_unregister_service(irnet_server.skey); | ||
979 | #endif /* ADVERTISE_HINT */ | ||
980 | |||
981 | /* Unregister with LM-IAS */ | ||
982 | if(irnet_server.ias_obj) | ||
983 | irias_delete_object(irnet_server.ias_obj); | ||
984 | |||
985 | /* Cleanup the socket part */ | ||
986 | irda_irnet_destroy(&irnet_server.s); | ||
987 | |||
988 | DEXIT(IRDA_SERV_TRACE, "\n"); | ||
989 | return; | ||
990 | } | ||
991 | |||
992 | |||
993 | /************************ IRDA-TTP CALLBACKS ************************/ | ||
994 | /* | ||
995 | * When we create a IrTTP instance, we pass to it a set of callbacks | ||
996 | * that IrTTP will call in case of various events. | ||
997 | * We take care of those events here. | ||
998 | */ | ||
999 | |||
1000 | /*------------------------------------------------------------------*/ | ||
1001 | /* | ||
1002 | * Function irnet_data_indication (instance, sap, skb) | ||
1003 | * | ||
1004 | * Received some data from TinyTP. Just queue it on the receive queue | ||
1005 | * | ||
1006 | */ | ||
1007 | static int | ||
1008 | irnet_data_indication(void * instance, | ||
1009 | void * sap, | ||
1010 | struct sk_buff *skb) | ||
1011 | { | ||
1012 | irnet_socket * ap = (irnet_socket *) instance; | ||
1013 | unsigned char * p; | ||
1014 | int code = 0; | ||
1015 | |||
1016 | DENTER(IRDA_TCB_TRACE, "(self/ap=0x%p, skb=0x%p)\n", | ||
1017 | ap, skb); | ||
1018 | DASSERT(skb != NULL, 0, IRDA_CB_ERROR, "skb is NULL !!!\n"); | ||
1019 | |||
1020 | /* Check is ppp is ready to receive our packet */ | ||
1021 | if(!ap->ppp_open) | ||
1022 | { | ||
1023 | DERROR(IRDA_CB_ERROR, "PPP not ready, dropping packet...\n"); | ||
1024 | /* When we return error, TTP will need to requeue the skb and | ||
1025 | * will stop the sender. IrTTP will stall until we send it a | ||
1026 | * flow control request... */ | ||
1027 | return -ENOMEM; | ||
1028 | } | ||
1029 | |||
1030 | /* strip address/control field if present */ | ||
1031 | p = skb->data; | ||
1032 | if((p[0] == PPP_ALLSTATIONS) && (p[1] == PPP_UI)) | ||
1033 | { | ||
1034 | /* chop off address/control */ | ||
1035 | if(skb->len < 3) | ||
1036 | goto err_exit; | ||
1037 | p = skb_pull(skb, 2); | ||
1038 | } | ||
1039 | |||
1040 | /* decompress protocol field if compressed */ | ||
1041 | if(p[0] & 1) | ||
1042 | { | ||
1043 | /* protocol is compressed */ | ||
1044 | skb_push(skb, 1)[0] = 0; | ||
1045 | } | ||
1046 | else | ||
1047 | if(skb->len < 2) | ||
1048 | goto err_exit; | ||
1049 | |||
1050 | /* pass to generic ppp layer */ | ||
1051 | /* Note : how do I know if ppp can accept or not the packet ? This is | ||
1052 | * essential if I want to manage flow control smoothly... */ | ||
1053 | ppp_input(&ap->chan, skb); | ||
1054 | |||
1055 | DEXIT(IRDA_TCB_TRACE, "\n"); | ||
1056 | return 0; | ||
1057 | |||
1058 | err_exit: | ||
1059 | DERROR(IRDA_CB_ERROR, "Packet too small, dropping...\n"); | ||
1060 | kfree_skb(skb); | ||
1061 | ppp_input_error(&ap->chan, code); | ||
1062 | return 0; /* Don't return an error code, only for flow control... */ | ||
1063 | } | ||
1064 | |||
1065 | /*------------------------------------------------------------------*/ | ||
1066 | /* | ||
1067 | * Function irnet_disconnect_indication (instance, sap, reason, skb) | ||
1068 | * | ||
1069 | * Connection has been closed. Chech reason to find out why | ||
1070 | * | ||
1071 | * Note : there are many cases where we come here : | ||
1072 | * o attempted to connect, timeout | ||
1073 | * o connected, link is broken, LAP has timeout | ||
1074 | * o connected, other side close the link | ||
1075 | * o connection request on the server not handled | ||
1076 | */ | ||
1077 | static void | ||
1078 | irnet_disconnect_indication(void * instance, | ||
1079 | void * sap, | ||
1080 | LM_REASON reason, | ||
1081 | struct sk_buff *skb) | ||
1082 | { | ||
1083 | irnet_socket * self = (irnet_socket *) instance; | ||
1084 | int test_open; | ||
1085 | int test_connect; | ||
1086 | |||
1087 | DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); | ||
1088 | DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); | ||
1089 | |||
1090 | /* Don't care about it, but let's not leak it */ | ||
1091 | if(skb) | ||
1092 | dev_kfree_skb(skb); | ||
1093 | |||
1094 | /* Prevent higher layer from accessing IrTTP */ | ||
1095 | test_open = test_and_clear_bit(0, &self->ttp_open); | ||
1096 | /* Not connecting anymore... | ||
1097 | * (note : TSAP is open, so IAP callbacks are no longer pending...) */ | ||
1098 | test_connect = test_and_clear_bit(0, &self->ttp_connect); | ||
1099 | |||
1100 | /* If both self->ttp_open and self->ttp_connect are NULL, it mean that we | ||
1101 | * have a race condition with irda_irnet_destroy() or | ||
1102 | * irnet_connect_indication(), so don't mess up tsap... | ||
1103 | */ | ||
1104 | if(!(test_open || test_connect)) | ||
1105 | { | ||
1106 | DERROR(IRDA_CB_ERROR, "Race condition detected...\n"); | ||
1107 | return; | ||
1108 | } | ||
1109 | |||
1110 | /* If we were active, notify the control channel */ | ||
1111 | if(test_open) | ||
1112 | irnet_post_event(self, IRNET_DISCONNECT_FROM, | ||
1113 | self->saddr, self->daddr, self->rname, 0); | ||
1114 | else | ||
1115 | /* If we were trying to connect, notify the control channel */ | ||
1116 | if((self->tsap) && (self != &irnet_server.s)) | ||
1117 | irnet_post_event(self, IRNET_NOANSWER_FROM, | ||
1118 | self->saddr, self->daddr, self->rname, 0); | ||
1119 | |||
1120 | /* Close our IrTTP connection, cleanup tsap */ | ||
1121 | if((self->tsap) && (self != &irnet_server.s)) | ||
1122 | { | ||
1123 | DEBUG(IRDA_CB_INFO, "Closing our TTP connection.\n"); | ||
1124 | irttp_close_tsap(self->tsap); | ||
1125 | self->tsap = NULL; | ||
1126 | } | ||
1127 | /* Cleanup the socket in case we want to reconnect in ppp_output_wakeup() */ | ||
1128 | self->stsap_sel = 0; | ||
1129 | self->daddr = DEV_ADDR_ANY; | ||
1130 | self->tx_flow = FLOW_START; | ||
1131 | |||
1132 | /* Deal with the ppp instance if it's still alive */ | ||
1133 | if(self->ppp_open) | ||
1134 | { | ||
1135 | if(test_open) | ||
1136 | { | ||
1137 | #ifdef MISSING_PPP_API | ||
1138 | /* ppp_unregister_channel() wants a user context, which we | ||
1139 | * are guaranteed to NOT have here. What are we supposed | ||
1140 | * to do here ? Jean II */ | ||
1141 | /* If we were connected, cleanup & close the PPP channel, | ||
1142 | * which will kill pppd (hangup) and the rest */ | ||
1143 | ppp_unregister_channel(&self->chan); | ||
1144 | self->ppp_open = 0; | ||
1145 | #endif | ||
1146 | } | ||
1147 | else | ||
1148 | { | ||
1149 | /* If we were trying to connect, flush (drain) ppp_generic | ||
1150 | * Tx queue (most often we have blocked it), which will | ||
1151 | * trigger an other attempt to connect. If we are passive, | ||
1152 | * this will empty the Tx queue after last try. */ | ||
1153 | ppp_output_wakeup(&self->chan); | ||
1154 | } | ||
1155 | } | ||
1156 | |||
1157 | DEXIT(IRDA_TCB_TRACE, "\n"); | ||
1158 | } | ||
1159 | |||
1160 | /*------------------------------------------------------------------*/ | ||
1161 | /* | ||
1162 | * Function irnet_connect_confirm (instance, sap, qos, max_sdu_size, skb) | ||
1163 | * | ||
1164 | * Connections has been confirmed by the remote device | ||
1165 | * | ||
1166 | */ | ||
1167 | static void | ||
1168 | irnet_connect_confirm(void * instance, | ||
1169 | void * sap, | ||
1170 | struct qos_info *qos, | ||
1171 | __u32 max_sdu_size, | ||
1172 | __u8 max_header_size, | ||
1173 | struct sk_buff *skb) | ||
1174 | { | ||
1175 | irnet_socket * self = (irnet_socket *) instance; | ||
1176 | |||
1177 | DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); | ||
1178 | |||
1179 | /* Check if socket is closing down (via irda_irnet_destroy()) */ | ||
1180 | if(! test_bit(0, &self->ttp_connect)) | ||
1181 | { | ||
1182 | DERROR(IRDA_CB_ERROR, "Socket no longer connecting. Ouch !\n"); | ||
1183 | return; | ||
1184 | } | ||
1185 | |||
1186 | /* How much header space do we need to reserve */ | ||
1187 | self->max_header_size = max_header_size; | ||
1188 | |||
1189 | /* IrTTP max SDU size in transmit direction */ | ||
1190 | self->max_sdu_size_tx = max_sdu_size; | ||
1191 | self->max_data_size = max_sdu_size; | ||
1192 | #ifdef STREAM_COMPAT | ||
1193 | if(max_sdu_size == 0) | ||
1194 | self->max_data_size = irttp_get_max_seg_size(self->tsap); | ||
1195 | #endif /* STREAM_COMPAT */ | ||
1196 | |||
1197 | /* At this point, IrLMP has assigned our source address */ | ||
1198 | self->saddr = irttp_get_saddr(self->tsap); | ||
1199 | |||
1200 | /* Allow higher layer to access IrTTP */ | ||
1201 | set_bit(0, &self->ttp_open); | ||
1202 | clear_bit(0, &self->ttp_connect); /* Not racy, IrDA traffic is serial */ | ||
1203 | /* Give a kick in the ass of ppp_generic so that he sends us some data */ | ||
1204 | ppp_output_wakeup(&self->chan); | ||
1205 | |||
1206 | /* Check size of received packet */ | ||
1207 | if(skb->len > 0) | ||
1208 | { | ||
1209 | #ifdef PASS_CONNECT_PACKETS | ||
1210 | DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n"); | ||
1211 | /* Try to pass it to PPP */ | ||
1212 | irnet_data_indication(instance, sap, skb); | ||
1213 | #else /* PASS_CONNECT_PACKETS */ | ||
1214 | DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n"); | ||
1215 | kfree_skb(skb); /* Note : will be optimised with other kfree... */ | ||
1216 | #endif /* PASS_CONNECT_PACKETS */ | ||
1217 | } | ||
1218 | else | ||
1219 | kfree_skb(skb); | ||
1220 | |||
1221 | /* Notify the control channel */ | ||
1222 | irnet_post_event(self, IRNET_CONNECT_TO, | ||
1223 | self->saddr, self->daddr, self->rname, 0); | ||
1224 | |||
1225 | DEXIT(IRDA_TCB_TRACE, "\n"); | ||
1226 | } | ||
1227 | |||
1228 | /*------------------------------------------------------------------*/ | ||
1229 | /* | ||
1230 | * Function irnet_flow_indication (instance, sap, flow) | ||
1231 | * | ||
1232 | * Used by TinyTP to tell us if it can accept more data or not | ||
1233 | * | ||
1234 | */ | ||
1235 | static void | ||
1236 | irnet_flow_indication(void * instance, | ||
1237 | void * sap, | ||
1238 | LOCAL_FLOW flow) | ||
1239 | { | ||
1240 | irnet_socket * self = (irnet_socket *) instance; | ||
1241 | LOCAL_FLOW oldflow = self->tx_flow; | ||
1242 | |||
1243 | DENTER(IRDA_TCB_TRACE, "(self=0x%p, flow=%d)\n", self, flow); | ||
1244 | |||
1245 | /* Update our state */ | ||
1246 | self->tx_flow = flow; | ||
1247 | |||
1248 | /* Check what IrTTP want us to do... */ | ||
1249 | switch(flow) | ||
1250 | { | ||
1251 | case FLOW_START: | ||
1252 | DEBUG(IRDA_CB_INFO, "IrTTP wants us to start again\n"); | ||
1253 | /* Check if we really need to wake up PPP */ | ||
1254 | if(oldflow == FLOW_STOP) | ||
1255 | ppp_output_wakeup(&self->chan); | ||
1256 | else | ||
1257 | DEBUG(IRDA_CB_INFO, "But we were already transmitting !!!\n"); | ||
1258 | break; | ||
1259 | case FLOW_STOP: | ||
1260 | DEBUG(IRDA_CB_INFO, "IrTTP wants us to slow down\n"); | ||
1261 | break; | ||
1262 | default: | ||
1263 | DEBUG(IRDA_CB_INFO, "Unknown flow command!\n"); | ||
1264 | break; | ||
1265 | } | ||
1266 | |||
1267 | DEXIT(IRDA_TCB_TRACE, "\n"); | ||
1268 | } | ||
1269 | |||
1270 | /*------------------------------------------------------------------*/ | ||
1271 | /* | ||
1272 | * Function irnet_status_indication (instance, sap, reason, skb) | ||
1273 | * | ||
1274 | * Link (IrLAP) status report. | ||
1275 | * | ||
1276 | */ | ||
1277 | static void | ||
1278 | irnet_status_indication(void * instance, | ||
1279 | LINK_STATUS link, | ||
1280 | LOCK_STATUS lock) | ||
1281 | { | ||
1282 | irnet_socket * self = (irnet_socket *) instance; | ||
1283 | |||
1284 | DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); | ||
1285 | DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); | ||
1286 | |||
1287 | /* We can only get this event if we are connected */ | ||
1288 | switch(link) | ||
1289 | { | ||
1290 | case STATUS_NO_ACTIVITY: | ||
1291 | irnet_post_event(self, IRNET_BLOCKED_LINK, | ||
1292 | self->saddr, self->daddr, self->rname, 0); | ||
1293 | break; | ||
1294 | default: | ||
1295 | DEBUG(IRDA_CB_INFO, "Unknown status...\n"); | ||
1296 | } | ||
1297 | |||
1298 | DEXIT(IRDA_TCB_TRACE, "\n"); | ||
1299 | } | ||
1300 | |||
1301 | /*------------------------------------------------------------------*/ | ||
1302 | /* | ||
1303 | * Function irnet_connect_indication(instance, sap, qos, max_sdu_size, userdata) | ||
1304 | * | ||
1305 | * Incoming connection | ||
1306 | * | ||
1307 | * In theory, this function is called only on the server socket. | ||
1308 | * Some other node is attempting to connect to the IrNET service, and has | ||
1309 | * sent a connection request on our server socket. | ||
1310 | * We just redirect the connection to the relevant IrNET socket. | ||
1311 | * | ||
1312 | * Note : we also make sure that between 2 irnet nodes, there can | ||
1313 | * exist only one irnet connection. | ||
1314 | */ | ||
1315 | static void | ||
1316 | irnet_connect_indication(void * instance, | ||
1317 | void * sap, | ||
1318 | struct qos_info *qos, | ||
1319 | __u32 max_sdu_size, | ||
1320 | __u8 max_header_size, | ||
1321 | struct sk_buff *skb) | ||
1322 | { | ||
1323 | irnet_socket * server = &irnet_server.s; | ||
1324 | irnet_socket * new = (irnet_socket *) NULL; | ||
1325 | |||
1326 | DENTER(IRDA_TCB_TRACE, "(server=0x%p)\n", server); | ||
1327 | DASSERT(instance == &irnet_server, , IRDA_CB_ERROR, | ||
1328 | "Invalid instance (0x%p) !!!\n", instance); | ||
1329 | DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n"); | ||
1330 | |||
1331 | /* Try to find the most appropriate IrNET socket */ | ||
1332 | new = irnet_find_socket(server); | ||
1333 | |||
1334 | /* After all this hard work, do we have an socket ? */ | ||
1335 | if(new == (irnet_socket *) NULL) | ||
1336 | { | ||
1337 | DEXIT(IRDA_CB_INFO, ": No socket waiting for this connection.\n"); | ||
1338 | irnet_disconnect_server(server, skb); | ||
1339 | return; | ||
1340 | } | ||
1341 | |||
1342 | /* Is the socket already busy ? */ | ||
1343 | if(test_bit(0, &new->ttp_open)) | ||
1344 | { | ||
1345 | DEXIT(IRDA_CB_INFO, ": Socket already connected.\n"); | ||
1346 | irnet_disconnect_server(server, skb); | ||
1347 | return; | ||
1348 | } | ||
1349 | |||
1350 | /* The following code is a bit tricky, so need comments ;-) | ||
1351 | */ | ||
1352 | /* If ttp_connect is set, the socket is trying to connect to the other | ||
1353 | * end and may have sent a IrTTP connection request and is waiting for | ||
1354 | * a connection response (that may never come). | ||
1355 | * Now, the pain is that the socket may have opened a tsap and is | ||
1356 | * waiting on it, while the other end is trying to connect to it on | ||
1357 | * another tsap. | ||
1358 | * Because IrNET can be peer to peer, we need to workaround this. | ||
1359 | * Furthermore, the way the irnetd script is implemented, the | ||
1360 | * target will create a second IrNET connection back to the | ||
1361 | * originator and expect the originator to bind this new connection | ||
1362 | * to the original PPPD instance. | ||
1363 | * And of course, if we don't use irnetd, we can have a race when | ||
1364 | * both side try to connect simultaneously, which could leave both | ||
1365 | * connections half closed (yuck). | ||
1366 | * Conclusions : | ||
1367 | * 1) The "originator" must accept the new connection and get rid | ||
1368 | * of the old one so that irnetd works | ||
1369 | * 2) One side must deny the new connection to avoid races, | ||
1370 | * but both side must agree on which side it is... | ||
1371 | * Most often, the originator is primary at the LAP layer. | ||
1372 | * Jean II | ||
1373 | */ | ||
1374 | /* Now, let's look at the way I wrote the test... | ||
1375 | * We need to clear up the ttp_connect flag atomically to prevent | ||
1376 | * irnet_disconnect_indication() to mess up the tsap we are going to close. | ||
1377 | * We want to clear the ttp_connect flag only if we close the tsap, | ||
1378 | * otherwise we will never close it, so we need to check for primary | ||
1379 | * *before* doing the test on the flag. | ||
1380 | * And of course, ALLOW_SIMULT_CONNECT can disable this entirely... | ||
1381 | * Jean II | ||
1382 | */ | ||
1383 | |||
1384 | /* Socket already connecting ? On primary ? */ | ||
1385 | if(0 | ||
1386 | #ifdef ALLOW_SIMULT_CONNECT | ||
1387 | || ((irttp_is_primary(server->tsap) == 1) /* primary */ | ||
1388 | && (test_and_clear_bit(0, &new->ttp_connect))) | ||
1389 | #endif /* ALLOW_SIMULT_CONNECT */ | ||
1390 | ) | ||
1391 | { | ||
1392 | DERROR(IRDA_CB_ERROR, "Socket already connecting, but going to reuse it !\n"); | ||
1393 | |||
1394 | /* Cleanup the old TSAP if necessary - IrIAP will be cleaned up later */ | ||
1395 | if(new->tsap != NULL) | ||
1396 | { | ||
1397 | /* Close the old connection the new socket was attempting, | ||
1398 | * so that we can hook it up to the new connection. | ||
1399 | * It's now safe to do it... */ | ||
1400 | irttp_close_tsap(new->tsap); | ||
1401 | new->tsap = NULL; | ||
1402 | } | ||
1403 | } | ||
1404 | else | ||
1405 | { | ||
1406 | /* Three options : | ||
1407 | * 1) socket was not connecting or connected : ttp_connect should be 0. | ||
1408 | * 2) we don't want to connect the socket because we are secondary or | ||
1409 | * ALLOW_SIMULT_CONNECT is undefined. ttp_connect should be 1. | ||
1410 | * 3) we are half way in irnet_disconnect_indication(), and it's a | ||
1411 | * nice race condition... Fortunately, we can detect that by checking | ||
1412 | * if tsap is still alive. On the other hand, we can't be in | ||
1413 | * irda_irnet_destroy() otherwise we would not have found this | ||
1414 | * socket in the hashbin. | ||
1415 | * Jean II */ | ||
1416 | if((test_bit(0, &new->ttp_connect)) || (new->tsap != NULL)) | ||
1417 | { | ||
1418 | /* Don't mess this socket, somebody else in in charge... */ | ||
1419 | DERROR(IRDA_CB_ERROR, "Race condition detected, socket in use, abort connect...\n"); | ||
1420 | irnet_disconnect_server(server, skb); | ||
1421 | return; | ||
1422 | } | ||
1423 | } | ||
1424 | |||
1425 | /* So : at this point, we have a socket, and it is idle. Good ! */ | ||
1426 | irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size); | ||
1427 | |||
1428 | /* Check size of received packet */ | ||
1429 | if(skb->len > 0) | ||
1430 | { | ||
1431 | #ifdef PASS_CONNECT_PACKETS | ||
1432 | DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n"); | ||
1433 | /* Try to pass it to PPP */ | ||
1434 | irnet_data_indication(new, new->tsap, skb); | ||
1435 | #else /* PASS_CONNECT_PACKETS */ | ||
1436 | DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n"); | ||
1437 | kfree_skb(skb); /* Note : will be optimised with other kfree... */ | ||
1438 | #endif /* PASS_CONNECT_PACKETS */ | ||
1439 | } | ||
1440 | else | ||
1441 | kfree_skb(skb); | ||
1442 | |||
1443 | DEXIT(IRDA_TCB_TRACE, "\n"); | ||
1444 | } | ||
1445 | |||
1446 | |||
1447 | /********************** IRDA-IAS/LMP CALLBACKS **********************/ | ||
1448 | /* | ||
1449 | * These are the callbacks called by other layers of the IrDA stack, | ||
1450 | * mainly LMP for discovery and IAS for name queries. | ||
1451 | */ | ||
1452 | |||
1453 | /*------------------------------------------------------------------*/ | ||
1454 | /* | ||
1455 | * Function irnet_getvalue_confirm (result, obj_id, value, priv) | ||
1456 | * | ||
1457 | * Got answer from remote LM-IAS, just connect | ||
1458 | * | ||
1459 | * This is the reply to a IAS query we were doing to find the TSAP of | ||
1460 | * the device we want to connect to. | ||
1461 | * If we have found a valid TSAP, just initiate the TTP connection | ||
1462 | * on this TSAP. | ||
1463 | */ | ||
1464 | static void | ||
1465 | irnet_getvalue_confirm(int result, | ||
1466 | __u16 obj_id, | ||
1467 | struct ias_value *value, | ||
1468 | void * priv) | ||
1469 | { | ||
1470 | irnet_socket * self = (irnet_socket *) priv; | ||
1471 | |||
1472 | DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); | ||
1473 | DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); | ||
1474 | |||
1475 | /* Check if already connected (via irnet_connect_socket()) | ||
1476 | * or socket is closing down (via irda_irnet_destroy()) */ | ||
1477 | if(! test_bit(0, &self->ttp_connect)) | ||
1478 | { | ||
1479 | DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n"); | ||
1480 | return; | ||
1481 | } | ||
1482 | |||
1483 | /* We probably don't need to make any more queries */ | ||
1484 | iriap_close(self->iriap); | ||
1485 | self->iriap = NULL; | ||
1486 | |||
1487 | /* Post process the IAS reply */ | ||
1488 | self->dtsap_sel = irnet_ias_to_tsap(self, result, value); | ||
1489 | |||
1490 | /* If error, just go out */ | ||
1491 | if(self->errno) | ||
1492 | { | ||
1493 | clear_bit(0, &self->ttp_connect); | ||
1494 | DERROR(IRDA_OCB_ERROR, "IAS connect failed ! (0x%X)\n", self->errno); | ||
1495 | return; | ||
1496 | } | ||
1497 | |||
1498 | DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n", | ||
1499 | self->daddr, self->dtsap_sel); | ||
1500 | |||
1501 | /* Start up TTP - non blocking */ | ||
1502 | irnet_connect_tsap(self); | ||
1503 | |||
1504 | DEXIT(IRDA_OCB_TRACE, "\n"); | ||
1505 | } | ||
1506 | |||
1507 | /*------------------------------------------------------------------*/ | ||
1508 | /* | ||
1509 | * Function irnet_discovervalue_confirm (result, obj_id, value, priv) | ||
1510 | * | ||
1511 | * Handle the TSAP discovery procedure state machine. | ||
1512 | * Got answer from remote LM-IAS, try next device | ||
1513 | * | ||
1514 | * We are doing a TSAP discovery procedure, and we got an answer to | ||
1515 | * a IAS query we were doing to find the TSAP on one of the address | ||
1516 | * in the discovery log. | ||
1517 | * | ||
1518 | * If we have found a valid TSAP for the first time, save it. If it's | ||
1519 | * not the first time we found one, complain. | ||
1520 | * | ||
1521 | * If we have more addresses in the log, just initiate a new query. | ||
1522 | * Note that those query may fail (see irnet_discover_daddr_and_lsap_sel()) | ||
1523 | * | ||
1524 | * Otherwise, wrap up the procedure (cleanup), check if we have found | ||
1525 | * any device and connect to it. | ||
1526 | */ | ||
1527 | static void | ||
1528 | irnet_discovervalue_confirm(int result, | ||
1529 | __u16 obj_id, | ||
1530 | struct ias_value *value, | ||
1531 | void * priv) | ||
1532 | { | ||
1533 | irnet_socket * self = (irnet_socket *) priv; | ||
1534 | __u8 dtsap_sel; /* TSAP we are looking for */ | ||
1535 | |||
1536 | DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); | ||
1537 | DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); | ||
1538 | |||
1539 | /* Check if already connected (via irnet_connect_socket()) | ||
1540 | * or socket is closing down (via irda_irnet_destroy()) */ | ||
1541 | if(! test_bit(0, &self->ttp_connect)) | ||
1542 | { | ||
1543 | DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n"); | ||
1544 | return; | ||
1545 | } | ||
1546 | |||
1547 | /* Post process the IAS reply */ | ||
1548 | dtsap_sel = irnet_ias_to_tsap(self, result, value); | ||
1549 | |||
1550 | /* Have we got something ? */ | ||
1551 | if(self->errno == 0) | ||
1552 | { | ||
1553 | /* We found the requested service */ | ||
1554 | if(self->daddr != DEV_ADDR_ANY) | ||
1555 | { | ||
1556 | DERROR(IRDA_OCB_ERROR, "More than one device in range supports IrNET...\n"); | ||
1557 | } | ||
1558 | else | ||
1559 | { | ||
1560 | /* First time we found that one, save it ! */ | ||
1561 | self->daddr = self->discoveries[self->disco_index].daddr; | ||
1562 | self->dtsap_sel = dtsap_sel; | ||
1563 | } | ||
1564 | } | ||
1565 | |||
1566 | /* If no failure */ | ||
1567 | if((self->errno == -EADDRNOTAVAIL) || (self->errno == 0)) | ||
1568 | { | ||
1569 | int ret; | ||
1570 | |||
1571 | /* Search the next node */ | ||
1572 | ret = irnet_discover_next_daddr(self); | ||
1573 | if(!ret) | ||
1574 | { | ||
1575 | /* In this case, the above request was non-blocking. | ||
1576 | * We will return here after a while... */ | ||
1577 | return; | ||
1578 | } | ||
1579 | /* In this case, we have processed the last discovery item */ | ||
1580 | } | ||
1581 | |||
1582 | /* No more queries to be done (failure or last one) */ | ||
1583 | |||
1584 | /* We probably don't need to make any more queries */ | ||
1585 | iriap_close(self->iriap); | ||
1586 | self->iriap = NULL; | ||
1587 | |||
1588 | /* No more items : remove the log and signal termination */ | ||
1589 | DEBUG(IRDA_OCB_INFO, "Cleaning up log (0x%p)\n", | ||
1590 | self->discoveries); | ||
1591 | if(self->discoveries != NULL) | ||
1592 | { | ||
1593 | /* Cleanup our copy of the discovery log */ | ||
1594 | kfree(self->discoveries); | ||
1595 | self->discoveries = NULL; | ||
1596 | } | ||
1597 | self->disco_number = -1; | ||
1598 | |||
1599 | /* Check out what we found */ | ||
1600 | if(self->daddr == DEV_ADDR_ANY) | ||
1601 | { | ||
1602 | self->daddr = DEV_ADDR_ANY; | ||
1603 | clear_bit(0, &self->ttp_connect); | ||
1604 | DEXIT(IRDA_OCB_TRACE, ": cannot discover IrNET in any device !!!\n"); | ||
1605 | return; | ||
1606 | } | ||
1607 | |||
1608 | /* We have a valid address - just connect */ | ||
1609 | |||
1610 | DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n", | ||
1611 | self->daddr, self->dtsap_sel); | ||
1612 | |||
1613 | /* Start up TTP - non blocking */ | ||
1614 | irnet_connect_tsap(self); | ||
1615 | |||
1616 | DEXIT(IRDA_OCB_TRACE, "\n"); | ||
1617 | } | ||
1618 | |||
1619 | #ifdef DISCOVERY_EVENTS | ||
1620 | /*------------------------------------------------------------------*/ | ||
1621 | /* | ||
1622 | * Function irnet_discovery_indication (discovery) | ||
1623 | * | ||
1624 | * Got a discovery indication from IrLMP, post an event | ||
1625 | * | ||
1626 | * Note : IrLMP take care of matching the hint mask for us, and also | ||
1627 | * check if it is a "new" node for us... | ||
1628 | * | ||
1629 | * As IrLMP filter on the IrLAN hint bit, we get both IrLAN and IrNET | ||
1630 | * nodes, so it's only at connection time that we will know if the | ||
1631 | * node support IrNET, IrLAN or both. The other solution is to check | ||
1632 | * in IAS the PNP ids and service name. | ||
1633 | * Note : even if a node support IrNET (or IrLAN), it's no guarantee | ||
1634 | * that we will be able to connect to it, the node might already be | ||
1635 | * busy... | ||
1636 | * | ||
1637 | * One last thing : in some case, this function will trigger duplicate | ||
1638 | * discovery events. On the other hand, we should catch all | ||
1639 | * discoveries properly (i.e. not miss one). Filtering duplicate here | ||
1640 | * is to messy, so we leave that to user space... | ||
1641 | */ | ||
1642 | static void | ||
1643 | irnet_discovery_indication(discinfo_t * discovery, | ||
1644 | DISCOVERY_MODE mode, | ||
1645 | void * priv) | ||
1646 | { | ||
1647 | irnet_socket * self = &irnet_server.s; | ||
1648 | |||
1649 | DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); | ||
1650 | DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, | ||
1651 | "Invalid instance (0x%p) !!!\n", priv); | ||
1652 | |||
1653 | DEBUG(IRDA_OCB_INFO, "Discovered new IrNET/IrLAN node %s...\n", | ||
1654 | discovery->info); | ||
1655 | |||
1656 | /* Notify the control channel */ | ||
1657 | irnet_post_event(NULL, IRNET_DISCOVER, | ||
1658 | discovery->saddr, discovery->daddr, discovery->info, | ||
1659 | u16ho(discovery->hints)); | ||
1660 | |||
1661 | DEXIT(IRDA_OCB_TRACE, "\n"); | ||
1662 | } | ||
1663 | |||
1664 | /*------------------------------------------------------------------*/ | ||
1665 | /* | ||
1666 | * Function irnet_expiry_indication (expiry) | ||
1667 | * | ||
1668 | * Got a expiry indication from IrLMP, post an event | ||
1669 | * | ||
1670 | * Note : IrLMP take care of matching the hint mask for us, we only | ||
1671 | * check if it is a "new" node... | ||
1672 | */ | ||
1673 | static void | ||
1674 | irnet_expiry_indication(discinfo_t * expiry, | ||
1675 | DISCOVERY_MODE mode, | ||
1676 | void * priv) | ||
1677 | { | ||
1678 | irnet_socket * self = &irnet_server.s; | ||
1679 | |||
1680 | DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); | ||
1681 | DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, | ||
1682 | "Invalid instance (0x%p) !!!\n", priv); | ||
1683 | |||
1684 | DEBUG(IRDA_OCB_INFO, "IrNET/IrLAN node %s expired...\n", | ||
1685 | expiry->info); | ||
1686 | |||
1687 | /* Notify the control channel */ | ||
1688 | irnet_post_event(NULL, IRNET_EXPIRE, | ||
1689 | expiry->saddr, expiry->daddr, expiry->info, | ||
1690 | u16ho(expiry->hints)); | ||
1691 | |||
1692 | DEXIT(IRDA_OCB_TRACE, "\n"); | ||
1693 | } | ||
1694 | #endif /* DISCOVERY_EVENTS */ | ||
1695 | |||
1696 | |||
1697 | /*********************** PROC ENTRY CALLBACKS ***********************/ | ||
1698 | /* | ||
1699 | * We create a instance in the /proc filesystem, and here we take care | ||
1700 | * of that... | ||
1701 | */ | ||
1702 | |||
1703 | #ifdef CONFIG_PROC_FS | ||
1704 | /*------------------------------------------------------------------*/ | ||
1705 | /* | ||
1706 | * Function irnet_proc_read (buf, start, offset, len, unused) | ||
1707 | * | ||
1708 | * Give some info to the /proc file system | ||
1709 | */ | ||
1710 | static int | ||
1711 | irnet_proc_read(char * buf, | ||
1712 | char ** start, | ||
1713 | off_t offset, | ||
1714 | int len) | ||
1715 | { | ||
1716 | irnet_socket * self; | ||
1717 | char * state; | ||
1718 | int i = 0; | ||
1719 | |||
1720 | len = 0; | ||
1721 | |||
1722 | /* Get the IrNET server information... */ | ||
1723 | len += sprintf(buf+len, "IrNET server - "); | ||
1724 | len += sprintf(buf+len, "IrDA state: %s, ", | ||
1725 | (irnet_server.running ? "running" : "dead")); | ||
1726 | len += sprintf(buf+len, "stsap_sel: %02x, ", irnet_server.s.stsap_sel); | ||
1727 | len += sprintf(buf+len, "dtsap_sel: %02x\n", irnet_server.s.dtsap_sel); | ||
1728 | |||
1729 | /* Do we need to continue ? */ | ||
1730 | if(!irnet_server.running) | ||
1731 | return len; | ||
1732 | |||
1733 | /* Protect access to the instance list */ | ||
1734 | spin_lock_bh(&irnet_server.spinlock); | ||
1735 | |||
1736 | /* Get the sockets one by one... */ | ||
1737 | self = (irnet_socket *) hashbin_get_first(irnet_server.list); | ||
1738 | while(self != NULL) | ||
1739 | { | ||
1740 | /* Start printing info about the socket. */ | ||
1741 | len += sprintf(buf+len, "\nIrNET socket %d - ", i++); | ||
1742 | |||
1743 | /* First, get the requested configuration */ | ||
1744 | len += sprintf(buf+len, "Requested IrDA name: \"%s\", ", self->rname); | ||
1745 | len += sprintf(buf+len, "daddr: %08x, ", self->rdaddr); | ||
1746 | len += sprintf(buf+len, "saddr: %08x\n", self->rsaddr); | ||
1747 | |||
1748 | /* Second, get all the PPP info */ | ||
1749 | len += sprintf(buf+len, " PPP state: %s", | ||
1750 | (self->ppp_open ? "registered" : "unregistered")); | ||
1751 | if(self->ppp_open) | ||
1752 | { | ||
1753 | len += sprintf(buf+len, ", unit: ppp%d", | ||
1754 | ppp_unit_number(&self->chan)); | ||
1755 | len += sprintf(buf+len, ", channel: %d", | ||
1756 | ppp_channel_index(&self->chan)); | ||
1757 | len += sprintf(buf+len, ", mru: %d", | ||
1758 | self->mru); | ||
1759 | /* Maybe add self->flags ? Later... */ | ||
1760 | } | ||
1761 | |||
1762 | /* Then, get all the IrDA specific info... */ | ||
1763 | if(self->ttp_open) | ||
1764 | state = "connected"; | ||
1765 | else | ||
1766 | if(self->tsap != NULL) | ||
1767 | state = "connecting"; | ||
1768 | else | ||
1769 | if(self->iriap != NULL) | ||
1770 | state = "searching"; | ||
1771 | else | ||
1772 | if(self->ttp_connect) | ||
1773 | state = "weird"; | ||
1774 | else | ||
1775 | state = "idle"; | ||
1776 | len += sprintf(buf+len, "\n IrDA state: %s, ", state); | ||
1777 | len += sprintf(buf+len, "daddr: %08x, ", self->daddr); | ||
1778 | len += sprintf(buf+len, "stsap_sel: %02x, ", self->stsap_sel); | ||
1779 | len += sprintf(buf+len, "dtsap_sel: %02x\n", self->dtsap_sel); | ||
1780 | |||
1781 | /* Next socket, please... */ | ||
1782 | self = (irnet_socket *) hashbin_get_next(irnet_server.list); | ||
1783 | } | ||
1784 | |||
1785 | /* Spin lock end */ | ||
1786 | spin_unlock_bh(&irnet_server.spinlock); | ||
1787 | |||
1788 | return len; | ||
1789 | } | ||
1790 | #endif /* PROC_FS */ | ||
1791 | |||
1792 | |||
1793 | /********************** CONFIGURATION/CLEANUP **********************/ | ||
1794 | /* | ||
1795 | * Initialisation and teardown of the IrDA part, called at module | ||
1796 | * insertion and removal... | ||
1797 | */ | ||
1798 | |||
1799 | /*------------------------------------------------------------------*/ | ||
1800 | /* | ||
1801 | * Prepare the IrNET layer for operation... | ||
1802 | */ | ||
1803 | int __init | ||
1804 | irda_irnet_init(void) | ||
1805 | { | ||
1806 | int err = 0; | ||
1807 | |||
1808 | DENTER(MODULE_TRACE, "()\n"); | ||
1809 | |||
1810 | /* Pure paranoia - should be redundant */ | ||
1811 | memset(&irnet_server, 0, sizeof(struct irnet_root)); | ||
1812 | |||
1813 | /* Setup start of irnet instance list */ | ||
1814 | irnet_server.list = hashbin_new(HB_NOLOCK); | ||
1815 | DABORT(irnet_server.list == NULL, -ENOMEM, | ||
1816 | MODULE_ERROR, "Can't allocate hashbin!\n"); | ||
1817 | /* Init spinlock for instance list */ | ||
1818 | spin_lock_init(&irnet_server.spinlock); | ||
1819 | |||
1820 | /* Initialise control channel */ | ||
1821 | init_waitqueue_head(&irnet_events.rwait); | ||
1822 | irnet_events.index = 0; | ||
1823 | /* Init spinlock for event logging */ | ||
1824 | spin_lock_init(&irnet_events.spinlock); | ||
1825 | |||
1826 | #ifdef CONFIG_PROC_FS | ||
1827 | /* Add a /proc file for irnet infos */ | ||
1828 | create_proc_info_entry("irnet", 0, proc_irda, irnet_proc_read); | ||
1829 | #endif /* CONFIG_PROC_FS */ | ||
1830 | |||
1831 | /* Setup the IrNET server */ | ||
1832 | err = irnet_setup_server(); | ||
1833 | |||
1834 | if(!err) | ||
1835 | /* We are no longer functional... */ | ||
1836 | irnet_server.running = 1; | ||
1837 | |||
1838 | DEXIT(MODULE_TRACE, "\n"); | ||
1839 | return err; | ||
1840 | } | ||
1841 | |||
1842 | /*------------------------------------------------------------------*/ | ||
1843 | /* | ||
1844 | * Cleanup at exit... | ||
1845 | */ | ||
1846 | void __exit | ||
1847 | irda_irnet_cleanup(void) | ||
1848 | { | ||
1849 | DENTER(MODULE_TRACE, "()\n"); | ||
1850 | |||
1851 | /* We are no longer there... */ | ||
1852 | irnet_server.running = 0; | ||
1853 | |||
1854 | #ifdef CONFIG_PROC_FS | ||
1855 | /* Remove our /proc file */ | ||
1856 | remove_proc_entry("irnet", proc_irda); | ||
1857 | #endif /* CONFIG_PROC_FS */ | ||
1858 | |||
1859 | /* Remove our IrNET server from existence */ | ||
1860 | irnet_destroy_server(); | ||
1861 | |||
1862 | /* Remove all instances of IrNET socket still present */ | ||
1863 | hashbin_delete(irnet_server.list, (FREE_FUNC) irda_irnet_destroy); | ||
1864 | |||
1865 | DEXIT(MODULE_TRACE, "\n"); | ||
1866 | } | ||
diff --git a/net/irda/irnet/irnet_irda.h b/net/irda/irnet/irnet_irda.h new file mode 100644 index 000000000000..f2fecd32d8f6 --- /dev/null +++ b/net/irda/irnet/irnet_irda.h | |||
@@ -0,0 +1,186 @@ | |||
1 | /* | ||
2 | * IrNET protocol module : Synchronous PPP over an IrDA socket. | ||
3 | * | ||
4 | * Jean II - HPL `00 - <jt@hpl.hp.com> | ||
5 | * | ||
6 | * This file contains all definitions and declarations necessary for the | ||
7 | * IRDA part of the IrNET module (dealing with IrTTP, IrIAS and co). | ||
8 | * This file is a private header, so other modules don't want to know | ||
9 | * what's in there... | ||
10 | */ | ||
11 | |||
12 | #ifndef IRNET_IRDA_H | ||
13 | #define IRNET_IRDA_H | ||
14 | |||
15 | /***************************** INCLUDES *****************************/ | ||
16 | /* Please add other headers in irnet.h */ | ||
17 | |||
18 | #include "irnet.h" /* Module global include */ | ||
19 | |||
20 | /************************ CONSTANTS & MACROS ************************/ | ||
21 | |||
22 | /* | ||
23 | * Name of the service (socket name) used by IrNET | ||
24 | */ | ||
25 | /* IAS object name (or part of it) */ | ||
26 | #define IRNET_SERVICE_NAME "IrNetv1" | ||
27 | /* IAS attribute */ | ||
28 | #define IRNET_IAS_VALUE "IrDA:TinyTP:LsapSel" | ||
29 | /* LMP notify name for client (only for /proc/net/irda/irlmp) */ | ||
30 | #define IRNET_NOTIFY_NAME "IrNET socket" | ||
31 | /* LMP notify name for server (only for /proc/net/irda/irlmp) */ | ||
32 | #define IRNET_NOTIFY_NAME_SERV "IrNET server" | ||
33 | |||
34 | /****************************** TYPES ******************************/ | ||
35 | |||
36 | /* | ||
37 | * This is the main structure where we store all the data pertaining to | ||
38 | * the IrNET server (listen for connection requests) and the root | ||
39 | * of the IrNET socket list | ||
40 | */ | ||
41 | typedef struct irnet_root | ||
42 | { | ||
43 | irnet_socket s; /* To pretend we are a client... */ | ||
44 | |||
45 | /* Generic stuff */ | ||
46 | int magic; /* Paranoia */ | ||
47 | int running; /* Are we operational ? */ | ||
48 | |||
49 | /* Link list of all IrNET instances opened */ | ||
50 | hashbin_t * list; | ||
51 | spinlock_t spinlock; /* Serialize access to the list */ | ||
52 | /* Note : the way hashbin has been designed is absolutely not | ||
53 | * reentrant, beware... So, we blindly protect all with spinlock */ | ||
54 | |||
55 | /* Handle for the hint bit advertised in IrLMP */ | ||
56 | void * skey; | ||
57 | |||
58 | /* Server socket part */ | ||
59 | struct ias_object * ias_obj; /* Our service name + lsap in IAS */ | ||
60 | |||
61 | } irnet_root; | ||
62 | |||
63 | |||
64 | /**************************** PROTOTYPES ****************************/ | ||
65 | |||
66 | /* ----------------------- CONTROL CHANNEL ----------------------- */ | ||
67 | static void | ||
68 | irnet_post_event(irnet_socket *, | ||
69 | irnet_event, | ||
70 | __u32, | ||
71 | __u32, | ||
72 | char *, | ||
73 | __u16); | ||
74 | /* ----------------------- IRDA SUBROUTINES ----------------------- */ | ||
75 | static inline int | ||
76 | irnet_open_tsap(irnet_socket *); | ||
77 | static inline __u8 | ||
78 | irnet_ias_to_tsap(irnet_socket *, | ||
79 | int, | ||
80 | struct ias_value *); | ||
81 | static inline int | ||
82 | irnet_find_lsap_sel(irnet_socket *); | ||
83 | static inline int | ||
84 | irnet_connect_tsap(irnet_socket *); | ||
85 | static inline int | ||
86 | irnet_discover_next_daddr(irnet_socket *); | ||
87 | static inline int | ||
88 | irnet_discover_daddr_and_lsap_sel(irnet_socket *); | ||
89 | static inline int | ||
90 | irnet_dname_to_daddr(irnet_socket *); | ||
91 | /* ------------------------ SERVER SOCKET ------------------------ */ | ||
92 | static inline int | ||
93 | irnet_daddr_to_dname(irnet_socket *); | ||
94 | static inline irnet_socket * | ||
95 | irnet_find_socket(irnet_socket *); | ||
96 | static inline int | ||
97 | irnet_connect_socket(irnet_socket *, | ||
98 | irnet_socket *, | ||
99 | struct qos_info *, | ||
100 | __u32, | ||
101 | __u8); | ||
102 | static inline void | ||
103 | irnet_disconnect_server(irnet_socket *, | ||
104 | struct sk_buff *); | ||
105 | static inline int | ||
106 | irnet_setup_server(void); | ||
107 | static inline void | ||
108 | irnet_destroy_server(void); | ||
109 | /* ---------------------- IRDA-TTP CALLBACKS ---------------------- */ | ||
110 | static int | ||
111 | irnet_data_indication(void *, /* instance */ | ||
112 | void *, /* sap */ | ||
113 | struct sk_buff *); | ||
114 | static void | ||
115 | irnet_disconnect_indication(void *, | ||
116 | void *, | ||
117 | LM_REASON, | ||
118 | struct sk_buff *); | ||
119 | static void | ||
120 | irnet_connect_confirm(void *, | ||
121 | void *, | ||
122 | struct qos_info *, | ||
123 | __u32, | ||
124 | __u8, | ||
125 | struct sk_buff *); | ||
126 | static void | ||
127 | irnet_flow_indication(void *, | ||
128 | void *, | ||
129 | LOCAL_FLOW); | ||
130 | static void | ||
131 | irnet_status_indication(void *, | ||
132 | LINK_STATUS, | ||
133 | LOCK_STATUS); | ||
134 | static void | ||
135 | irnet_connect_indication(void *, | ||
136 | void *, | ||
137 | struct qos_info *, | ||
138 | __u32, | ||
139 | __u8, | ||
140 | struct sk_buff *); | ||
141 | /* -------------------- IRDA-IAS/LMP CALLBACKS -------------------- */ | ||
142 | static void | ||
143 | irnet_getvalue_confirm(int, | ||
144 | __u16, | ||
145 | struct ias_value *, | ||
146 | void *); | ||
147 | static void | ||
148 | irnet_discovervalue_confirm(int, | ||
149 | __u16, | ||
150 | struct ias_value *, | ||
151 | void *); | ||
152 | #ifdef DISCOVERY_EVENTS | ||
153 | static void | ||
154 | irnet_discovery_indication(discinfo_t *, | ||
155 | DISCOVERY_MODE, | ||
156 | void *); | ||
157 | static void | ||
158 | irnet_expiry_indication(discinfo_t *, | ||
159 | DISCOVERY_MODE, | ||
160 | void *); | ||
161 | #endif | ||
162 | /* -------------------------- PROC ENTRY -------------------------- */ | ||
163 | #ifdef CONFIG_PROC_FS | ||
164 | static int | ||
165 | irnet_proc_read(char *, | ||
166 | char **, | ||
167 | off_t, | ||
168 | int); | ||
169 | #endif /* CONFIG_PROC_FS */ | ||
170 | |||
171 | /**************************** VARIABLES ****************************/ | ||
172 | |||
173 | /* | ||
174 | * The IrNET server. Listen to connection requests and co... | ||
175 | */ | ||
176 | static struct irnet_root irnet_server; | ||
177 | |||
178 | /* Control channel stuff (note : extern) */ | ||
179 | struct irnet_ctrl_channel irnet_events; | ||
180 | |||
181 | /* The /proc/net/irda directory, defined elsewhere... */ | ||
182 | #ifdef CONFIG_PROC_FS | ||
183 | extern struct proc_dir_entry *proc_irda; | ||
184 | #endif /* CONFIG_PROC_FS */ | ||
185 | |||
186 | #endif /* IRNET_IRDA_H */ | ||
diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c new file mode 100644 index 000000000000..f8f984bb9922 --- /dev/null +++ b/net/irda/irnet/irnet_ppp.c | |||
@@ -0,0 +1,1142 @@ | |||
1 | /* | ||
2 | * IrNET protocol module : Synchronous PPP over an IrDA socket. | ||
3 | * | ||
4 | * Jean II - HPL `00 - <jt@hpl.hp.com> | ||
5 | * | ||
6 | * This file implement the PPP interface and /dev/irnet character device. | ||
7 | * The PPP interface hook to the ppp_generic module, handle all our | ||
8 | * relationship to the PPP code in the kernel (and by extension to pppd), | ||
9 | * and exchange PPP frames with this module (send/receive). | ||
10 | * The /dev/irnet device is used primarily for 2 functions : | ||
11 | * 1) as a stub for pppd (the ppp daemon), so that we can appropriately | ||
12 | * generate PPP sessions (we pretend we are a tty). | ||
13 | * 2) as a control channel (write commands, read events) | ||
14 | */ | ||
15 | |||
16 | #include "irnet_ppp.h" /* Private header */ | ||
17 | /* Please put other headers in irnet.h - Thanks */ | ||
18 | |||
19 | /* Generic PPP callbacks (to call us) */ | ||
20 | static struct ppp_channel_ops irnet_ppp_ops = { | ||
21 | .start_xmit = ppp_irnet_send, | ||
22 | .ioctl = ppp_irnet_ioctl | ||
23 | }; | ||
24 | |||
25 | /************************* CONTROL CHANNEL *************************/ | ||
26 | /* | ||
27 | * When a pppd instance is not active on /dev/irnet, it acts as a control | ||
28 | * channel. | ||
29 | * Writing allow to set up the IrDA destination of the IrNET channel, | ||
30 | * and any application may be read events happening in IrNET... | ||
31 | */ | ||
32 | |||
33 | /*------------------------------------------------------------------*/ | ||
34 | /* | ||
35 | * Write is used to send a command to configure a IrNET channel | ||
36 | * before it is open by pppd. The syntax is : "command argument" | ||
37 | * Currently there is only two defined commands : | ||
38 | * o name : set the requested IrDA nickname of the IrNET peer. | ||
39 | * o addr : set the requested IrDA address of the IrNET peer. | ||
40 | * Note : the code is crude, but effective... | ||
41 | */ | ||
42 | static inline ssize_t | ||
43 | irnet_ctrl_write(irnet_socket * ap, | ||
44 | const char __user *buf, | ||
45 | size_t count) | ||
46 | { | ||
47 | char command[IRNET_MAX_COMMAND]; | ||
48 | char * start; /* Current command being processed */ | ||
49 | char * next; /* Next command to process */ | ||
50 | int length; /* Length of current command */ | ||
51 | |||
52 | DENTER(CTRL_TRACE, "(ap=0x%p, count=%Zd)\n", ap, count); | ||
53 | |||
54 | /* Check for overflow... */ | ||
55 | DABORT(count >= IRNET_MAX_COMMAND, -ENOMEM, | ||
56 | CTRL_ERROR, "Too much data !!!\n"); | ||
57 | |||
58 | /* Get the data in the driver */ | ||
59 | if(copy_from_user(command, buf, count)) | ||
60 | { | ||
61 | DERROR(CTRL_ERROR, "Invalid user space pointer.\n"); | ||
62 | return -EFAULT; | ||
63 | } | ||
64 | |||
65 | /* Safe terminate the string */ | ||
66 | command[count] = '\0'; | ||
67 | DEBUG(CTRL_INFO, "Command line received is ``%s'' (%Zd).\n", | ||
68 | command, count); | ||
69 | |||
70 | /* Check every commands in the command line */ | ||
71 | next = command; | ||
72 | while(next != NULL) | ||
73 | { | ||
74 | /* Look at the next command */ | ||
75 | start = next; | ||
76 | |||
77 | /* Scrap whitespaces before the command */ | ||
78 | while(isspace(*start)) | ||
79 | start++; | ||
80 | |||
81 | /* ',' is our command separator */ | ||
82 | next = strchr(start, ','); | ||
83 | if(next) | ||
84 | { | ||
85 | *next = '\0'; /* Terminate command */ | ||
86 | length = next - start; /* Length */ | ||
87 | next++; /* Skip the '\0' */ | ||
88 | } | ||
89 | else | ||
90 | length = strlen(start); | ||
91 | |||
92 | DEBUG(CTRL_INFO, "Found command ``%s'' (%d).\n", start, length); | ||
93 | |||
94 | /* Check if we recognised one of the known command | ||
95 | * We can't use "switch" with strings, so hack with "continue" */ | ||
96 | |||
97 | /* First command : name -> Requested IrDA nickname */ | ||
98 | if(!strncmp(start, "name", 4)) | ||
99 | { | ||
100 | /* Copy the name only if is included and not "any" */ | ||
101 | if((length > 5) && (strcmp(start + 5, "any"))) | ||
102 | { | ||
103 | /* Strip out trailing whitespaces */ | ||
104 | while(isspace(start[length - 1])) | ||
105 | length--; | ||
106 | |||
107 | /* Copy the name for later reuse */ | ||
108 | memcpy(ap->rname, start + 5, length - 5); | ||
109 | ap->rname[length - 5] = '\0'; | ||
110 | } | ||
111 | else | ||
112 | ap->rname[0] = '\0'; | ||
113 | DEBUG(CTRL_INFO, "Got rname = ``%s''\n", ap->rname); | ||
114 | |||
115 | /* Restart the loop */ | ||
116 | continue; | ||
117 | } | ||
118 | |||
119 | /* Second command : addr, daddr -> Requested IrDA destination address | ||
120 | * Also process : saddr -> Requested IrDA source address */ | ||
121 | if((!strncmp(start, "addr", 4)) || | ||
122 | (!strncmp(start, "daddr", 5)) || | ||
123 | (!strncmp(start, "saddr", 5))) | ||
124 | { | ||
125 | __u32 addr = DEV_ADDR_ANY; | ||
126 | |||
127 | /* Copy the address only if is included and not "any" */ | ||
128 | if((length > 5) && (strcmp(start + 5, "any"))) | ||
129 | { | ||
130 | char * begp = start + 5; | ||
131 | char * endp; | ||
132 | |||
133 | /* Scrap whitespaces before the command */ | ||
134 | while(isspace(*begp)) | ||
135 | begp++; | ||
136 | |||
137 | /* Convert argument to a number (last arg is the base) */ | ||
138 | addr = simple_strtoul(begp, &endp, 16); | ||
139 | /* Has it worked ? (endp should be start + length) */ | ||
140 | DABORT(endp <= (start + 5), -EINVAL, | ||
141 | CTRL_ERROR, "Invalid address.\n"); | ||
142 | } | ||
143 | /* Which type of address ? */ | ||
144 | if(start[0] == 's') | ||
145 | { | ||
146 | /* Save it */ | ||
147 | ap->rsaddr = addr; | ||
148 | DEBUG(CTRL_INFO, "Got rsaddr = %08x\n", ap->rsaddr); | ||
149 | } | ||
150 | else | ||
151 | { | ||
152 | /* Save it */ | ||
153 | ap->rdaddr = addr; | ||
154 | DEBUG(CTRL_INFO, "Got rdaddr = %08x\n", ap->rdaddr); | ||
155 | } | ||
156 | |||
157 | /* Restart the loop */ | ||
158 | continue; | ||
159 | } | ||
160 | |||
161 | /* Other possible command : connect N (number of retries) */ | ||
162 | |||
163 | /* No command matched -> Failed... */ | ||
164 | DABORT(1, -EINVAL, CTRL_ERROR, "Not a recognised IrNET command.\n"); | ||
165 | } | ||
166 | |||
167 | /* Success : we have parsed all commands successfully */ | ||
168 | return(count); | ||
169 | } | ||
170 | |||
171 | #ifdef INITIAL_DISCOVERY | ||
172 | /*------------------------------------------------------------------*/ | ||
173 | /* | ||
174 | * Function irnet_get_discovery_log (self) | ||
175 | * | ||
176 | * Query the content on the discovery log if not done | ||
177 | * | ||
178 | * This function query the current content of the discovery log | ||
179 | * at the startup of the event channel and save it in the internal struct. | ||
180 | */ | ||
181 | static void | ||
182 | irnet_get_discovery_log(irnet_socket * ap) | ||
183 | { | ||
184 | __u16 mask = irlmp_service_to_hint(S_LAN); | ||
185 | |||
186 | /* Ask IrLMP for the current discovery log */ | ||
187 | ap->discoveries = irlmp_get_discoveries(&ap->disco_number, mask, | ||
188 | DISCOVERY_DEFAULT_SLOTS); | ||
189 | |||
190 | /* Check if the we got some results */ | ||
191 | if(ap->discoveries == NULL) | ||
192 | ap->disco_number = -1; | ||
193 | |||
194 | DEBUG(CTRL_INFO, "Got the log (0x%p), size is %d\n", | ||
195 | ap->discoveries, ap->disco_number); | ||
196 | } | ||
197 | |||
198 | /*------------------------------------------------------------------*/ | ||
199 | /* | ||
200 | * Function irnet_read_discovery_log (self, event) | ||
201 | * | ||
202 | * Read the content on the discovery log | ||
203 | * | ||
204 | * This function dump the current content of the discovery log | ||
205 | * at the startup of the event channel. | ||
206 | * Return 1 if wrote an event on the control channel... | ||
207 | * | ||
208 | * State of the ap->disco_XXX variables : | ||
209 | * Socket creation : discoveries = NULL ; disco_index = 0 ; disco_number = 0 | ||
210 | * While reading : discoveries = ptr ; disco_index = X ; disco_number = Y | ||
211 | * After reading : discoveries = NULL ; disco_index = Y ; disco_number = -1 | ||
212 | */ | ||
213 | static inline int | ||
214 | irnet_read_discovery_log(irnet_socket * ap, | ||
215 | char * event) | ||
216 | { | ||
217 | int done_event = 0; | ||
218 | |||
219 | DENTER(CTRL_TRACE, "(ap=0x%p, event=0x%p)\n", | ||
220 | ap, event); | ||
221 | |||
222 | /* Test if we have some work to do or we have already finished */ | ||
223 | if(ap->disco_number == -1) | ||
224 | { | ||
225 | DEBUG(CTRL_INFO, "Already done\n"); | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | /* Test if it's the first time and therefore we need to get the log */ | ||
230 | if(ap->discoveries == NULL) | ||
231 | irnet_get_discovery_log(ap); | ||
232 | |||
233 | /* Check if we have more item to dump */ | ||
234 | if(ap->disco_index < ap->disco_number) | ||
235 | { | ||
236 | /* Write an event */ | ||
237 | sprintf(event, "Found %08x (%s) behind %08x {hints %02X-%02X}\n", | ||
238 | ap->discoveries[ap->disco_index].daddr, | ||
239 | ap->discoveries[ap->disco_index].info, | ||
240 | ap->discoveries[ap->disco_index].saddr, | ||
241 | ap->discoveries[ap->disco_index].hints[0], | ||
242 | ap->discoveries[ap->disco_index].hints[1]); | ||
243 | DEBUG(CTRL_INFO, "Writing discovery %d : %s\n", | ||
244 | ap->disco_index, ap->discoveries[ap->disco_index].info); | ||
245 | |||
246 | /* We have an event */ | ||
247 | done_event = 1; | ||
248 | /* Next discovery */ | ||
249 | ap->disco_index++; | ||
250 | } | ||
251 | |||
252 | /* Check if we have done the last item */ | ||
253 | if(ap->disco_index >= ap->disco_number) | ||
254 | { | ||
255 | /* No more items : remove the log and signal termination */ | ||
256 | DEBUG(CTRL_INFO, "Cleaning up log (0x%p)\n", | ||
257 | ap->discoveries); | ||
258 | if(ap->discoveries != NULL) | ||
259 | { | ||
260 | /* Cleanup our copy of the discovery log */ | ||
261 | kfree(ap->discoveries); | ||
262 | ap->discoveries = NULL; | ||
263 | } | ||
264 | ap->disco_number = -1; | ||
265 | } | ||
266 | |||
267 | return done_event; | ||
268 | } | ||
269 | #endif /* INITIAL_DISCOVERY */ | ||
270 | |||
271 | /*------------------------------------------------------------------*/ | ||
272 | /* | ||
273 | * Read is used to get IrNET events | ||
274 | */ | ||
275 | static inline ssize_t | ||
276 | irnet_ctrl_read(irnet_socket * ap, | ||
277 | struct file * file, | ||
278 | char __user * buf, | ||
279 | size_t count) | ||
280 | { | ||
281 | DECLARE_WAITQUEUE(wait, current); | ||
282 | char event[64]; /* Max event is 61 char */ | ||
283 | ssize_t ret = 0; | ||
284 | |||
285 | DENTER(CTRL_TRACE, "(ap=0x%p, count=%Zd)\n", ap, count); | ||
286 | |||
287 | /* Check if we can write an event out in one go */ | ||
288 | DABORT(count < sizeof(event), -EOVERFLOW, CTRL_ERROR, "Buffer to small.\n"); | ||
289 | |||
290 | #ifdef INITIAL_DISCOVERY | ||
291 | /* Check if we have read the log */ | ||
292 | if(irnet_read_discovery_log(ap, event)) | ||
293 | { | ||
294 | /* We have an event !!! Copy it to the user */ | ||
295 | if(copy_to_user(buf, event, strlen(event))) | ||
296 | { | ||
297 | DERROR(CTRL_ERROR, "Invalid user space pointer.\n"); | ||
298 | return -EFAULT; | ||
299 | } | ||
300 | |||
301 | DEXIT(CTRL_TRACE, "\n"); | ||
302 | return(strlen(event)); | ||
303 | } | ||
304 | #endif /* INITIAL_DISCOVERY */ | ||
305 | |||
306 | /* Put ourselves on the wait queue to be woken up */ | ||
307 | add_wait_queue(&irnet_events.rwait, &wait); | ||
308 | current->state = TASK_INTERRUPTIBLE; | ||
309 | for(;;) | ||
310 | { | ||
311 | /* If there is unread events */ | ||
312 | ret = 0; | ||
313 | if(ap->event_index != irnet_events.index) | ||
314 | break; | ||
315 | ret = -EAGAIN; | ||
316 | if(file->f_flags & O_NONBLOCK) | ||
317 | break; | ||
318 | ret = -ERESTARTSYS; | ||
319 | if(signal_pending(current)) | ||
320 | break; | ||
321 | /* Yield and wait to be woken up */ | ||
322 | schedule(); | ||
323 | } | ||
324 | current->state = TASK_RUNNING; | ||
325 | remove_wait_queue(&irnet_events.rwait, &wait); | ||
326 | |||
327 | /* Did we got it ? */ | ||
328 | if(ret != 0) | ||
329 | { | ||
330 | /* No, return the error code */ | ||
331 | DEXIT(CTRL_TRACE, " - ret %Zd\n", ret); | ||
332 | return ret; | ||
333 | } | ||
334 | |||
335 | /* Which event is it ? */ | ||
336 | switch(irnet_events.log[ap->event_index].event) | ||
337 | { | ||
338 | case IRNET_DISCOVER: | ||
339 | sprintf(event, "Discovered %08x (%s) behind %08x {hints %02X-%02X}\n", | ||
340 | irnet_events.log[ap->event_index].daddr, | ||
341 | irnet_events.log[ap->event_index].name, | ||
342 | irnet_events.log[ap->event_index].saddr, | ||
343 | irnet_events.log[ap->event_index].hints.byte[0], | ||
344 | irnet_events.log[ap->event_index].hints.byte[1]); | ||
345 | break; | ||
346 | case IRNET_EXPIRE: | ||
347 | sprintf(event, "Expired %08x (%s) behind %08x {hints %02X-%02X}\n", | ||
348 | irnet_events.log[ap->event_index].daddr, | ||
349 | irnet_events.log[ap->event_index].name, | ||
350 | irnet_events.log[ap->event_index].saddr, | ||
351 | irnet_events.log[ap->event_index].hints.byte[0], | ||
352 | irnet_events.log[ap->event_index].hints.byte[1]); | ||
353 | break; | ||
354 | case IRNET_CONNECT_TO: | ||
355 | sprintf(event, "Connected to %08x (%s) on ppp%d\n", | ||
356 | irnet_events.log[ap->event_index].daddr, | ||
357 | irnet_events.log[ap->event_index].name, | ||
358 | irnet_events.log[ap->event_index].unit); | ||
359 | break; | ||
360 | case IRNET_CONNECT_FROM: | ||
361 | sprintf(event, "Connection from %08x (%s) on ppp%d\n", | ||
362 | irnet_events.log[ap->event_index].daddr, | ||
363 | irnet_events.log[ap->event_index].name, | ||
364 | irnet_events.log[ap->event_index].unit); | ||
365 | break; | ||
366 | case IRNET_REQUEST_FROM: | ||
367 | sprintf(event, "Request from %08x (%s) behind %08x\n", | ||
368 | irnet_events.log[ap->event_index].daddr, | ||
369 | irnet_events.log[ap->event_index].name, | ||
370 | irnet_events.log[ap->event_index].saddr); | ||
371 | break; | ||
372 | case IRNET_NOANSWER_FROM: | ||
373 | sprintf(event, "No-answer from %08x (%s) on ppp%d\n", | ||
374 | irnet_events.log[ap->event_index].daddr, | ||
375 | irnet_events.log[ap->event_index].name, | ||
376 | irnet_events.log[ap->event_index].unit); | ||
377 | break; | ||
378 | case IRNET_BLOCKED_LINK: | ||
379 | sprintf(event, "Blocked link with %08x (%s) on ppp%d\n", | ||
380 | irnet_events.log[ap->event_index].daddr, | ||
381 | irnet_events.log[ap->event_index].name, | ||
382 | irnet_events.log[ap->event_index].unit); | ||
383 | break; | ||
384 | case IRNET_DISCONNECT_FROM: | ||
385 | sprintf(event, "Disconnection from %08x (%s) on ppp%d\n", | ||
386 | irnet_events.log[ap->event_index].daddr, | ||
387 | irnet_events.log[ap->event_index].name, | ||
388 | irnet_events.log[ap->event_index].unit); | ||
389 | break; | ||
390 | case IRNET_DISCONNECT_TO: | ||
391 | sprintf(event, "Disconnected to %08x (%s)\n", | ||
392 | irnet_events.log[ap->event_index].daddr, | ||
393 | irnet_events.log[ap->event_index].name); | ||
394 | break; | ||
395 | default: | ||
396 | sprintf(event, "Bug\n"); | ||
397 | } | ||
398 | /* Increment our event index */ | ||
399 | ap->event_index = (ap->event_index + 1) % IRNET_MAX_EVENTS; | ||
400 | |||
401 | DEBUG(CTRL_INFO, "Event is :%s", event); | ||
402 | |||
403 | /* Copy it to the user */ | ||
404 | if(copy_to_user(buf, event, strlen(event))) | ||
405 | { | ||
406 | DERROR(CTRL_ERROR, "Invalid user space pointer.\n"); | ||
407 | return -EFAULT; | ||
408 | } | ||
409 | |||
410 | DEXIT(CTRL_TRACE, "\n"); | ||
411 | return(strlen(event)); | ||
412 | } | ||
413 | |||
414 | /*------------------------------------------------------------------*/ | ||
415 | /* | ||
416 | * Poll : called when someone do a select on /dev/irnet. | ||
417 | * Just check if there are new events... | ||
418 | */ | ||
419 | static inline unsigned int | ||
420 | irnet_ctrl_poll(irnet_socket * ap, | ||
421 | struct file * file, | ||
422 | poll_table * wait) | ||
423 | { | ||
424 | unsigned int mask; | ||
425 | |||
426 | DENTER(CTRL_TRACE, "(ap=0x%p)\n", ap); | ||
427 | |||
428 | poll_wait(file, &irnet_events.rwait, wait); | ||
429 | mask = POLLOUT | POLLWRNORM; | ||
430 | /* If there is unread events */ | ||
431 | if(ap->event_index != irnet_events.index) | ||
432 | mask |= POLLIN | POLLRDNORM; | ||
433 | #ifdef INITIAL_DISCOVERY | ||
434 | if(ap->disco_number != -1) | ||
435 | { | ||
436 | /* Test if it's the first time and therefore we need to get the log */ | ||
437 | if(ap->discoveries == NULL) | ||
438 | irnet_get_discovery_log(ap); | ||
439 | /* Recheck */ | ||
440 | if(ap->disco_number != -1) | ||
441 | mask |= POLLIN | POLLRDNORM; | ||
442 | } | ||
443 | #endif /* INITIAL_DISCOVERY */ | ||
444 | |||
445 | DEXIT(CTRL_TRACE, " - mask=0x%X\n", mask); | ||
446 | return mask; | ||
447 | } | ||
448 | |||
449 | |||
450 | /*********************** FILESYSTEM CALLBACKS ***********************/ | ||
451 | /* | ||
452 | * Implement the usual open, read, write functions that will be called | ||
453 | * by the file system when some action is performed on /dev/irnet. | ||
454 | * Most of those actions will in fact be performed by "pppd" or | ||
455 | * the control channel, we just act as a redirector... | ||
456 | */ | ||
457 | |||
458 | /*------------------------------------------------------------------*/ | ||
459 | /* | ||
460 | * Open : when somebody open /dev/irnet | ||
461 | * We basically create a new instance of irnet and initialise it. | ||
462 | */ | ||
463 | static int | ||
464 | dev_irnet_open(struct inode * inode, | ||
465 | struct file * file) | ||
466 | { | ||
467 | struct irnet_socket * ap; | ||
468 | int err; | ||
469 | |||
470 | DENTER(FS_TRACE, "(file=0x%p)\n", file); | ||
471 | |||
472 | #ifdef SECURE_DEVIRNET | ||
473 | /* This could (should?) be enforced by the permissions on /dev/irnet. */ | ||
474 | if(!capable(CAP_NET_ADMIN)) | ||
475 | return -EPERM; | ||
476 | #endif /* SECURE_DEVIRNET */ | ||
477 | |||
478 | /* Allocate a private structure for this IrNET instance */ | ||
479 | ap = kmalloc(sizeof(*ap), GFP_KERNEL); | ||
480 | DABORT(ap == NULL, -ENOMEM, FS_ERROR, "Can't allocate struct irnet...\n"); | ||
481 | |||
482 | /* initialize the irnet structure */ | ||
483 | memset(ap, 0, sizeof(*ap)); | ||
484 | ap->file = file; | ||
485 | |||
486 | /* PPP channel setup */ | ||
487 | ap->ppp_open = 0; | ||
488 | ap->chan.private = ap; | ||
489 | ap->chan.ops = &irnet_ppp_ops; | ||
490 | ap->chan.mtu = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN); | ||
491 | ap->chan.hdrlen = 2 + TTP_MAX_HEADER; /* for A/C + Max IrDA hdr */ | ||
492 | /* PPP parameters */ | ||
493 | ap->mru = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN); | ||
494 | ap->xaccm[0] = ~0U; | ||
495 | ap->xaccm[3] = 0x60000000U; | ||
496 | ap->raccm = ~0U; | ||
497 | |||
498 | /* Setup the IrDA part... */ | ||
499 | err = irda_irnet_create(ap); | ||
500 | if(err) | ||
501 | { | ||
502 | DERROR(FS_ERROR, "Can't setup IrDA link...\n"); | ||
503 | kfree(ap); | ||
504 | return err; | ||
505 | } | ||
506 | |||
507 | /* For the control channel */ | ||
508 | ap->event_index = irnet_events.index; /* Cancel all past events */ | ||
509 | |||
510 | /* Put our stuff where we will be able to find it later */ | ||
511 | file->private_data = ap; | ||
512 | |||
513 | DEXIT(FS_TRACE, " - ap=0x%p\n", ap); | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | |||
518 | /*------------------------------------------------------------------*/ | ||
519 | /* | ||
520 | * Close : when somebody close /dev/irnet | ||
521 | * Destroy the instance of /dev/irnet | ||
522 | */ | ||
523 | static int | ||
524 | dev_irnet_close(struct inode * inode, | ||
525 | struct file * file) | ||
526 | { | ||
527 | irnet_socket * ap = (struct irnet_socket *) file->private_data; | ||
528 | |||
529 | DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n", | ||
530 | file, ap); | ||
531 | DABORT(ap == NULL, 0, FS_ERROR, "ap is NULL !!!\n"); | ||
532 | |||
533 | /* Detach ourselves */ | ||
534 | file->private_data = NULL; | ||
535 | |||
536 | /* Close IrDA stuff */ | ||
537 | irda_irnet_destroy(ap); | ||
538 | |||
539 | /* Disconnect from the generic PPP layer if not already done */ | ||
540 | if(ap->ppp_open) | ||
541 | { | ||
542 | DERROR(FS_ERROR, "Channel still registered - deregistering !\n"); | ||
543 | ap->ppp_open = 0; | ||
544 | ppp_unregister_channel(&ap->chan); | ||
545 | } | ||
546 | |||
547 | kfree(ap); | ||
548 | |||
549 | DEXIT(FS_TRACE, "\n"); | ||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | /*------------------------------------------------------------------*/ | ||
554 | /* | ||
555 | * Write does nothing. | ||
556 | * (we receive packet from ppp_generic through ppp_irnet_send()) | ||
557 | */ | ||
558 | static ssize_t | ||
559 | dev_irnet_write(struct file * file, | ||
560 | const char __user *buf, | ||
561 | size_t count, | ||
562 | loff_t * ppos) | ||
563 | { | ||
564 | irnet_socket * ap = (struct irnet_socket *) file->private_data; | ||
565 | |||
566 | DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%Zd)\n", | ||
567 | file, ap, count); | ||
568 | DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n"); | ||
569 | |||
570 | /* If we are connected to ppp_generic, let it handle the job */ | ||
571 | if(ap->ppp_open) | ||
572 | return -EAGAIN; | ||
573 | else | ||
574 | return irnet_ctrl_write(ap, buf, count); | ||
575 | } | ||
576 | |||
577 | /*------------------------------------------------------------------*/ | ||
578 | /* | ||
579 | * Read doesn't do much either. | ||
580 | * (pppd poll us, but ultimately reads through /dev/ppp) | ||
581 | */ | ||
582 | static ssize_t | ||
583 | dev_irnet_read(struct file * file, | ||
584 | char __user * buf, | ||
585 | size_t count, | ||
586 | loff_t * ppos) | ||
587 | { | ||
588 | irnet_socket * ap = (struct irnet_socket *) file->private_data; | ||
589 | |||
590 | DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%Zd)\n", | ||
591 | file, ap, count); | ||
592 | DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n"); | ||
593 | |||
594 | /* If we are connected to ppp_generic, let it handle the job */ | ||
595 | if(ap->ppp_open) | ||
596 | return -EAGAIN; | ||
597 | else | ||
598 | return irnet_ctrl_read(ap, file, buf, count); | ||
599 | } | ||
600 | |||
601 | /*------------------------------------------------------------------*/ | ||
602 | /* | ||
603 | * Poll : called when someone do a select on /dev/irnet | ||
604 | */ | ||
605 | static unsigned int | ||
606 | dev_irnet_poll(struct file * file, | ||
607 | poll_table * wait) | ||
608 | { | ||
609 | irnet_socket * ap = (struct irnet_socket *) file->private_data; | ||
610 | unsigned int mask; | ||
611 | |||
612 | DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n", | ||
613 | file, ap); | ||
614 | |||
615 | mask = POLLOUT | POLLWRNORM; | ||
616 | DABORT(ap == NULL, mask, FS_ERROR, "ap is NULL !!!\n"); | ||
617 | |||
618 | /* If we are connected to ppp_generic, let it handle the job */ | ||
619 | if(!ap->ppp_open) | ||
620 | mask |= irnet_ctrl_poll(ap, file, wait); | ||
621 | |||
622 | DEXIT(FS_TRACE, " - mask=0x%X\n", mask); | ||
623 | return(mask); | ||
624 | } | ||
625 | |||
626 | /*------------------------------------------------------------------*/ | ||
627 | /* | ||
628 | * IOCtl : Called when someone does some ioctls on /dev/irnet | ||
629 | * This is the way pppd configure us and control us while the PPP | ||
630 | * instance is active. | ||
631 | */ | ||
632 | static int | ||
633 | dev_irnet_ioctl(struct inode * inode, | ||
634 | struct file * file, | ||
635 | unsigned int cmd, | ||
636 | unsigned long arg) | ||
637 | { | ||
638 | irnet_socket * ap = (struct irnet_socket *) file->private_data; | ||
639 | int err; | ||
640 | int val; | ||
641 | void __user *argp = (void __user *)arg; | ||
642 | |||
643 | DENTER(FS_TRACE, "(file=0x%p, ap=0x%p, cmd=0x%X)\n", | ||
644 | file, ap, cmd); | ||
645 | |||
646 | /* Basic checks... */ | ||
647 | DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n"); | ||
648 | #ifdef SECURE_DEVIRNET | ||
649 | if(!capable(CAP_NET_ADMIN)) | ||
650 | return -EPERM; | ||
651 | #endif /* SECURE_DEVIRNET */ | ||
652 | |||
653 | err = -EFAULT; | ||
654 | switch(cmd) | ||
655 | { | ||
656 | /* Set discipline (should be N_SYNC_PPP or N_TTY) */ | ||
657 | case TIOCSETD: | ||
658 | if(get_user(val, (int __user *)argp)) | ||
659 | break; | ||
660 | if((val == N_SYNC_PPP) || (val == N_PPP)) | ||
661 | { | ||
662 | DEBUG(FS_INFO, "Entering PPP discipline.\n"); | ||
663 | /* PPP channel setup (ap->chan in configued in dev_irnet_open())*/ | ||
664 | err = ppp_register_channel(&ap->chan); | ||
665 | if(err == 0) | ||
666 | { | ||
667 | /* Our ppp side is active */ | ||
668 | ap->ppp_open = 1; | ||
669 | |||
670 | DEBUG(FS_INFO, "Trying to establish a connection.\n"); | ||
671 | /* Setup the IrDA link now - may fail... */ | ||
672 | irda_irnet_connect(ap); | ||
673 | } | ||
674 | else | ||
675 | DERROR(FS_ERROR, "Can't setup PPP channel...\n"); | ||
676 | } | ||
677 | else | ||
678 | { | ||
679 | /* In theory, should be N_TTY */ | ||
680 | DEBUG(FS_INFO, "Exiting PPP discipline.\n"); | ||
681 | /* Disconnect from the generic PPP layer */ | ||
682 | if(ap->ppp_open) | ||
683 | { | ||
684 | ap->ppp_open = 0; | ||
685 | ppp_unregister_channel(&ap->chan); | ||
686 | } | ||
687 | else | ||
688 | DERROR(FS_ERROR, "Channel not registered !\n"); | ||
689 | err = 0; | ||
690 | } | ||
691 | break; | ||
692 | |||
693 | /* Query PPP channel and unit number */ | ||
694 | case PPPIOCGCHAN: | ||
695 | if(!ap->ppp_open) | ||
696 | break; | ||
697 | if(put_user(ppp_channel_index(&ap->chan), (int __user *)argp)) | ||
698 | break; | ||
699 | DEBUG(FS_INFO, "Query channel.\n"); | ||
700 | err = 0; | ||
701 | break; | ||
702 | case PPPIOCGUNIT: | ||
703 | if(!ap->ppp_open) | ||
704 | break; | ||
705 | if(put_user(ppp_unit_number(&ap->chan), (int __user *)argp)) | ||
706 | break; | ||
707 | DEBUG(FS_INFO, "Query unit number.\n"); | ||
708 | err = 0; | ||
709 | break; | ||
710 | |||
711 | /* All these ioctls can be passed both directly and from ppp_generic, | ||
712 | * so we just deal with them in one place... | ||
713 | */ | ||
714 | case PPPIOCGFLAGS: | ||
715 | case PPPIOCSFLAGS: | ||
716 | case PPPIOCGASYNCMAP: | ||
717 | case PPPIOCSASYNCMAP: | ||
718 | case PPPIOCGRASYNCMAP: | ||
719 | case PPPIOCSRASYNCMAP: | ||
720 | case PPPIOCGXASYNCMAP: | ||
721 | case PPPIOCSXASYNCMAP: | ||
722 | case PPPIOCGMRU: | ||
723 | case PPPIOCSMRU: | ||
724 | DEBUG(FS_INFO, "Standard PPP ioctl.\n"); | ||
725 | if(!capable(CAP_NET_ADMIN)) | ||
726 | err = -EPERM; | ||
727 | else | ||
728 | err = ppp_irnet_ioctl(&ap->chan, cmd, arg); | ||
729 | break; | ||
730 | |||
731 | /* TTY IOCTLs : Pretend that we are a tty, to keep pppd happy */ | ||
732 | /* Get termios */ | ||
733 | case TCGETS: | ||
734 | DEBUG(FS_INFO, "Get termios.\n"); | ||
735 | if(kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios)) | ||
736 | break; | ||
737 | err = 0; | ||
738 | break; | ||
739 | /* Set termios */ | ||
740 | case TCSETSF: | ||
741 | DEBUG(FS_INFO, "Set termios.\n"); | ||
742 | if(user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp)) | ||
743 | break; | ||
744 | err = 0; | ||
745 | break; | ||
746 | |||
747 | /* Set DTR/RTS */ | ||
748 | case TIOCMBIS: | ||
749 | case TIOCMBIC: | ||
750 | /* Set exclusive/non-exclusive mode */ | ||
751 | case TIOCEXCL: | ||
752 | case TIOCNXCL: | ||
753 | DEBUG(FS_INFO, "TTY compatibility.\n"); | ||
754 | err = 0; | ||
755 | break; | ||
756 | |||
757 | case TCGETA: | ||
758 | DEBUG(FS_INFO, "TCGETA\n"); | ||
759 | break; | ||
760 | |||
761 | case TCFLSH: | ||
762 | DEBUG(FS_INFO, "TCFLSH\n"); | ||
763 | /* Note : this will flush buffers in PPP, so it *must* be done | ||
764 | * We should also worry that we don't accept junk here and that | ||
765 | * we get rid of our own buffers */ | ||
766 | #ifdef FLUSH_TO_PPP | ||
767 | ppp_output_wakeup(&ap->chan); | ||
768 | #endif /* FLUSH_TO_PPP */ | ||
769 | err = 0; | ||
770 | break; | ||
771 | |||
772 | case FIONREAD: | ||
773 | DEBUG(FS_INFO, "FIONREAD\n"); | ||
774 | val = 0; | ||
775 | if(put_user(val, (int __user *)argp)) | ||
776 | break; | ||
777 | err = 0; | ||
778 | break; | ||
779 | |||
780 | default: | ||
781 | DERROR(FS_ERROR, "Unsupported ioctl (0x%X)\n", cmd); | ||
782 | err = -ENOIOCTLCMD; | ||
783 | } | ||
784 | |||
785 | DEXIT(FS_TRACE, " - err = 0x%X\n", err); | ||
786 | return err; | ||
787 | } | ||
788 | |||
789 | /************************** PPP CALLBACKS **************************/ | ||
790 | /* | ||
791 | * This are the functions that the generic PPP driver in the kernel | ||
792 | * will call to communicate to us. | ||
793 | */ | ||
794 | |||
795 | /*------------------------------------------------------------------*/ | ||
796 | /* | ||
797 | * Prepare the ppp frame for transmission over the IrDA socket. | ||
798 | * We make sure that the header space is enough, and we change ppp header | ||
799 | * according to flags passed by pppd. | ||
800 | * This is not a callback, but just a helper function used in ppp_irnet_send() | ||
801 | */ | ||
802 | static inline struct sk_buff * | ||
803 | irnet_prepare_skb(irnet_socket * ap, | ||
804 | struct sk_buff * skb) | ||
805 | { | ||
806 | unsigned char * data; | ||
807 | int proto; /* PPP protocol */ | ||
808 | int islcp; /* Protocol == LCP */ | ||
809 | int needaddr; /* Need PPP address */ | ||
810 | |||
811 | DENTER(PPP_TRACE, "(ap=0x%p, skb=0x%p)\n", | ||
812 | ap, skb); | ||
813 | |||
814 | /* Extract PPP protocol from the frame */ | ||
815 | data = skb->data; | ||
816 | proto = (data[0] << 8) + data[1]; | ||
817 | |||
818 | /* LCP packets with codes between 1 (configure-request) | ||
819 | * and 7 (code-reject) must be sent as though no options | ||
820 | * have been negotiated. */ | ||
821 | islcp = (proto == PPP_LCP) && (1 <= data[2]) && (data[2] <= 7); | ||
822 | |||
823 | /* compress protocol field if option enabled */ | ||
824 | if((data[0] == 0) && (ap->flags & SC_COMP_PROT) && (!islcp)) | ||
825 | skb_pull(skb,1); | ||
826 | |||
827 | /* Check if we need address/control fields */ | ||
828 | needaddr = 2*((ap->flags & SC_COMP_AC) == 0 || islcp); | ||
829 | |||
830 | /* Is the skb headroom large enough to contain all IrDA-headers? */ | ||
831 | if((skb_headroom(skb) < (ap->max_header_size + needaddr)) || | ||
832 | (skb_shared(skb))) | ||
833 | { | ||
834 | struct sk_buff * new_skb; | ||
835 | |||
836 | DEBUG(PPP_INFO, "Reallocating skb\n"); | ||
837 | |||
838 | /* Create a new skb */ | ||
839 | new_skb = skb_realloc_headroom(skb, ap->max_header_size + needaddr); | ||
840 | |||
841 | /* We have to free the original skb anyway */ | ||
842 | dev_kfree_skb(skb); | ||
843 | |||
844 | /* Did the realloc succeed ? */ | ||
845 | DABORT(new_skb == NULL, NULL, PPP_ERROR, "Could not realloc skb\n"); | ||
846 | |||
847 | /* Use the new skb instead */ | ||
848 | skb = new_skb; | ||
849 | } | ||
850 | |||
851 | /* prepend address/control fields if necessary */ | ||
852 | if(needaddr) | ||
853 | { | ||
854 | skb_push(skb, 2); | ||
855 | skb->data[0] = PPP_ALLSTATIONS; | ||
856 | skb->data[1] = PPP_UI; | ||
857 | } | ||
858 | |||
859 | DEXIT(PPP_TRACE, "\n"); | ||
860 | |||
861 | return skb; | ||
862 | } | ||
863 | |||
864 | /*------------------------------------------------------------------*/ | ||
865 | /* | ||
866 | * Send a packet to the peer over the IrTTP connection. | ||
867 | * Returns 1 iff the packet was accepted. | ||
868 | * Returns 0 iff packet was not consumed. | ||
869 | * If the packet was not accepted, we will call ppp_output_wakeup | ||
870 | * at some later time to reactivate flow control in ppp_generic. | ||
871 | */ | ||
872 | static int | ||
873 | ppp_irnet_send(struct ppp_channel * chan, | ||
874 | struct sk_buff * skb) | ||
875 | { | ||
876 | irnet_socket * self = (struct irnet_socket *) chan->private; | ||
877 | int ret; | ||
878 | |||
879 | DENTER(PPP_TRACE, "(channel=0x%p, ap/self=0x%p)\n", | ||
880 | chan, self); | ||
881 | |||
882 | /* Check if things are somewhat valid... */ | ||
883 | DASSERT(self != NULL, 0, PPP_ERROR, "Self is NULL !!!\n"); | ||
884 | |||
885 | /* Check if we are connected */ | ||
886 | if(!(test_bit(0, &self->ttp_open))) | ||
887 | { | ||
888 | #ifdef CONNECT_IN_SEND | ||
889 | /* Let's try to connect one more time... */ | ||
890 | /* Note : we won't be connected after this call, but we should be | ||
891 | * ready for next packet... */ | ||
892 | /* If we are already connecting, this will fail */ | ||
893 | irda_irnet_connect(self); | ||
894 | #endif /* CONNECT_IN_SEND */ | ||
895 | |||
896 | DEBUG(PPP_INFO, "IrTTP not ready ! (%ld-%ld)\n", | ||
897 | self->ttp_open, self->ttp_connect); | ||
898 | |||
899 | /* Note : we can either drop the packet or block the packet. | ||
900 | * | ||
901 | * Blocking the packet allow us a better connection time, | ||
902 | * because by calling ppp_output_wakeup() we can have | ||
903 | * ppp_generic resending the LCP request immediately to us, | ||
904 | * rather than waiting for one of pppd periodic transmission of | ||
905 | * LCP request. | ||
906 | * | ||
907 | * On the other hand, if we block all packet, all those periodic | ||
908 | * transmissions of pppd accumulate in ppp_generic, creating a | ||
909 | * backlog of LCP request. When we eventually connect later on, | ||
910 | * we have to transmit all this backlog before we can connect | ||
911 | * proper (if we don't timeout before). | ||
912 | * | ||
913 | * The current strategy is as follow : | ||
914 | * While we are attempting to connect, we block packets to get | ||
915 | * a better connection time. | ||
916 | * If we fail to connect, we drain the queue and start dropping packets | ||
917 | */ | ||
918 | #ifdef BLOCK_WHEN_CONNECT | ||
919 | /* If we are attempting to connect */ | ||
920 | if(test_bit(0, &self->ttp_connect)) | ||
921 | { | ||
922 | /* Blocking packet, ppp_generic will retry later */ | ||
923 | return 0; | ||
924 | } | ||
925 | #endif /* BLOCK_WHEN_CONNECT */ | ||
926 | |||
927 | /* Dropping packet, pppd will retry later */ | ||
928 | dev_kfree_skb(skb); | ||
929 | return 1; | ||
930 | } | ||
931 | |||
932 | /* Check if the queue can accept any packet, otherwise block */ | ||
933 | if(self->tx_flow != FLOW_START) | ||
934 | DRETURN(0, PPP_INFO, "IrTTP queue full (%d skbs)...\n", | ||
935 | skb_queue_len(&self->tsap->tx_queue)); | ||
936 | |||
937 | /* Prepare ppp frame for transmission */ | ||
938 | skb = irnet_prepare_skb(self, skb); | ||
939 | DABORT(skb == NULL, 1, PPP_ERROR, "Prepare skb for Tx failed.\n"); | ||
940 | |||
941 | /* Send the packet to IrTTP */ | ||
942 | ret = irttp_data_request(self->tsap, skb); | ||
943 | if(ret < 0) | ||
944 | { | ||
945 | /* | ||
946 | * > IrTTPs tx queue is full, so we just have to | ||
947 | * > drop the frame! You might think that we should | ||
948 | * > just return -1 and don't deallocate the frame, | ||
949 | * > but that is dangerous since it's possible that | ||
950 | * > we have replaced the original skb with a new | ||
951 | * > one with larger headroom, and that would really | ||
952 | * > confuse do_dev_queue_xmit() in dev.c! I have | ||
953 | * > tried :-) DB | ||
954 | * Correction : we verify the flow control above (self->tx_flow), | ||
955 | * so we come here only if IrTTP doesn't like the packet (empty, | ||
956 | * too large, IrTTP not connected). In those rare cases, it's ok | ||
957 | * to drop it, we don't want to see it here again... | ||
958 | * Jean II | ||
959 | */ | ||
960 | DERROR(PPP_ERROR, "IrTTP doesn't like this packet !!! (0x%X)\n", ret); | ||
961 | /* irttp_data_request already free the packet */ | ||
962 | } | ||
963 | |||
964 | DEXIT(PPP_TRACE, "\n"); | ||
965 | return 1; /* Packet has been consumed */ | ||
966 | } | ||
967 | |||
968 | /*------------------------------------------------------------------*/ | ||
969 | /* | ||
970 | * Take care of the ioctls that ppp_generic doesn't want to deal with... | ||
971 | * Note : we are also called from dev_irnet_ioctl(). | ||
972 | */ | ||
973 | static int | ||
974 | ppp_irnet_ioctl(struct ppp_channel * chan, | ||
975 | unsigned int cmd, | ||
976 | unsigned long arg) | ||
977 | { | ||
978 | irnet_socket * ap = (struct irnet_socket *) chan->private; | ||
979 | int err; | ||
980 | int val; | ||
981 | u32 accm[8]; | ||
982 | void __user *argp = (void __user *)arg; | ||
983 | |||
984 | DENTER(PPP_TRACE, "(channel=0x%p, ap=0x%p, cmd=0x%X)\n", | ||
985 | chan, ap, cmd); | ||
986 | |||
987 | /* Basic checks... */ | ||
988 | DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n"); | ||
989 | |||
990 | err = -EFAULT; | ||
991 | switch(cmd) | ||
992 | { | ||
993 | /* PPP flags */ | ||
994 | case PPPIOCGFLAGS: | ||
995 | val = ap->flags | ap->rbits; | ||
996 | if(put_user(val, (int __user *) argp)) | ||
997 | break; | ||
998 | err = 0; | ||
999 | break; | ||
1000 | case PPPIOCSFLAGS: | ||
1001 | if(get_user(val, (int __user *) argp)) | ||
1002 | break; | ||
1003 | ap->flags = val & ~SC_RCV_BITS; | ||
1004 | ap->rbits = val & SC_RCV_BITS; | ||
1005 | err = 0; | ||
1006 | break; | ||
1007 | |||
1008 | /* Async map stuff - all dummy to please pppd */ | ||
1009 | case PPPIOCGASYNCMAP: | ||
1010 | if(put_user(ap->xaccm[0], (u32 __user *) argp)) | ||
1011 | break; | ||
1012 | err = 0; | ||
1013 | break; | ||
1014 | case PPPIOCSASYNCMAP: | ||
1015 | if(get_user(ap->xaccm[0], (u32 __user *) argp)) | ||
1016 | break; | ||
1017 | err = 0; | ||
1018 | break; | ||
1019 | case PPPIOCGRASYNCMAP: | ||
1020 | if(put_user(ap->raccm, (u32 __user *) argp)) | ||
1021 | break; | ||
1022 | err = 0; | ||
1023 | break; | ||
1024 | case PPPIOCSRASYNCMAP: | ||
1025 | if(get_user(ap->raccm, (u32 __user *) argp)) | ||
1026 | break; | ||
1027 | err = 0; | ||
1028 | break; | ||
1029 | case PPPIOCGXASYNCMAP: | ||
1030 | if(copy_to_user(argp, ap->xaccm, sizeof(ap->xaccm))) | ||
1031 | break; | ||
1032 | err = 0; | ||
1033 | break; | ||
1034 | case PPPIOCSXASYNCMAP: | ||
1035 | if(copy_from_user(accm, argp, sizeof(accm))) | ||
1036 | break; | ||
1037 | accm[2] &= ~0x40000000U; /* can't escape 0x5e */ | ||
1038 | accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ | ||
1039 | memcpy(ap->xaccm, accm, sizeof(ap->xaccm)); | ||
1040 | err = 0; | ||
1041 | break; | ||
1042 | |||
1043 | /* Max PPP frame size */ | ||
1044 | case PPPIOCGMRU: | ||
1045 | if(put_user(ap->mru, (int __user *) argp)) | ||
1046 | break; | ||
1047 | err = 0; | ||
1048 | break; | ||
1049 | case PPPIOCSMRU: | ||
1050 | if(get_user(val, (int __user *) argp)) | ||
1051 | break; | ||
1052 | if(val < PPP_MRU) | ||
1053 | val = PPP_MRU; | ||
1054 | ap->mru = val; | ||
1055 | err = 0; | ||
1056 | break; | ||
1057 | |||
1058 | default: | ||
1059 | DEBUG(PPP_INFO, "Unsupported ioctl (0x%X)\n", cmd); | ||
1060 | err = -ENOIOCTLCMD; | ||
1061 | } | ||
1062 | |||
1063 | DEXIT(PPP_TRACE, " - err = 0x%X\n", err); | ||
1064 | return err; | ||
1065 | } | ||
1066 | |||
1067 | /************************** INITIALISATION **************************/ | ||
1068 | /* | ||
1069 | * Module initialisation and all that jazz... | ||
1070 | */ | ||
1071 | |||
1072 | /*------------------------------------------------------------------*/ | ||
1073 | /* | ||
1074 | * Hook our device callbacks in the filesystem, to connect our code | ||
1075 | * to /dev/irnet | ||
1076 | */ | ||
1077 | static inline int __init | ||
1078 | ppp_irnet_init(void) | ||
1079 | { | ||
1080 | int err = 0; | ||
1081 | |||
1082 | DENTER(MODULE_TRACE, "()\n"); | ||
1083 | |||
1084 | /* Allocate ourselves as a minor in the misc range */ | ||
1085 | err = misc_register(&irnet_misc_device); | ||
1086 | |||
1087 | DEXIT(MODULE_TRACE, "\n"); | ||
1088 | return err; | ||
1089 | } | ||
1090 | |||
1091 | /*------------------------------------------------------------------*/ | ||
1092 | /* | ||
1093 | * Cleanup at exit... | ||
1094 | */ | ||
1095 | static inline void __exit | ||
1096 | ppp_irnet_cleanup(void) | ||
1097 | { | ||
1098 | DENTER(MODULE_TRACE, "()\n"); | ||
1099 | |||
1100 | /* De-allocate /dev/irnet minor in misc range */ | ||
1101 | misc_deregister(&irnet_misc_device); | ||
1102 | |||
1103 | DEXIT(MODULE_TRACE, "\n"); | ||
1104 | } | ||
1105 | |||
1106 | /*------------------------------------------------------------------*/ | ||
1107 | /* | ||
1108 | * Module main entry point | ||
1109 | */ | ||
1110 | int __init | ||
1111 | irnet_init(void) | ||
1112 | { | ||
1113 | int err; | ||
1114 | |||
1115 | /* Initialise both parts... */ | ||
1116 | err = irda_irnet_init(); | ||
1117 | if(!err) | ||
1118 | err = ppp_irnet_init(); | ||
1119 | return err; | ||
1120 | } | ||
1121 | |||
1122 | /*------------------------------------------------------------------*/ | ||
1123 | /* | ||
1124 | * Module exit | ||
1125 | */ | ||
1126 | static void __exit | ||
1127 | irnet_cleanup(void) | ||
1128 | { | ||
1129 | irda_irnet_cleanup(); | ||
1130 | ppp_irnet_cleanup(); | ||
1131 | } | ||
1132 | |||
1133 | /*------------------------------------------------------------------*/ | ||
1134 | /* | ||
1135 | * Module magic | ||
1136 | */ | ||
1137 | module_init(irnet_init); | ||
1138 | module_exit(irnet_cleanup); | ||
1139 | MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>"); | ||
1140 | MODULE_DESCRIPTION("IrNET : Synchronous PPP over IrDA"); | ||
1141 | MODULE_LICENSE("GPL"); | ||
1142 | MODULE_ALIAS_CHARDEV(10, 187); | ||
diff --git a/net/irda/irnet/irnet_ppp.h b/net/irda/irnet/irnet_ppp.h new file mode 100644 index 000000000000..d2beb7df8f7f --- /dev/null +++ b/net/irda/irnet/irnet_ppp.h | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * IrNET protocol module : Synchronous PPP over an IrDA socket. | ||
3 | * | ||
4 | * Jean II - HPL `00 - <jt@hpl.hp.com> | ||
5 | * | ||
6 | * This file contains all definitions and declarations necessary for the | ||
7 | * PPP part of the IrNET module. | ||
8 | * This file is a private header, so other modules don't want to know | ||
9 | * what's in there... | ||
10 | */ | ||
11 | |||
12 | #ifndef IRNET_PPP_H | ||
13 | #define IRNET_PPP_H | ||
14 | |||
15 | /***************************** INCLUDES *****************************/ | ||
16 | |||
17 | #include "irnet.h" /* Module global include */ | ||
18 | |||
19 | /************************ CONSTANTS & MACROS ************************/ | ||
20 | |||
21 | /* /dev/irnet file constants */ | ||
22 | #define IRNET_MAJOR 10 /* Misc range */ | ||
23 | #define IRNET_MINOR 187 /* Official allocation */ | ||
24 | |||
25 | /* IrNET control channel stuff */ | ||
26 | #define IRNET_MAX_COMMAND 256 /* Max length of a command line */ | ||
27 | |||
28 | /* PPP hardcore stuff */ | ||
29 | |||
30 | /* Bits in rbits (PPP flags in irnet struct) */ | ||
31 | #define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) | ||
32 | |||
33 | /* Bit numbers in busy */ | ||
34 | #define XMIT_BUSY 0 | ||
35 | #define RECV_BUSY 1 | ||
36 | #define XMIT_WAKEUP 2 | ||
37 | #define XMIT_FULL 3 | ||
38 | |||
39 | /* Queue management */ | ||
40 | #define PPPSYNC_MAX_RQLEN 32 /* arbitrary */ | ||
41 | |||
42 | /****************************** TYPES ******************************/ | ||
43 | |||
44 | |||
45 | /**************************** PROTOTYPES ****************************/ | ||
46 | |||
47 | /* ----------------------- CONTROL CHANNEL ----------------------- */ | ||
48 | static inline ssize_t | ||
49 | irnet_ctrl_write(irnet_socket *, | ||
50 | const char *, | ||
51 | size_t); | ||
52 | static inline ssize_t | ||
53 | irnet_ctrl_read(irnet_socket *, | ||
54 | struct file *, | ||
55 | char *, | ||
56 | size_t); | ||
57 | static inline unsigned int | ||
58 | irnet_ctrl_poll(irnet_socket *, | ||
59 | struct file *, | ||
60 | poll_table *); | ||
61 | /* ----------------------- CHARACTER DEVICE ----------------------- */ | ||
62 | static int | ||
63 | dev_irnet_open(struct inode *, /* fs callback : open */ | ||
64 | struct file *), | ||
65 | dev_irnet_close(struct inode *, | ||
66 | struct file *); | ||
67 | static ssize_t | ||
68 | dev_irnet_write(struct file *, | ||
69 | const char __user *, | ||
70 | size_t, | ||
71 | loff_t *), | ||
72 | dev_irnet_read(struct file *, | ||
73 | char __user *, | ||
74 | size_t, | ||
75 | loff_t *); | ||
76 | static unsigned int | ||
77 | dev_irnet_poll(struct file *, | ||
78 | poll_table *); | ||
79 | static int | ||
80 | dev_irnet_ioctl(struct inode *, | ||
81 | struct file *, | ||
82 | unsigned int, | ||
83 | unsigned long); | ||
84 | /* ------------------------ PPP INTERFACE ------------------------ */ | ||
85 | static inline struct sk_buff * | ||
86 | irnet_prepare_skb(irnet_socket *, | ||
87 | struct sk_buff *); | ||
88 | static int | ||
89 | ppp_irnet_send(struct ppp_channel *, | ||
90 | struct sk_buff *); | ||
91 | static int | ||
92 | ppp_irnet_ioctl(struct ppp_channel *, | ||
93 | unsigned int, | ||
94 | unsigned long); | ||
95 | |||
96 | /**************************** VARIABLES ****************************/ | ||
97 | |||
98 | /* Filesystem callbacks (to call us) */ | ||
99 | static struct file_operations irnet_device_fops = | ||
100 | { | ||
101 | .owner = THIS_MODULE, | ||
102 | .read = dev_irnet_read, | ||
103 | .write = dev_irnet_write, | ||
104 | .poll = dev_irnet_poll, | ||
105 | .ioctl = dev_irnet_ioctl, | ||
106 | .open = dev_irnet_open, | ||
107 | .release = dev_irnet_close | ||
108 | /* Also : llseek, readdir, mmap, flush, fsync, fasync, lock, readv, writev */ | ||
109 | }; | ||
110 | |||
111 | /* Structure so that the misc major (drivers/char/misc.c) take care of us... */ | ||
112 | static struct miscdevice irnet_misc_device = | ||
113 | { | ||
114 | IRNET_MINOR, | ||
115 | "irnet", | ||
116 | &irnet_device_fops | ||
117 | }; | ||
118 | |||
119 | #endif /* IRNET_PPP_H */ | ||