5 * o allow users to set the parameters
6 * o sync/async switching ?
8 * Note: This does _not_ implement CCITT X.25 asynchronous framing
9 * recommendations. Its primarily for testing purposes. If you wanted
10 * to do CCITT then in theory all you need is to nick the HDLC async
11 * checksum routines from ppp.c
14 #include <linux/module.h>
16 #include <asm/system.h>
17 #include <asm/uaccess.h>
18 #include <asm/bitops.h>
19 #include <linux/string.h>
21 #include <linux/interrupt.h>
23 #include <linux/tty.h>
24 #include <linux/errno.h>
25 #include <linux/netdevice.h>
26 #include <linux/etherdevice.h>
27 #include <linux/skbuff.h>
28 #include <linux/if_arp.h>
29 #include <linux/x25.h>
30 #include <linux/lapb.h>
31 #include <linux/init.h>
34 typedef struct x25_ctrl
{
35 char if_name
[8]; /* "xasy0\0" .. "xasy99999\0" */
36 struct x25_asy ctrl
; /* X.25 things */
37 struct net_device dev
; /* the device */
40 static x25_asy_ctrl_t
**x25_asy_ctrls
= NULL
;
42 int x25_asy_maxdev
= SL_NRUNIT
; /* Can be overridden with insmod! */
43 MODULE_PARM(x25_asy_maxdev
, "i");
45 static struct tty_ldisc x25_ldisc
;
47 static int x25_asy_esc(unsigned char *p
, unsigned char *d
, int len
);
48 static void x25_asy_unesc(struct x25_asy
*sl
, unsigned char c
);
50 /* Find a free X.25 channel, and link in this `tty' line. */
51 static inline struct x25_asy
*x25_asy_alloc(void)
53 x25_asy_ctrl_t
*slp
= NULL
;
56 if (x25_asy_ctrls
== NULL
)
57 return NULL
; /* Master array missing ! */
59 for (i
= 0; i
< x25_asy_maxdev
; i
++)
61 slp
= x25_asy_ctrls
[i
];
66 if (!test_and_set_bit(SLF_INUSE
, &slp
->ctrl
.flags
))
71 /* Sorry, too many, all slots in use */
72 if (i
>= x25_asy_maxdev
)
75 /* If no channels are available, allocate one */
77 (x25_asy_ctrls
[i
] = (x25_asy_ctrl_t
*)kmalloc(sizeof(x25_asy_ctrl_t
),
78 GFP_KERNEL
)) != NULL
) {
79 slp
= x25_asy_ctrls
[i
];
80 memset(slp
, 0, sizeof(x25_asy_ctrl_t
));
82 /* Initialize channel control data */
83 set_bit(SLF_INUSE
, &slp
->ctrl
.flags
);
85 sprintf(slp
->if_name
, "x25asy%d", i
);
86 slp
->dev
.name
= slp
->if_name
;
87 slp
->dev
.base_addr
= i
;
88 slp
->dev
.priv
= (void*)&(slp
->ctrl
);
90 slp
->dev
.init
= x25_asy_init
;
95 /* register device so that it can be ifconfig'ed */
96 /* x25_asy_init() will be called as a side-effect */
97 /* SIDE-EFFECT WARNING: x25_asy_init() CLEARS slp->ctrl ! */
99 if (register_netdev(&(slp
->dev
)) == 0)
101 /* (Re-)Set the INUSE bit. Very Important! */
102 set_bit(SLF_INUSE
, &slp
->ctrl
.flags
);
103 slp
->ctrl
.dev
= &(slp
->dev
);
104 slp
->dev
.priv
= (void*)&(slp
->ctrl
);
105 return (&(slp
->ctrl
));
109 clear_bit(SLF_INUSE
,&(slp
->ctrl
.flags
));
110 printk("x25_asy_alloc() - register_netdev() failure.\n");
117 /* Free an X.25 channel. */
119 static inline void x25_asy_free(struct x25_asy
*sl
)
121 /* Free all X.25 frame buffers. */
131 if (!test_and_clear_bit(SLF_INUSE
, &sl
->flags
)) {
132 printk("%s: x25_asy_free for already free unit.\n", sl
->dev
->name
);
136 /* MTU has been changed by the IP layer. Unfortunately we are not told
137 about this, but we spot it ourselves and fix things up. We could be
138 in an upcall from the tty driver, or in an ip packet queue. */
140 static void x25_asy_changed_mtu(struct x25_asy
*sl
)
142 struct net_device
*dev
= sl
->dev
;
143 unsigned char *xbuff
, *rbuff
, *oxbuff
, *orbuff
;
149 xbuff
= (unsigned char *) kmalloc (len
+ 4, GFP_ATOMIC
);
150 rbuff
= (unsigned char *) kmalloc (len
+ 4, GFP_ATOMIC
);
152 if (xbuff
== NULL
|| rbuff
== NULL
)
154 printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n",
173 if (sl
->xleft
<= len
) {
174 memcpy(sl
->xbuff
, sl
->xhead
, sl
->xleft
);
180 sl
->xhead
= sl
->xbuff
;
183 if (sl
->rcount
<= len
) {
184 memcpy(sl
->rbuff
, orbuff
, sl
->rcount
);
187 sl
->rx_over_errors
++;
188 set_bit(SLF_ERROR
, &sl
->flags
);
195 restore_flags(flags
);
204 /* Set the "sending" flag. This must be atomic, hence the ASM. */
206 static inline void x25_asy_lock(struct x25_asy
*sl
)
208 if (test_and_set_bit(0, (void *) &sl
->dev
->tbusy
))
209 printk("%s: trying to lock already locked device!\n", sl
->dev
->name
);
213 /* Clear the "sending" flag. This must be atomic, hence the ASM. */
215 static inline void x25_asy_unlock(struct x25_asy
*sl
)
217 if (!test_and_clear_bit(0, (void *)&sl
->dev
->tbusy
))
218 printk("%s: trying to unlock already unlocked device!\n", sl
->dev
->name
);
221 /* Send one completely decapsulated IP datagram to the IP layer. */
223 static void x25_asy_bump(struct x25_asy
*sl
)
232 skb
= dev_alloc_skb(count
+1);
235 printk("%s: memory squeeze, dropping packet.\n", sl
->dev
->name
);
239 skb_push(skb
,1); /* LAPB internal control */
241 memcpy(skb_put(skb
,count
), sl
->rbuff
, count
);
242 skb
->mac
.raw
=skb
->data
;
243 skb
->protocol
=htons(ETH_P_X25
);
244 if((err
=lapb_data_received(sl
,skb
))!=LAPB_OK
)
247 printk(KERN_DEBUG
"x25_asy: data received err - %d\n",err
);
256 /* Encapsulate one IP datagram and stuff into a TTY queue. */
257 static void x25_asy_encaps(struct x25_asy
*sl
, unsigned char *icp
, int len
)
263 if (sl
->mtu
!= sl
->dev
->mtu
) { /* Someone has been ifconfigging */
265 x25_asy_changed_mtu(sl
);
269 { /* Sigh, shouldn't occur BUT ... */
271 printk ("%s: truncating oversized transmit packet!\n", sl
->dev
->name
);
278 count
= x25_asy_esc(p
, (unsigned char *) sl
->xbuff
, len
);
280 /* Order of next two lines is *very* important.
281 * When we are sending a little amount of data,
282 * the transfer may be completed inside driver.write()
283 * routine, because it's running with interrupts enabled.
284 * In this case we *never* got WRITE_WAKEUP event,
285 * if we did not request it before write operation.
286 * 14 Oct 1994 Dmitry Gorodchanin.
288 sl
->tty
->flags
|= (1 << TTY_DO_WRITE_WAKEUP
);
289 actual
= sl
->tty
->driver
.write(sl
->tty
, 0, sl
->xbuff
, count
);
290 sl
->xleft
= count
- actual
;
291 sl
->xhead
= sl
->xbuff
+ actual
;
293 clear_bit(SLF_OUTWAIT
, &sl
->flags
); /* reset outfill flag */
297 * Called by the driver when there's room for more data. If we have
298 * more packets to send, we send them here.
300 static void x25_asy_write_wakeup(struct tty_struct
*tty
)
303 struct x25_asy
*sl
= (struct x25_asy
*) tty
->disc_data
;
305 /* First make sure we're connected. */
306 if (!sl
|| sl
->magic
!= X25_ASY_MAGIC
|| !sl
->dev
->start
)
311 /* Now serial buffer is almost free & we can start
312 * transmission of another packet */
314 tty
->flags
&= ~(1 << TTY_DO_WRITE_WAKEUP
);
320 actual
= tty
->driver
.write(tty
, 0, sl
->xhead
, sl
->xleft
);
325 /* Encapsulate an IP datagram and kick it into a TTY queue. */
327 static int x25_asy_xmit(struct sk_buff
*skb
, struct net_device
*dev
)
329 struct x25_asy
*sl
= (struct x25_asy
*)(dev
->priv
);
334 printk("%s: xmit call when iface is down\n", dev
->name
);
341 case 0x01: /* Connection request .. do nothing */
342 if((err
=lapb_connect_request(sl
))!=LAPB_OK
)
343 printk(KERN_ERR
"x25_asy: lapb_connect_request error - %d\n", err
);
346 case 0x02: /* Disconnect request .. do nothing - hang up ?? */
347 if((err
=lapb_disconnect_request(sl
))!=LAPB_OK
)
348 printk(KERN_ERR
"x25_asy: lapb_disconnect_request error - %d\n", err
);
353 skb_pull(skb
,1); /* Remove control byte */
355 * If we are busy already- too bad. We ought to be able
356 * to queue things at this point, to allow for a little
357 * frame buffer. Oh well...
358 * -----------------------------------------------------
359 * I hate queues in X.25 driver. May be it's efficient,
360 * but for me latency is more important. ;)
362 * 14 Oct 1994 Dmitry Gorodchanin.
365 /* May be we must check transmitter timeout here ?
366 * 14 Oct 1994 Dmitry Gorodchanin.
368 #ifdef SL_CHECK_TRANSMIT
369 if (jiffies
- dev
->trans_start
< 20 * HZ
) {
370 /* 20 sec timeout not reached */
373 printk("%s: transmit timed out, %s?\n", dev
->name
,
374 (sl
->tty
->driver
.chars_in_buffer(sl
->tty
) || sl
->xleft
) ?
375 "bad line quality" : "driver error");
377 sl
->tty
->flags
&= ~(1 << TTY_DO_WRITE_WAKEUP
);
384 if((err
=lapb_data_request(sl
,skb
))!=LAPB_OK
)
386 printk(KERN_ERR
"lapbeth: lapb_data_request error - %d\n", err
);
395 * LAPB interface boilerplate
399 * Called when I frame data arrives. We did the work above - throw it
403 static void x25_asy_data_indication(void *token
, struct sk_buff
*skb
)
409 * Data has emerged from the LAPB protocol machine. We don't handle
410 * busy cases too well. Its tricky to see how to do this nicely -
411 * perhaps lapb should allow us to bounce this ?
414 static void x25_asy_data_transmit(void *token
, struct sk_buff
*skb
)
416 struct x25_asy
*sl
=token
;
419 printk(KERN_ERR
"x25_asy: tbusy drop\n");
423 /* We were not busy, so we are now... :-) */
427 sl
->tx_bytes
+=skb
->len
;
428 x25_asy_encaps(sl
, skb
->data
, skb
->len
);
434 * LAPB connection establish/down information.
437 static void x25_asy_connected(void *token
, int reason
)
439 struct x25_asy
*sl
= token
;
443 if ((skb
= dev_alloc_skb(1)) == NULL
) {
444 printk(KERN_ERR
"lapbeth: out of memory\n");
448 ptr
= skb_put(skb
, 1);
452 skb
->protocol
= htons(ETH_P_X25
);
453 skb
->mac
.raw
= skb
->data
;
454 skb
->pkt_type
= PACKET_HOST
;
459 static void x25_asy_disconnected(void *token
, int reason
)
461 struct x25_asy
*sl
= token
;
465 if ((skb
= dev_alloc_skb(1)) == NULL
) {
466 printk(KERN_ERR
"x25_asy: out of memory\n");
470 ptr
= skb_put(skb
, 1);
474 skb
->protocol
= htons(ETH_P_X25
);
475 skb
->mac
.raw
= skb
->data
;
476 skb
->pkt_type
= PACKET_HOST
;
482 /* Open the low-level part of the X.25 channel. Easy! */
484 static int x25_asy_open(struct net_device
*dev
)
486 struct lapb_register_struct x25_asy_callbacks
;
487 struct x25_asy
*sl
= (struct x25_asy
*)(dev
->priv
);
495 * Allocate the X.25 frame buffers:
497 * rbuff Receive buffer.
498 * xbuff Transmit buffer.
503 sl
->rbuff
= (unsigned char *) kmalloc(len
+ 4, GFP_KERNEL
);
504 if (sl
->rbuff
== NULL
) {
507 sl
->xbuff
= (unsigned char *) kmalloc(len
+ 4, GFP_KERNEL
);
508 if (sl
->xbuff
== NULL
) {
515 sl
->flags
&= (1 << SLF_INUSE
); /* Clear ESCAPE & ERROR flags */
518 /* dev->flags |= IFF_UP; */
525 x25_asy_callbacks
.connect_confirmation
=x25_asy_connected
;
526 x25_asy_callbacks
.connect_indication
=x25_asy_connected
;
527 x25_asy_callbacks
.disconnect_confirmation
=x25_asy_disconnected
;
528 x25_asy_callbacks
.disconnect_indication
=x25_asy_disconnected
;
529 x25_asy_callbacks
.data_indication
=x25_asy_data_indication
;
530 x25_asy_callbacks
.data_transmit
=x25_asy_data_transmit
;
532 if((err
=lapb_register(sl
, &x25_asy_callbacks
))==LAPB_OK
)
544 /* Close the low-level part of the X.25 channel. Easy! */
545 static int x25_asy_close(struct net_device
*dev
)
547 struct x25_asy
*sl
= (struct x25_asy
*)(dev
->priv
);
553 sl
->tty
->flags
&= ~(1 << TTY_DO_WRITE_WAKEUP
);
556 if((err
=lapb_unregister(sl
))!=LAPB_OK
)
557 printk(KERN_ERR
"x25_asy_close: lapb_unregister error -%d\n",err
);
559 /* dev->flags &= ~IFF_UP; */
563 static int x25_asy_receive_room(struct tty_struct
*tty
)
565 return 65536; /* We can handle an infinite amount of data. :-) */
569 * Handle the 'receiver data ready' interrupt.
570 * This function is called by the 'tty_io' module in the kernel when
571 * a block of X.25 data has been received, which can now be decapsulated
572 * and sent on to some IP layer for further processing.
575 static void x25_asy_receive_buf(struct tty_struct
*tty
, const unsigned char *cp
, char *fp
, int count
)
577 struct x25_asy
*sl
= (struct x25_asy
*) tty
->disc_data
;
579 if (!sl
|| sl
->magic
!= X25_ASY_MAGIC
|| !sl
->dev
->start
)
583 * Argh! mtu change time! - costs us the packet part received
586 if (sl
->mtu
!= sl
->dev
->mtu
) {
588 x25_asy_changed_mtu(sl
);
591 /* Read the characters out of the buffer */
594 if (!test_and_set_bit(SLF_ERROR
, &sl
->flags
)) {
600 x25_asy_unesc(sl
, *cp
++);
605 * Open the high-level part of the X.25 channel.
606 * This function is called by the TTY module when the
607 * X.25 line discipline is called for. Because we are
608 * sure the tty line exists, we only have to link it to
609 * a free X.25 channel...
612 static int x25_asy_open_tty(struct tty_struct
*tty
)
614 struct x25_asy
*sl
= (struct x25_asy
*) tty
->disc_data
;
617 /* First make sure we're not already connected. */
618 if (sl
&& sl
->magic
== X25_ASY_MAGIC
) {
622 /* OK. Find a free X.25 channel to use. */
623 if ((sl
= x25_asy_alloc()) == NULL
) {
629 if (tty
->driver
.flush_buffer
) {
630 tty
->driver
.flush_buffer(tty
);
632 if (tty
->ldisc
.flush_buffer
) {
633 tty
->ldisc
.flush_buffer(tty
);
636 /* Restore default settings */
637 sl
->dev
->type
= ARPHRD_X25
;
639 /* Perform the low-level X.25 async init */
640 if ((err
= x25_asy_open(sl
->dev
)))
645 /* Done. We have linked the TTY line to a channel. */
646 return sl
->dev
->base_addr
;
651 * Close down an X.25 channel.
652 * This means flushing out any pending queues, and then restoring the
653 * TTY line discipline to what it was before it got hooked to X.25
654 * (which usually is TTY again).
656 static void x25_asy_close_tty(struct tty_struct
*tty
)
658 struct x25_asy
*sl
= (struct x25_asy
*) tty
->disc_data
;
660 /* First make sure we're connected. */
661 if (!sl
|| sl
->magic
!= X25_ASY_MAGIC
)
664 if (sl
->dev
->flags
& IFF_UP
)
666 (void) dev_close(sl
->dev
);
672 unregister_netdev(sl
->dev
);
677 static struct net_device_stats
*x25_asy_get_stats(struct net_device
*dev
)
679 static struct net_device_stats stats
;
680 struct x25_asy
*sl
= (struct x25_asy
*)(dev
->priv
);
682 memset(&stats
, 0, sizeof(struct net_device_stats
));
684 stats
.rx_packets
= sl
->rx_packets
;
685 stats
.tx_packets
= sl
->tx_packets
;
686 stats
.rx_bytes
= sl
->rx_bytes
;
687 stats
.tx_bytes
= sl
->tx_bytes
;
688 stats
.rx_dropped
= sl
->rx_dropped
;
689 stats
.tx_dropped
= sl
->tx_dropped
;
690 stats
.tx_errors
= sl
->tx_errors
;
691 stats
.rx_errors
= sl
->rx_errors
;
692 stats
.rx_over_errors
= sl
->rx_over_errors
;
697 /************************************************************************
698 * STANDARD X.25 ENCAPSULATION *
699 ************************************************************************/
701 int x25_asy_esc(unsigned char *s
, unsigned char *d
, int len
)
703 unsigned char *ptr
= d
;
707 * Send an initial END character to flush out any
708 * data that may have accumulated in the receiver
712 *ptr
++ = X25_END
; /* Send 10111110 bit seq */
715 * For each byte in the packet, send the appropriate
716 * character sequence, according to the X.25 protocol.
725 *ptr
++ = X25_ESCAPE(X25_END
);
729 *ptr
++ = X25_ESCAPE(X25_ESC
);
740 static void x25_asy_unesc(struct x25_asy
*sl
, unsigned char s
)
746 if (!test_and_clear_bit(SLF_ERROR
, &sl
->flags
) && (sl
->rcount
> 2))
750 clear_bit(SLF_ESCAPE
, &sl
->flags
);
755 set_bit(SLF_ESCAPE
, &sl
->flags
);
758 case X25_ESCAPE(X25_ESC
):
759 case X25_ESCAPE(X25_END
):
760 if (test_and_clear_bit(SLF_ESCAPE
, &sl
->flags
))
764 if (!test_bit(SLF_ERROR
, &sl
->flags
))
766 if (sl
->rcount
< sl
->buffsize
)
768 sl
->rbuff
[sl
->rcount
++] = s
;
771 sl
->rx_over_errors
++;
772 set_bit(SLF_ERROR
, &sl
->flags
);
777 /* Perform I/O control on an active X.25 channel. */
778 static int x25_asy_ioctl(struct tty_struct
*tty
, void *file
, int cmd
, void *arg
)
780 struct x25_asy
*sl
= (struct x25_asy
*) tty
->disc_data
;
782 /* First make sure we're connected. */
783 if (!sl
|| sl
->magic
!= X25_ASY_MAGIC
) {
790 if(copy_to_user(arg
, sl
->dev
->name
, strlen(sl
->dev
->name
) + 1))
797 /* Allow stty to read, but not set, the serial port */
800 return n_tty_ioctl(tty
, (struct file
*) file
, cmd
, (unsigned long) arg
);
807 static int x25_asy_open_dev(struct net_device
*dev
)
809 struct x25_asy
*sl
= (struct x25_asy
*)(dev
->priv
);
815 /* Initialize X.25 control device -- register X.25 line discipline */
817 static int x25_asy_init_ctrl_dev(void)
819 int __init
x25_asy_init_ctrl_dev(struct net_device
*dummy
)
824 if (x25_asy_maxdev
< 4) x25_asy_maxdev
= 4; /* Sanity */
826 printk(KERN_INFO
"X.25 async: version 0.00 ALPHA (dynamic channels, max=%d).\n",
828 x25_asy_ctrls
= (x25_asy_ctrl_t
**) kmalloc(sizeof(void*)*x25_asy_maxdev
, GFP_KERNEL
);
829 if (x25_asy_ctrls
== NULL
)
831 printk("X25 async: Can't allocate x25_asy_ctrls[] array! Uaargh! (-> No X.25 available)\n");
835 /* Clear the pointer array, we allocate devices when we need them */
836 memset(x25_asy_ctrls
, 0, sizeof(void*)*x25_asy_maxdev
); /* Pointers */
838 /* Fill in our line protocol discipline, and register it */
839 memset(&x25_ldisc
, 0, sizeof(x25_ldisc
));
840 x25_ldisc
.magic
= TTY_LDISC_MAGIC
;
841 x25_ldisc
.name
= "X.25";
843 x25_ldisc
.open
= x25_asy_open_tty
;
844 x25_ldisc
.close
= x25_asy_close_tty
;
845 x25_ldisc
.read
= NULL
;
846 x25_ldisc
.write
= NULL
;
847 x25_ldisc
.ioctl
= (int (*)(struct tty_struct
*, struct file
*,
848 unsigned int, unsigned long)) x25_asy_ioctl
;
849 x25_ldisc
.poll
= NULL
;
850 x25_ldisc
.receive_buf
= x25_asy_receive_buf
;
851 x25_ldisc
.receive_room
= x25_asy_receive_room
;
852 x25_ldisc
.write_wakeup
= x25_asy_write_wakeup
;
853 if ((status
= tty_register_ldisc(N_X25
, &x25_ldisc
)) != 0) {
854 printk("X.25 async: can't register line discipline (err = %d)\n", status
);
860 /* Return "not found", so that dev_init() will unlink
861 * the placeholder device entry for us.
868 /* Initialise the X.25 driver. Called by the device init code */
870 int x25_asy_init(struct net_device
*dev
)
872 struct x25_asy
*sl
= (struct x25_asy
*)(dev
->priv
);
874 if (sl
== NULL
) /* Allocation failed ?? */
877 /* Set up the control block. (And clear statistics) */
879 memset(sl
, 0, sizeof (struct x25_asy
));
880 sl
->magic
= X25_ASY_MAGIC
;
884 * Finish setting up the DEVICE info.
888 dev
->hard_start_xmit
= x25_asy_xmit
;
889 dev
->open
= x25_asy_open_dev
;
890 dev
->stop
= x25_asy_close
;
891 dev
->get_stats
= x25_asy_get_stats
;
892 dev
->hard_header_len
= 0;
894 dev
->type
= ARPHRD_X25
;
895 dev
->tx_queue_len
= 10;
897 dev_init_buffers(dev
);
899 /* New-style flags. */
900 dev
->flags
= IFF_NOARP
;
909 return x25_asy_init_ctrl_dev();
917 if (x25_asy_ctrls
!= NULL
)
919 for (i
= 0; i
< x25_asy_maxdev
; i
++)
921 if (x25_asy_ctrls
[i
])
924 * VSV = if dev->start==0, then device
925 * unregistered while close proc.
927 if (x25_asy_ctrls
[i
]->dev
.start
)
928 unregister_netdev(&(x25_asy_ctrls
[i
]->dev
));
930 kfree(x25_asy_ctrls
[i
]);
931 x25_asy_ctrls
[i
] = NULL
;
934 kfree(x25_asy_ctrls
);
935 x25_asy_ctrls
= NULL
;
937 if ((i
= tty_register_ldisc(N_X25
, NULL
)))
939 printk("X.25 async: can't unregister line discipline (err = %d)\n", i
);