4e3819cf |
1 | /* -*-c-*- |
2 | * |
7e365031 |
3 | * $Id: unet.c,v 1.3 2001/02/19 19:10:28 mdw Exp $ |
4e3819cf |
4 | * |
5 | * User-space network device support. |
6 | * |
7 | * (c) 1998 Mark Wooding |
8 | */ |
9 | |
10 | /*----- Licensing notice --------------------------------------------------* |
11 | * |
12 | * This file is part of Usernet. |
13 | * |
14 | * Usernet is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by |
16 | * the Free Software Foundation; either version 2 of the License, or |
17 | * (at your option) any later version. |
18 | * |
19 | * Usernet is distributed in the hope that it will be useful, |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | * GNU General Public License for more details. |
23 | * |
24 | * You should have received a copy of the GNU General Public License |
25 | * along with Usernet; if not, write to the Free Software Foundation, |
26 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
27 | */ |
28 | |
29 | /*----- Revision history --------------------------------------------------* |
30 | * |
31 | * $Log: unet.c,v $ |
7e365031 |
32 | * Revision 1.3 2001/02/19 19:10:28 mdw |
33 | * New option to allow changing interface flags. |
34 | * |
88613db4 |
35 | * Revision 1.2 2001/02/03 18:39:59 mdw |
36 | * Setting the maximum interface count now does the right thing. |
37 | * |
4e3819cf |
38 | * Revision 1.1 2001/01/25 22:03:39 mdw |
39 | * Initial check-in (somewhat belated). |
40 | * |
41 | */ |
42 | |
43 | /*----- Include files -----------------------------------------------------*/ |
44 | |
45 | #include <linux/module.h> |
46 | |
47 | #include <asm/byteorder.h> |
48 | #include <asm/segment.h> |
49 | |
50 | #include <linux/types.h> |
51 | #include <linux/kernel.h> |
52 | #include <linux/wait.h> |
53 | #include <linux/sched.h> |
54 | #include <linux/fs.h> |
55 | #include <linux/poll.h> |
56 | #include <linux/netdevice.h> |
57 | #include <linux/etherdevice.h> |
58 | #include <linux/if_arp.h> |
59 | #include <linux/malloc.h> |
60 | #include <linux/errno.h> |
61 | #include <linux/init.h> |
62 | |
63 | #include "unetconf.h" |
64 | #include "unet.h" |
65 | |
66 | MODULE_AUTHOR("Mark Wooding"); |
67 | MODULE_DESCRIPTION("Allows userland handling of a network interface"); |
68 | |
69 | /*----- Debugging macros --------------------------------------------------*/ |
70 | |
71 | #define UNET_DEBUGALWAYS 1 |
72 | #define UNET_DEBUGRUNTIME 0 |
73 | #define UNET_DEBUGNEVER -1 |
74 | |
75 | /* --- If the macro isn't defined then be switchable at runtime --- */ |
76 | |
77 | #ifndef UNET_DEBUG |
78 | # define UNET_DEBUG UNET_DEBUGRUNTIME |
79 | #endif |
80 | |
81 | /* --- Define the base macro @D@ according to the debug setting --- */ |
82 | |
83 | #if UNET_DEBUG == UNET_DEBUGALWAYS |
84 | # define D(x) { x } |
85 | # define DIF(u, x) if ((u)->f & UNIF_DEBUG) { x } |
86 | #elif UNET_DEBUG == UNET_DEBUGRUNTIME |
87 | # define D(x) if (unet_debug) { x } |
88 | # define DIF(u, x) if ((u)->f & UNIF_DEBUG) { x } |
89 | #elif UNET_DEBUG == UNET_DEBUGNEVER |
90 | # define D(x) |
91 | # define DIF(u, x) |
92 | #elif |
93 | # error UNET_DEBUG set to invalid value (bug in configure script?) |
94 | #endif |
95 | |
96 | /*----- Type definitions --------------------------------------------------*/ |
97 | |
98 | /* --- Unet connection status --- * |
99 | * |
100 | * Records are stored in a slightly strange doubly linked list. The list |
101 | * exists so that I can find the next unused sequence number when creating |
102 | * new connections. It's odd because of the type of the @prev@ node; |
103 | * rather than being the address of the previous item, it's the address of |
104 | * the previous item's pointer to me, which among other good things means |
105 | * that it works on the list head too. |
106 | */ |
107 | |
108 | struct unet { |
109 | struct unet *next, **prev; /* List of unet blocks */ |
110 | struct device nif; /* Network interface block */ |
111 | int seq; /* Sequence number for connection */ |
112 | char name[UNET_NAMEMAX]; /* Buffer for my interface name */ |
113 | struct wait_queue *q; /* Wait list for device reads */ |
114 | struct sk_buff_head skbq; /* Queue of packets waiting */ |
115 | struct enet_statistics e; /* Pointer to statistics block */ |
116 | unsigned short protocol; /* Protocol for outgoing packets */ |
117 | unsigned f; /* Userful flags */ |
118 | }; |
119 | |
120 | /*----- Static variables --------------------------------------------------*/ |
121 | |
122 | #if UNET_DEBUG == UNET_DEBUGRUNTIME |
123 | static int unet_debug = 0; |
124 | MODULE_PARM(unet_debug, "i"); |
125 | #endif |
126 | |
127 | static int unet_npersist = UNET_NPERSIST; |
128 | static int unet_maxif = UNET_MAXIF; |
129 | static struct unet *unet_persistent; |
130 | static struct unet *unet_list = 0; |
88613db4 |
131 | static int unet_nif = 0; |
4e3819cf |
132 | |
133 | MODULE_PARM(unet_npersist, "i"); |
134 | MODULE_PARM(unet_maxif, "i"); |
135 | |
136 | /*----- Debugging code ----------------------------------------------------*/ |
137 | |
138 | #if UNET_DEBUG != UNET_DEBUGNEVER |
139 | |
140 | /* --- @unet_dumpBlock@ --- * |
141 | * |
142 | * Arguments: @struct unet *u@ = pointer to block to dump |
143 | * |
144 | * Returns: --- |
145 | * |
146 | * Use: Dumps a unet object to syslogd. |
147 | */ |
148 | |
149 | static void unet_dumpBlock(struct unet *u) |
150 | { |
151 | printk(KERN_DEBUG "unet: dumping unet block at %p\n", u); |
152 | printk(KERN_DEBUG " sequence number = %d\n", u->seq); |
153 | printk(KERN_DEBUG " interface name = `%s'\n", u->name); |
154 | printk(KERN_DEBUG " flags =%s%s%s\n", |
155 | u->f & UNIF_TRANS ? " TRANS" : "", |
156 | u->f & UNIF_OPEN ? " OPEN" : "", |
157 | u->f & UNIF_DEBUG ? " DEBUG" : ""); |
158 | printk(KERN_DEBUG " interface type = %d\n", u->nif.type); |
159 | printk(KERN_DEBUG " header len = %d\n", u->nif.hard_header_len); |
160 | printk(KERN_DEBUG " mtu = %d\n", u->nif.mtu); |
161 | printk(KERN_DEBUG " protocol = %d\n", ntohs(u->protocol)); |
162 | printk(KERN_DEBUG " address len = %d\n", u->nif.addr_len); |
163 | } |
164 | |
165 | /* --- @unet_dump@ --- * |
166 | * |
167 | * Arguments: --- |
168 | * |
169 | * Returns: --- |
170 | * |
171 | * Use: Dumps the entire unet state to syslogd. |
172 | */ |
173 | |
174 | static void unet_dump(void) |
175 | { |
176 | int i; |
177 | struct unet *u; |
178 | |
179 | for (i = 0; i < unet_npersist; i++) |
180 | unet_dumpBlock(&unet_persistent[i]); |
181 | for (u = unet_list; u; u = u->next) |
182 | unet_dumpBlock(u); |
183 | } |
184 | |
185 | /* --- @unet_hexdump@ --- * |
186 | * |
187 | * Arguments: @const char *prefix@ = prefix to print on output lines |
188 | * @const void *b@ = pointer to block to dump |
189 | * @size_t sz@ = size of block to dump |
190 | * |
191 | * Returns: --- |
192 | * |
193 | * Use: Dumps a hex block to the kernel log. |
194 | */ |
195 | |
196 | #define UNET_HEXROWSZ 16 |
197 | |
198 | static void unet_hexdump(const char *prefix, const char *b, size_t sz) |
199 | { |
200 | const unsigned char *p = b; |
201 | size_t i; |
202 | unsigned long o = 0; |
203 | size_t c; |
204 | |
205 | char buf[256], *q; |
206 | |
207 | /* --- Now start work --- */ |
208 | |
209 | while (sz) { |
210 | q = buf; |
211 | q += sprintf(q, "%s%08lx : ", prefix, o); |
212 | for (i = 0; i < UNET_HEXROWSZ; i++) { |
213 | if (i < sz) |
214 | q += sprintf(q, "%02x ", p[i]); |
215 | else |
216 | q += sprintf(q, "** "); |
217 | } |
218 | *q++ = ':'; *q++ = ' '; |
219 | for (i = 0; i < UNET_HEXROWSZ; i++) { |
220 | if (i < sz) |
221 | *q++ = (p[i] >= 32 && p[i] < 127) ? p[i] : '.'; |
222 | else |
223 | *q++ = '*'; |
224 | } |
225 | *q++ = '\n'; |
226 | *q++ = 0; |
227 | printk("%s", buf); |
228 | c = (sz >= UNET_HEXROWSZ) ? UNET_HEXROWSZ : sz; |
229 | sz -= c, p += c, o += c; |
230 | } |
231 | } |
232 | |
233 | #endif |
234 | |
235 | /*----- The unet network interfaces ---------------------------------------*/ |
236 | |
237 | /* --- @unet_ifopen@ --- * |
238 | * |
239 | * Arguments: @struct device *nif@ = pointer to network interface |
240 | * |
241 | * Returns: Zero or error condition. |
242 | * |
243 | * Use: Turns on the network interface ready for action. Oh, yes. |
244 | */ |
245 | |
246 | static int unet_ifopen(struct device *nif) |
247 | { |
248 | D( struct unet *u = nif->priv; |
249 | if (u->f & UNIF_DEBUG) |
250 | printk(KERN_DEBUG "unet: opening interface %s\n", u->name); ) |
251 | MOD_INC_USE_COUNT; |
252 | return (0); |
253 | } |
254 | |
255 | /* --- @unet_ifclose@ --- * |
256 | * |
257 | * Arguments: @struct device *nif@ = pointer to network interface |
258 | * |
259 | * Returns: Zero or error condition. |
260 | * |
261 | * Use: Turns off the network interface. |
262 | */ |
263 | |
264 | static int unet_ifclose(struct device *nif) |
265 | { |
266 | D( struct unet *u = nif->priv; |
267 | if (u->f & UNIF_DEBUG) |
268 | printk(KERN_DEBUG "unet: closing interface %d\n", u->seq); ) |
269 | MOD_DEC_USE_COUNT; |
270 | return (0); |
271 | } |
272 | |
273 | /* --- @unet_iftx@ --- * |
274 | * |
275 | * Arguments: @struct sk_buff *skb@ = incoming network packet |
276 | * @struct device *nif@ = pointer to network interface |
277 | * |
278 | * Returns: Zero or error condition. |
279 | * |
280 | * Use: Queues a network packet ready for collection by the user |
281 | * end of the business. |
282 | */ |
283 | |
284 | static int unet_iftx(struct sk_buff *skb, struct device *nif) |
285 | { |
286 | struct unet *u = nif->priv; |
287 | int qed; |
288 | |
289 | DIF(u, |
290 | printk(KERN_DEBUG "unet: packet received on if %s\n", u->name); |
291 | unet_hexdump(KERN_DEBUG " ", skb->data, skb->len); ) |
292 | |
293 | /* --- Discard packets when nobody's listening --- */ |
294 | |
295 | if ((u->f & UNIF_OPEN) == 0) { |
296 | DIF(u, printk(KERN_DEBUG "unet: dropped packet: nobody's listening\n"); ) |
297 | dev_kfree_skb(skb); |
298 | u->e.tx_dropped++; |
299 | return (0); |
300 | } |
301 | |
302 | /* --- Discard packets when the queue's too long --- */ |
303 | |
304 | if (u->skbq.qlen >= UNET_QMAXLEN) { |
305 | DIF(u, printk(KERN_DEBUG "unet: refused packet: queue overflow\n"); ) |
306 | return (-1); |
307 | } |
308 | |
309 | /* --- Attach the buffer to the waiting list --- */ |
310 | |
311 | qed = u->skbq.qlen; |
312 | skb_queue_tail(&u->skbq, skb); |
313 | u->e.tx_packets++; |
314 | DIF(u, printk(KERN_DEBUG "unet: queued packet OK\n"); ) |
315 | |
316 | /* --- If there are waiting processes, give 'em a kick --- */ |
317 | |
318 | if (qed == 0) { |
319 | DIF(u, printk(KERN_DEBUG "unet: waking up sleeping listeners\n"); ) |
320 | wake_up_interruptible(&u->q); |
321 | } |
322 | return (0); |
323 | } |
324 | |
325 | /* --- @unet_ifgetstats@ --- * |
326 | * |
327 | * Arguments: @struct device *nif@ = pointer to network interface |
328 | * |
329 | * Returns: Pointer to a statistics buffer. |
330 | * |
331 | * Use: Returns a block of interface statistics. |
332 | */ |
333 | |
334 | static struct enet_statistics *unet_ifgetstats(struct device *nif) |
335 | { |
336 | struct unet *u = nif->priv; |
337 | DIF(u, printk(KERN_DEBUG "unet: stats request for if %s\n", u->name); ) |
338 | return (&u->e); |
339 | } |
340 | |
341 | /* --- @unet_ifinit@ --- * |
342 | * |
343 | * Arguments: @struct device *nif@ = pointer to network interface |
344 | * |
345 | * Returns: Zero or error condition. |
346 | * |
347 | * Use: Initialises a unet network interface. |
348 | */ |
349 | |
350 | static int unet_ifinit(struct device *nif) |
351 | { |
352 | struct unet *u = nif->priv; |
353 | |
354 | DIF(u, printk(KERN_DEBUG "unet: initialise interface %s\n", u->name); ) |
355 | |
356 | /* --- Initialise statistics gathering --- */ |
357 | |
358 | memset(&u->e, 0, sizeof(u->e)); |
359 | u->nif.get_stats = unet_ifgetstats; |
360 | |
361 | /* --- Opening and closing interfaces --- */ |
362 | |
363 | u->nif.open = unet_ifopen; |
364 | u->nif.stop = unet_ifclose; |
365 | |
366 | /* --- Sending packets to the `outside world' --- */ |
367 | |
368 | u->nif.hard_start_xmit = unet_iftx; |
369 | |
370 | /* --- Some initialisation magic --- */ |
371 | |
372 | #ifdef notdef |
373 | for (i = 0; i < DEV_NUMBUFFS; i++) |
374 | skb_queue_head_init(&u->nif.buffs[i]); |
375 | #endif |
376 | |
377 | /* --- Configure other grotty bits of the interface --- */ |
378 | |
379 | u->nif.hard_header = 0; |
380 | u->nif.rebuild_header = 0; |
381 | u->nif.set_mac_address = 0; |
382 | |
7e365031 |
383 | u->nif.type = ARPHRD_TUNNEL; /* Got a better idea? */ |
4e3819cf |
384 | u->nif.hard_header_len = 0; |
385 | u->nif.mtu = 1500 - MAX_HEADER; |
386 | u->nif.addr_len = 0; |
387 | u->nif.tx_queue_len = 16; /* I keep my own queue */ |
388 | |
389 | memset(u->nif.broadcast, 0xFFu, MAX_ADDR_LEN); |
390 | |
391 | u->nif.flags = IFF_NOARP; |
392 | |
393 | /* --- Finished! --- */ |
394 | |
395 | return (0); |
396 | } |
397 | |
398 | /*----- Attachment management ---------------------------------------------*/ |
399 | |
400 | /* --- @unet_setup@ --- * |
401 | * |
402 | * Arguments: @struct unet *u@ = pointer to a unet block |
403 | * @int seq@ = sequence number to allocate |
404 | * |
405 | * Returns: Zero or error condition. |
406 | * |
407 | * Use: Initialises a unet block ready for action. |
408 | */ |
409 | |
410 | static int unet_setup(struct unet *u, int seq) |
411 | { |
412 | static struct device tpl; |
413 | int e; |
414 | |
415 | D( printk(KERN_DEBUG "unet: setting up unet block %d\n", seq); ) |
416 | |
417 | /* --- A little bit of initialisation --- */ |
418 | |
419 | u->seq = seq; |
420 | u->f = 0; |
421 | u->q = 0; |
422 | |
423 | /* --- Inherit device debug flag from global flag --- */ |
424 | |
425 | #if UNET_DEBUG == UNET_DEBUGRUNTIME |
426 | if (unet_debug) |
427 | u->f |= UNIF_DEBUG; |
428 | #elif UNET_DEBUG == UNET_DEBUGALWAYS |
429 | u->f |= UNIF_DEBUG; |
430 | #endif |
431 | |
432 | /* --- Set up the network device --- */ |
433 | |
434 | u->nif = tpl; |
435 | sprintf(u->name, "unet%d", seq); |
436 | u->nif.name = u->name; |
437 | u->nif.priv = u; |
438 | u->nif.init = unet_ifinit; |
439 | u->protocol = htons(ETH_P_IP); |
440 | |
441 | if ((e = register_netdev(&u->nif)) != 0) { |
442 | printk(KERN_ERR "unet: couldn't register net interface\n"); |
443 | return (e); |
444 | } |
445 | |
446 | /* --- Empty the skbuff list --- */ |
447 | |
448 | skb_queue_head_init(&u->skbq); |
449 | |
450 | /* --- We're only finished, that's all --- */ |
451 | |
452 | return (0); |
453 | } |
454 | |
455 | /* --- @unet_flush@ --- * |
456 | * |
457 | * Arguments: @struct unet *u@ = pointer to a unet block |
458 | * |
459 | * Returns: --- |
460 | * |
461 | * Use: Releases all the packets waiting for transmission. |
462 | */ |
463 | |
464 | static void unet_flush(struct unet *u) |
465 | { |
466 | struct sk_buff *skb; |
467 | |
468 | #if UNET_DEBUG != UNET_DEBUGNEVER |
469 | int i = 0; |
470 | #endif |
471 | |
472 | DIF(u, printk(KERN_DEBUG "unet: flushing packets on %s\n", u->name); ) |
473 | |
474 | while ((skb = skb_dequeue(&u->skbq)) != 0) { |
475 | dev_kfree_skb(skb); |
476 | D( i++; ) |
477 | } |
478 | DIF(u, printk(KERN_DEBUG "unet: released %d waiting packets\n", i); ) |
479 | } |
480 | |
481 | /* --- @unet_kill@ --- * |
482 | * |
483 | * Arguments: @struct unet *u@ = pointer to a unet block |
484 | * |
485 | * Returns: --- |
486 | * |
487 | * Use: Kills and decommissions a Usernet block. |
488 | */ |
489 | |
490 | static void unet_kill(struct unet *u) |
491 | { |
492 | unet_flush(u); |
493 | unregister_netdev(&u->nif); |
494 | } |
495 | |
496 | /*----- Handling the unet device ------------------------------------------*/ |
497 | |
498 | /* --- @unet_devopen@ --- * |
499 | * |
500 | * Arguments: @struct inode *ino@ = inode block to open |
501 | * @struct file *f@ = file block to play with |
502 | * |
503 | * Returns: Zero or error condition. |
504 | * |
505 | * Use: Handles the opening of a unet device. |
506 | */ |
507 | |
508 | static int unet_devopen(struct inode *ino, struct file *f) |
509 | { |
510 | struct unet *u, **up; |
511 | int seq; |
512 | int e = 0; |
513 | |
514 | D( printk(KERN_DEBUG "unet: device open request\n"); ) |
515 | |
516 | /* --- Decide whether this is a persistent unet --- */ |
517 | |
518 | if ((seq = MINOR(ino->i_rdev)) < unet_npersist) { |
519 | u = &unet_persistent[seq]; |
520 | if (u->f & UNIF_OPEN) { |
521 | e = -EBUSY; |
522 | goto tidy_0; |
523 | } |
524 | D( printk(KERN_DEBUG "unet: opened persistent %s\n", u->name); ) |
525 | } |
526 | |
527 | /* --- Otherwise we've got to create a new one --- */ |
528 | |
88613db4 |
529 | else if (seq == UNET_TRANSMINOR) { |
4e3819cf |
530 | |
531 | /* --- Try to find a spare sequence number --- */ |
532 | |
88613db4 |
533 | if (unet_nif >= unet_maxif) { |
534 | printk(KERN_NOTICE "unet: no interfaces left\n"); |
535 | e = -ENFILE; |
536 | goto tidy_0; |
537 | } |
4e3819cf |
538 | for (seq = unet_npersist, up = &unet_list; *up != 0; |
539 | seq++, up = &(*up)->next) { |
540 | if ((*up)->seq > seq) |
541 | break; |
4e3819cf |
542 | } |
4e3819cf |
543 | D( printk(KERN_DEBUG "unet: allocated sequence number %d\n", seq); ) |
544 | |
545 | /* --- Allocate a new block --- */ |
546 | |
547 | if ((u = kmalloc(sizeof(*u), GFP_KERNEL)) == 0) { |
548 | printk(KERN_ERR "unet: couldn't allocate a unet block\n"); |
549 | e = -ENOMEM; |
550 | goto tidy_0; |
551 | } |
552 | |
553 | /* --- Initialise the block --- */ |
554 | |
555 | if ((e = unet_setup(u, seq)) != 0) |
556 | goto tidy_1; |
557 | u->f |= UNIF_TRANS; |
88613db4 |
558 | unet_nif++; |
4e3819cf |
559 | |
560 | /* --- Link the block into the list --- */ |
561 | |
562 | u->next = *up; |
563 | u->prev = up; |
564 | if (*up) |
565 | (*up)->prev = &u->next; |
566 | *up = u; |
567 | |
568 | D( printk(KERN_DEBUG "unet: opened transient %d\n", seq); |
569 | unet_dumpBlock(u); ) |
88613db4 |
570 | } else |
571 | return (-ENODEV); |
4e3819cf |
572 | |
573 | /* --- Done --- */ |
574 | |
575 | u->f |= UNIF_OPEN; |
576 | f->private_data = u; |
577 | MOD_INC_USE_COUNT; |
578 | return (0); |
579 | |
580 | /* --- Tidy up after little disasters --- */ |
581 | |
582 | tidy_1: |
583 | kfree(u); |
584 | tidy_0: |
585 | return (e); |
586 | } |
587 | |
588 | /* --- @unet_devclose@ --- * |
589 | * |
590 | * Arguments: @struct inode *ino@ = pointer to inode block |
591 | * @struct file *f@ = pointer to file block |
592 | * |
593 | * Returns: --- |
594 | * |
595 | * Use: Frees up a unet connection. |
596 | */ |
597 | |
598 | static int unet_devclose(struct inode *ino, struct file *f) |
599 | { |
600 | struct unet *u = f->private_data; |
601 | |
602 | DIF(u, printk(KERN_DEBUG "unet: closing %s\n", u->name); ) |
603 | |
604 | /* --- A transient unet needs to be destroyed --- */ |
605 | |
606 | if (u->f & UNIF_TRANS) { |
88613db4 |
607 | int seq = u->seq; |
4e3819cf |
608 | *u->prev = u->next; |
609 | if (u->next) |
610 | u->next->prev = u->prev; |
611 | unet_kill(u); |
612 | kfree(u); |
88613db4 |
613 | unet_nif--; |
614 | D( printk(KERN_DEBUG "unet: released transient %d\n", seq); ) |
4e3819cf |
615 | } |
616 | |
617 | /* --- A persistent unet needs to be shutdown --- */ |
618 | |
619 | else { |
620 | u->f &= ~UNIF_OPEN; |
621 | unet_flush(u); |
622 | DIF(u, printk(KERN_DEBUG "unet: unblocked persistent unet\n"); ) |
623 | } |
624 | |
625 | MOD_DEC_USE_COUNT; |
626 | return (0); |
627 | } |
628 | |
629 | /* --- @unet_devpoll@ --- * |
630 | * |
631 | * Arguments: @struct file *f@ = pointer to my file block |
632 | * @struct poll_table_struct *p@ = poll table to wait on |
633 | * |
634 | * Returns: Nonzero if OK to continue, zero if waiting. |
635 | * |
636 | * Use: Plays a unet device's part in a @poll@(2) call. |
637 | */ |
638 | |
639 | static unsigned unet_devpoll(struct file *f, struct poll_table_struct *p) |
640 | { |
641 | struct unet *u = f->private_data; |
642 | unsigned m = 0; |
643 | |
644 | DIF(u, printk(KERN_DEBUG "unet: poll request for %s\n", u->name); ) |
645 | |
646 | poll_wait(f, &u->q, p); |
647 | if (skb_peek(&u->skbq)) |
648 | m |= POLLIN | POLLRDNORM; |
649 | m |= POLLOUT | POLLWRNORM; |
650 | return (m); |
651 | } |
652 | |
653 | /* --- @unet_devwrite@ --- * |
654 | * |
655 | * Arguments: @struct file *f@ = pointer to the file block |
656 | * @char *buf@ = pointer to caller's buffer |
657 | * @size_t sz@ = size of data to send |
658 | * @loff_t *off@ = offset to set (ignored) |
659 | * |
660 | * Returns: Number of bytes written, or error condition. |
661 | * |
662 | * Use: Sends a packet of data. No buffering is done. |
663 | */ |
664 | |
665 | static ssize_t unet_devwrite(struct file *f, const char *buf, size_t sz, |
666 | loff_t *off) |
667 | { |
668 | struct unet *u = f->private_data; |
669 | struct sk_buff *skb; |
670 | |
671 | DIF(u, printk(KERN_DEBUG "unet: write request for %s\n", u->name); ) |
672 | |
673 | /* --- Dump the packet we're meant to send --- */ |
674 | |
675 | #ifdef UNET_DEBUG |
676 | if (u->f & UNIF_DEBUG) { |
677 | void *b = kmalloc(sz, GFP_KERNEL); |
678 | if (b) { |
679 | copy_from_user(b, buf, sz); |
680 | unet_hexdump(KERN_DEBUG " ", b, sz); |
681 | kfree(b); |
682 | } else |
683 | printk(KERN_NOTICE "unet: not enough memory to dump block"); |
684 | } |
685 | #endif |
686 | |
687 | /* --- Allocate an skbuff for the block --- */ |
688 | |
689 | if ((skb = dev_alloc_skb(sz)) == 0) { |
690 | printk(KERN_ERR "unet: failed to allocate skbuff\n"); |
691 | u->e.rx_dropped++; |
692 | return (-ENOSR); |
693 | } |
694 | |
695 | /* --- Copy my data into the skbuff --- */ |
696 | |
697 | copy_from_user(skb_put(skb, sz), buf, sz); |
698 | skb->dev = &u->nif; |
699 | skb->mac.raw = skb->data; |
700 | skb->protocol = u->protocol; |
701 | netif_rx(skb); |
702 | u->e.rx_packets++; |
703 | return (sz); |
704 | } |
705 | |
706 | /* --- @unet_devread@ --- * |
707 | * |
708 | * Arguments: @struct file *f@ = pointer to the file block |
709 | * @char *buf@ = pointer to caller's buffer |
710 | * @size_t sz@ = size of caller's buffer |
711 | * @loff_t *off@ = offset to set (ignored) |
712 | * |
713 | * Returns: Number of bytes read, or error condition. |
714 | * |
715 | * Use: Reads the next packet waiting for the device. |
716 | */ |
717 | |
718 | static ssize_t unet_devread(struct file *f, char *buf, size_t sz, |
719 | loff_t *off) |
720 | { |
721 | struct unet *u = f->private_data; |
722 | struct sk_buff *skb; |
723 | |
724 | DIF(u, printk(KERN_DEBUG "unet: read request for %s\n", u->name); ) |
725 | |
726 | /* --- Is the user sane? --- * |
727 | * |
728 | * The UDP protocol returns immediately in response to a zero-length read, |
729 | * and following this behaviour seems to cause `least surprise'. |
730 | */ |
731 | |
732 | if (!sz) |
733 | return (0); |
734 | |
735 | /* --- Make sure there's a packet waiting for me --- */ |
736 | |
737 | if ((skb = skb_dequeue(&u->skbq)) == 0) { |
738 | struct wait_queue wq = { current, 0 }; |
739 | |
740 | DIF(u, printk(KERN_DEBUG "unet: no packets waiting\n"); ) |
741 | |
742 | /* --- Check for nonblocking I/O --- */ |
743 | |
744 | if (f->f_flags & O_NONBLOCK) { |
745 | DIF(u, printk(KERN_DEBUG "unet: nonblocking read: fail\n"); ) |
746 | return (-EWOULDBLOCK); |
747 | } |
748 | |
749 | /* --- Otherwise block until there's a packet --- */ |
750 | |
751 | current->state = TASK_INTERRUPTIBLE; |
752 | add_wait_queue(&u->q, &wq); |
753 | |
754 | do { |
755 | |
756 | if (signal_pending(current)) { |
757 | |
758 | DIF(u, printk(KERN_DEBUG "unet: interrupted by signal\n"); ) |
759 | |
760 | remove_wait_queue(&u->q, &wq); |
761 | current->state = TASK_RUNNING; |
762 | return (-ERESTARTSYS); |
763 | } |
764 | |
765 | DIF(u, printk(KERN_DEBUG "unet: blocking until packet arrives\n"); ) |
766 | |
767 | schedule(); |
768 | |
769 | } while ((skb = skb_dequeue(&u->skbq)) == 0); |
770 | |
771 | remove_wait_queue(&u->q, &wq); |
772 | current->state = TASK_RUNNING; |
773 | } |
774 | |
775 | DIF(u, printk(KERN_DEBUG "unet: found a packet\n"); ) |
776 | |
777 | /* --- There is now a packet waiting --- */ |
778 | |
779 | if (sz > skb->len) |
780 | sz = skb->len; |
781 | copy_to_user(buf, skb->data, sz); |
782 | dev_kfree_skb(skb); |
783 | |
784 | DIF(u, printk(KERN_DEBUG "unet: passed packet on to user\n"); ) |
785 | |
786 | return (sz); |
787 | } |
788 | |
789 | /* --- @unet_devioctl@ --- * |
790 | * |
791 | * Arguments: @struct inode *ino@ = pointer to inode block |
792 | * @struct file *f@ = pointer to file block |
793 | * @unsigned int c@ = command code to execute |
794 | * @unsigned long arg@ = argument passed to me |
795 | * |
796 | * Returns: Positive return value, or negative error condition. |
797 | * |
798 | * Use: Performs miscellaneous operations on a unet device. |
799 | */ |
800 | |
801 | static int unet_devioctl(struct inode *ino, |
802 | struct file *f, |
803 | unsigned int c, |
804 | unsigned long arg) |
805 | { |
806 | struct unet *u = f->private_data; |
807 | int e = 0; |
808 | |
809 | DIF(u, printk(KERN_DEBUG "unet: ioctl request for %s\n", u->name); ) |
810 | |
811 | switch (c) { |
812 | |
813 | /* --- @FIONREAD@ --- * |
814 | * |
815 | * Caller wants to know how big the next packet will be. Don't |
816 | * disappoint. |
817 | */ |
818 | |
819 | case FIONREAD: { |
820 | struct sk_buff *skb = skb_peek(&u->skbq); |
821 | |
822 | DIF(u, printk(KERN_DEBUG "unet: FIONREAD found %d bytes\n", |
823 | skb ? skb->len : 0); ) |
824 | |
825 | if (skb) |
826 | e = skb->len; |
827 | } break; |
828 | |
829 | /* --- @UNIOCGINFO@ --- * |
830 | * |
831 | * Caller wants information about me. |
832 | */ |
833 | |
834 | case UNIOCGINFO: { |
835 | struct unet_info uni, *unip; |
836 | |
837 | DIF(u, printk(KERN_DEBUG "unet: UNIOCGINFO called\n"); ) |
838 | |
839 | unip = (struct unet_info *)arg; |
840 | |
841 | /* --- Special case --- * |
842 | * |
843 | * If the pointer is null, this call means `are you there?' and can |
844 | * be used to check for a Usernet attachment. |
845 | */ |
846 | |
847 | if (!unip) |
848 | break; |
849 | |
850 | /* --- Ensure that the area can be written to --- */ |
851 | |
852 | if ((e = verify_area(VERIFY_WRITE, unip, sizeof(*unip))) != 0) |
853 | return (e); |
854 | |
855 | /* --- Build the information block in memory --- */ |
856 | |
857 | memset(&uni, 0, sizeof(uni)); /* Paranoia */ |
858 | strncpy(uni.uni_ifname, u->name, UNET_NAMEMAX); |
859 | uni.uni_mtu = u->nif.mtu; |
860 | uni.uni_family = AF_INET; |
861 | uni.uni_proto = ntohs(u->protocol); |
862 | uni.uni_flags = u->f; |
863 | |
864 | /* --- Copy it to the user and return --- */ |
865 | |
866 | copy_to_user(unip, &uni, sizeof(uni)); |
867 | } break; |
868 | |
869 | /* --- @UNIOCSDEBUG@ --- */ |
870 | |
871 | #if UNET_DEBUG != UNET_DEBUGNEVER |
872 | case UNIOCSDEBUG: { |
873 | int n = !!arg; |
874 | int o = !!(u->f & UNIF_DEBUG); |
875 | |
88613db4 |
876 | if (!capable(CAP_SYS_ADMIN)) |
877 | return (-EPERM); |
4e3819cf |
878 | if (n || o) { |
879 | printk(KERN_DEBUG "unet: UNIOCSDEBUG on %s: %s\n", u->name, |
880 | (o && n) ? "debugging still on" : |
881 | (!o && n) ? "debugging turned on" : |
882 | (o && !n) ? "debugging turned off" : |
883 | (!o && !n) ? "you can't see this message" : |
884 | "Logic failure: universe exploding"); |
885 | } |
886 | if (n) |
887 | u->f |= UNIF_DEBUG; |
888 | else |
889 | u->f &= ~UNIF_DEBUG; |
890 | } break; |
891 | #endif |
892 | |
893 | /* --- @UNIOCGPROTO@ and @UNIOCSPROTO@ --- */ |
894 | |
895 | case UNIOCGPROTO: |
896 | D( printk(KERN_DEBUG "unet: UNIOCGPROTO on %s: read protocol: %d\n", |
897 | u->name, ntohs(u->protocol)); ) |
898 | e = ntohs(u->protocol); |
899 | break; |
900 | case UNIOCSPROTO: |
901 | D( printk(KERN_DEBUG "unet: UNIOCSPROTO on %s: set protocol: %d\n", |
902 | u->name, (int)arg); ) |
903 | u->protocol = htons(arg); |
904 | break; |
905 | |
906 | /* --- @UNIOCGGDEBUG@ and @UNIOCSGDEBUG@ --- */ |
907 | |
908 | case UNIOCGGDEBUG: |
909 | D( printk(KERN_DEBUG "unet: UNIOCGGDEBUG: get global debug: on\n"); ) |
910 | #if UNET_DEBUG == UNET_DEBUGRUNTIME |
911 | e = unet_debug; |
912 | #elif UNET_DEBUG == UNET_DEBUGALWAYS |
913 | e = 1; |
914 | #elif UNET_DEBUG == UNET_DEBUGNEVER |
915 | e = 0; |
916 | #endif |
917 | break; |
918 | |
919 | #if UNET_DEBUG == UNET_DEBUGRUNTIME |
920 | case UNIOCSGDEBUG: |
88613db4 |
921 | if (!capable(CAP_SYS_ADMIN)) |
922 | return (-EPERM); |
923 | if (arg || unet_debug) { |
924 | printk(KERN_DEBUG "unet: UNIOCSGDEBUG: set global debug: %s\n", |
925 | (arg && unet_debug) ? "debugging still on" : |
926 | (!arg && unet_debug) ? "debugging turned off" : |
927 | (arg && !unet_debug) ? "debugging turned on" : |
928 | (!arg && !unet_debug) ? "you can't see this message" : |
929 | "Logic failure: universe exploding"); |
930 | } |
4e3819cf |
931 | unet_debug = !!arg; |
932 | break; |
933 | #endif |
934 | |
935 | /* --- @UNIOCDUMP@ --- */ |
936 | |
937 | #if UNET_DEBUG != UNET_DEBUGNEVER |
938 | case UNIOCDUMP: |
939 | D( unet_dumpBlock(u); ) |
940 | break; |
941 | #endif |
942 | |
943 | /* --- @UNIOCGMAXIF@ --- */ |
944 | |
945 | case UNIOCGMAXIF: |
946 | D( printk(KERN_DEBUG "unet: UNIOCGMAXIF: unet_maxif = %d\n", |
947 | unet_maxif); ) |
948 | e = unet_maxif; |
949 | break; |
950 | |
951 | /* --- @UNIOCSMAXIF@ --- */ |
952 | |
953 | case UNIOCSMAXIF: |
88613db4 |
954 | if (!capable(CAP_SYS_ADMIN)) |
955 | return (-EPERM); |
956 | D( printk(KERN_DEBUG "unet: UNIOCSMAXIF: " |
957 | "arg = %ld; npersist = %d; nif = %d\n", |
958 | arg, unet_npersist, unet_nif); ) |
4e3819cf |
959 | if (arg < unet_npersist || arg > INT_MAX) |
960 | return (-EINVAL); |
88613db4 |
961 | if (arg < unet_nif) |
962 | return (-EBUSY); |
4e3819cf |
963 | unet_maxif = arg; |
88613db4 |
964 | e = 0; |
965 | D( printk(KERN_DEBUG "unet: UNIOCSMAXIF: set unet_maxif = %d\n", |
4e3819cf |
966 | unet_maxif); ) |
967 | break; |
968 | |
7e365031 |
969 | /* --- @UNIOCFIFFLAGS@ and @UNIOCSIFFLAGS@ --- */ |
970 | |
971 | case UNIOCGIFFLAGS: |
972 | D( printk(KERN_DEBUG "unet: UNIOCGIFFFLAGS\n"); ) |
973 | e = u->nif.flags; |
974 | break; |
975 | case UNIOCSIFFLAGS: |
976 | D( printk(KERN_DEBUG "unet: UNIOCSIFFFLAGS: arg = %ld\n", arg); ) |
977 | if ((u->nif.flags ^ arg) & ~IFF_VOLATILE) |
978 | return (-EINVAL); |
979 | u->nif.flags = arg; |
980 | break; |
981 | |
4e3819cf |
982 | /* --- Everything else --- * |
983 | * |
984 | * You lose. |
985 | */ |
986 | |
987 | default: |
988 | D( printk(KERN_DEBUG "unet: unknown ioctl %08x\n", c); ) |
989 | e = -EINVAL; |
990 | } |
991 | |
992 | return (e); |
993 | } |
994 | |
995 | /*----- The unet device ---------------------------------------------------*/ |
996 | |
997 | /* --- Device operations --- */ |
998 | |
999 | struct file_operations unet_fops = { |
1000 | 0, /* unet_devlseek */ |
1001 | unet_devread, |
1002 | unet_devwrite, |
1003 | 0, /* unet_devreaddir */ |
1004 | unet_devpoll, |
1005 | unet_devioctl, |
1006 | 0, /* unet_devmmap */ |
1007 | unet_devopen, |
1008 | 0, /* unet_flush */ |
1009 | unet_devclose |
1010 | }; |
1011 | |
1012 | /*----- Initaliseation and shutdown ---------------------------------------*/ |
1013 | |
1014 | /* --- @unet_init@ --- * |
1015 | * |
1016 | * Arguments: --- |
1017 | * |
1018 | * Returns: Zero or error condition. |
1019 | * |
1020 | * Use: Registers the unet device. |
1021 | */ |
1022 | |
1023 | __initfunc(int unet_init(void)) |
1024 | { |
1025 | int e = 0; |
1026 | int i = 0; |
1027 | |
1028 | /* --- Register my character device --- */ |
1029 | |
1030 | if ((e = register_chrdev(UNET_MAJOR, "unet", &unet_fops)) != 0) { |
1031 | printk(KERN_ERR "unet: can't claim major device %d\n", UNET_MAJOR); |
1032 | goto tidy_0; |
1033 | } |
1034 | |
1035 | /* --- Make the persistent unet devices --- */ |
1036 | |
1037 | if ((unet_persistent = kmalloc(unet_npersist * sizeof(struct unet), |
1038 | GFP_KERNEL)) == 0) { |
1039 | printk(KERN_ERR "unet: can't allocate %i persistent unet blocks", |
1040 | unet_npersist); |
1041 | e = -ENOMEM; |
1042 | goto tidy_1; |
1043 | } |
1044 | |
1045 | for (i = 0; i < unet_npersist; i++) { |
1046 | if ((e = unet_setup(&unet_persistent[i], i)) != 0) { |
1047 | printk(KERN_ERR "unet: can't create persistent unet %d\n", i); |
1048 | goto tidy_2; |
1049 | } |
1050 | } |
88613db4 |
1051 | unet_nif = unet_npersist; |
4e3819cf |
1052 | |
1053 | /* --- Done --- */ |
1054 | |
1055 | D( unet_dump(); ) |
1056 | return (0); |
1057 | |
1058 | /* --- Some bad stuff happened --- */ |
1059 | |
1060 | tidy_2: |
1061 | while (i > 0) { |
1062 | i--; |
1063 | unregister_netdev(&unet_persistent[i].nif); |
1064 | } |
1065 | kfree(unet_persistent); |
1066 | |
1067 | tidy_1: |
1068 | unregister_chrdev(UNET_MAJOR, "unet"); |
1069 | |
1070 | tidy_0: |
1071 | return (e); |
1072 | } |
1073 | |
1074 | #ifdef MODULE |
1075 | |
1076 | /* --- @init_module@ --- * |
1077 | * |
1078 | * Arguments: --- |
1079 | * |
1080 | * Returns: Zero or error condition. |
1081 | * |
1082 | * Use: Initialises the unet kernel module. |
1083 | */ |
1084 | |
1085 | int init_module(void) |
1086 | { |
1087 | if (unet_npersist < 0 || unet_maxif < unet_npersist |
1088 | #if UNET_DEBUG == UNET_DEBUGRUNTIME |
1089 | || (unet_debug != 0 && unet_debug != 1) |
1090 | #endif |
1091 | ) |
1092 | return (-EINVAL); |
1093 | return (unet_init()); |
1094 | } |
1095 | |
1096 | /* --- @cleanup_module@ --- * |
1097 | * |
1098 | * Arguments: --- |
1099 | * |
1100 | * Returns: --- |
1101 | * |
1102 | * Use: Tidies up the unet module ready for it to be killed. |
1103 | */ |
1104 | |
1105 | void cleanup_module(void) |
1106 | { |
1107 | int i; |
1108 | |
1109 | for (i = 0; i < unet_npersist; i++) { |
1110 | D( printk(KERN_DEBUG "unet: releasing persistent unet %d\n", i); ) |
1111 | unet_kill(&unet_persistent[i]); |
1112 | } |
1113 | kfree(unet_persistent); |
1114 | |
1115 | unregister_chrdev(UNET_MAJOR, "unet"); |
1116 | } |
1117 | |
1118 | #endif |
1119 | |
1120 | /*----- That's all, folks -------------------------------------------------*/ |