diff options
Diffstat (limited to 'net/econet')
| -rw-r--r-- | net/econet/Kconfig | 36 | ||||
| -rw-r--r-- | net/econet/Makefile | 7 | ||||
| -rw-r--r-- | net/econet/af_econet.c | 1170 |
3 files changed, 1213 insertions, 0 deletions
diff --git a/net/econet/Kconfig b/net/econet/Kconfig new file mode 100644 index 00000000000..39a2d2975e0 --- /dev/null +++ b/net/econet/Kconfig | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | # | ||
| 2 | # Acorn Econet/AUN protocols | ||
| 3 | # | ||
| 4 | |||
| 5 | config ECONET | ||
| 6 | tristate "Acorn Econet/AUN protocols (EXPERIMENTAL)" | ||
| 7 | depends on EXPERIMENTAL && INET | ||
| 8 | ---help--- | ||
| 9 | Econet is a fairly old and slow networking protocol mainly used by | ||
| 10 | Acorn computers to access file and print servers. It uses native | ||
| 11 | Econet network cards. AUN is an implementation of the higher level | ||
| 12 | parts of Econet that runs over ordinary Ethernet connections, on | ||
| 13 | top of the UDP packet protocol, which in turn runs on top of the | ||
| 14 | Internet protocol IP. | ||
| 15 | |||
| 16 | If you say Y here, you can choose with the next two options whether | ||
| 17 | to send Econet/AUN traffic over a UDP Ethernet connection or over | ||
| 18 | a native Econet network card. | ||
| 19 | |||
| 20 | To compile this driver as a module, choose M here: the module | ||
| 21 | will be called econet. | ||
| 22 | |||
| 23 | config ECONET_AUNUDP | ||
| 24 | bool "AUN over UDP" | ||
| 25 | depends on ECONET | ||
| 26 | help | ||
| 27 | Say Y here if you want to send Econet/AUN traffic over a UDP | ||
| 28 | connection (UDP is a packet based protocol that runs on top of the | ||
| 29 | Internet protocol IP) using an ordinary Ethernet network card. | ||
| 30 | |||
| 31 | config ECONET_NATIVE | ||
| 32 | bool "Native Econet" | ||
| 33 | depends on ECONET | ||
| 34 | help | ||
| 35 | Say Y here if you have a native Econet network card installed in | ||
| 36 | your computer. | ||
diff --git a/net/econet/Makefile b/net/econet/Makefile new file mode 100644 index 00000000000..05fae8be2fe --- /dev/null +++ b/net/econet/Makefile | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | # | ||
| 2 | # Makefile for Econet support code. | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_ECONET) += econet.o | ||
| 6 | |||
| 7 | econet-y := af_econet.o | ||
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c new file mode 100644 index 00000000000..1c1f26c5d67 --- /dev/null +++ b/net/econet/af_econet.c | |||
| @@ -0,0 +1,1170 @@ | |||
| 1 | /* | ||
| 2 | * An implementation of the Acorn Econet and AUN protocols. | ||
| 3 | * Philip Blundell <philb@gnu.org> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * as published by the Free Software Foundation; either version | ||
| 8 | * 2 of the License, or (at your option) any later version. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | |||
| 12 | #define pr_fmt(fmt) fmt | ||
| 13 | |||
| 14 | #include <linux/module.h> | ||
| 15 | |||
| 16 | #include <linux/types.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/string.h> | ||
| 19 | #include <linux/mm.h> | ||
| 20 | #include <linux/socket.h> | ||
| 21 | #include <linux/sockios.h> | ||
| 22 | #include <linux/in.h> | ||
| 23 | #include <linux/errno.h> | ||
| 24 | #include <linux/interrupt.h> | ||
| 25 | #include <linux/if_ether.h> | ||
| 26 | #include <linux/netdevice.h> | ||
| 27 | #include <linux/inetdevice.h> | ||
| 28 | #include <linux/route.h> | ||
| 29 | #include <linux/inet.h> | ||
| 30 | #include <linux/etherdevice.h> | ||
| 31 | #include <linux/if_arp.h> | ||
| 32 | #include <linux/wireless.h> | ||
| 33 | #include <linux/skbuff.h> | ||
| 34 | #include <linux/udp.h> | ||
| 35 | #include <linux/slab.h> | ||
| 36 | #include <linux/vmalloc.h> | ||
| 37 | #include <net/sock.h> | ||
| 38 | #include <net/inet_common.h> | ||
| 39 | #include <linux/stat.h> | ||
| 40 | #include <linux/init.h> | ||
| 41 | #include <linux/if_ec.h> | ||
| 42 | #include <net/udp.h> | ||
| 43 | #include <net/ip.h> | ||
| 44 | #include <linux/spinlock.h> | ||
| 45 | #include <linux/rcupdate.h> | ||
| 46 | #include <linux/bitops.h> | ||
| 47 | #include <linux/mutex.h> | ||
| 48 | |||
| 49 | #include <linux/uaccess.h> | ||
| 50 | #include <asm/system.h> | ||
| 51 | |||
| 52 | static const struct proto_ops econet_ops; | ||
| 53 | static struct hlist_head econet_sklist; | ||
| 54 | static DEFINE_SPINLOCK(econet_lock); | ||
| 55 | static DEFINE_MUTEX(econet_mutex); | ||
| 56 | |||
| 57 | /* Since there are only 256 possible network numbers (or fewer, depends | ||
| 58 | how you count) it makes sense to use a simple lookup table. */ | ||
| 59 | static struct net_device *net2dev_map[256]; | ||
| 60 | |||
| 61 | #define EC_PORT_IP 0xd2 | ||
| 62 | |||
| 63 | #ifdef CONFIG_ECONET_AUNUDP | ||
| 64 | static DEFINE_SPINLOCK(aun_queue_lock); | ||
| 65 | static struct socket *udpsock; | ||
| 66 | #define AUN_PORT 0x8000 | ||
| 67 | |||
| 68 | struct aunhdr { | ||
| 69 | unsigned char code; /* AUN magic protocol byte */ | ||
| 70 | unsigned char port; | ||
| 71 | unsigned char cb; | ||
| 72 | unsigned char pad; | ||
| 73 | unsigned long handle; | ||
| 74 | }; | ||
| 75 | |||
| 76 | static unsigned long aun_seq; | ||
| 77 | |||
| 78 | /* Queue of packets waiting to be transmitted. */ | ||
| 79 | static struct sk_buff_head aun_queue; | ||
| 80 | static struct timer_list ab_cleanup_timer; | ||
| 81 | |||
| 82 | #endif /* CONFIG_ECONET_AUNUDP */ | ||
| 83 | |||
| 84 | /* Per-packet information */ | ||
| 85 | struct ec_cb { | ||
| 86 | struct sockaddr_ec sec; | ||
| 87 | unsigned long cookie; /* Supplied by user. */ | ||
| 88 | #ifdef CONFIG_ECONET_AUNUDP | ||
| 89 | int done; | ||
| 90 | unsigned long seq; /* Sequencing */ | ||
| 91 | unsigned long timeout; /* Timeout */ | ||
| 92 | unsigned long start; /* jiffies */ | ||
| 93 | #endif | ||
| 94 | #ifdef CONFIG_ECONET_NATIVE | ||
| 95 | void (*sent)(struct sk_buff *, int result); | ||
| 96 | #endif | ||
| 97 | }; | ||
| 98 | |||
| 99 | static void econet_remove_socket(struct hlist_head *list, struct sock *sk) | ||
| 100 | { | ||
| 101 | spin_lock_bh(&econet_lock); | ||
| 102 | sk_del_node_init(sk); | ||
| 103 | spin_unlock_bh(&econet_lock); | ||
| 104 | } | ||
| 105 | |||
| 106 | static void econet_insert_socket(struct hlist_head *list, struct sock *sk) | ||
| 107 | { | ||
| 108 | spin_lock_bh(&econet_lock); | ||
| 109 | sk_add_node(sk, list); | ||
| 110 | spin_unlock_bh(&econet_lock); | ||
| 111 | } | ||
| 112 | |||
| 113 | /* | ||
| 114 | * Pull a packet from our receive queue and hand it to the user. | ||
| 115 | * If necessary we block. | ||
| 116 | */ | ||
| 117 | |||
| 118 | static int econet_recvmsg(struct kiocb *iocb, struct socket *sock, | ||
| 119 | struct msghdr *msg, size_t len, int flags) | ||
| 120 | { | ||
| 121 | struct sock *sk = sock->sk; | ||
| 122 | struct sk_buff *skb; | ||
| 123 | size_t copied; | ||
| 124 | int err; | ||
| 125 | |||
| 126 | msg->msg_namelen = sizeof(struct sockaddr_ec); | ||
| 127 | |||
| 128 | mutex_lock(&econet_mutex); | ||
| 129 | |||
| 130 | /* | ||
| 131 | * Call the generic datagram receiver. This handles all sorts | ||
| 132 | * of horrible races and re-entrancy so we can forget about it | ||
| 133 | * in the protocol layers. | ||
| 134 | * | ||
| 135 | * Now it will return ENETDOWN, if device have just gone down, | ||
| 136 | * but then it will block. | ||
| 137 | */ | ||
| 138 | |||
| 139 | skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err); | ||
| 140 | |||
| 141 | /* | ||
| 142 | * An error occurred so return it. Because skb_recv_datagram() | ||
| 143 | * handles the blocking we don't see and worry about blocking | ||
| 144 | * retries. | ||
| 145 | */ | ||
| 146 | |||
| 147 | if (skb == NULL) | ||
| 148 | goto out; | ||
| 149 | |||
| 150 | /* | ||
| 151 | * You lose any data beyond the buffer you gave. If it worries a | ||
| 152 | * user program they can ask the device for its MTU anyway. | ||
| 153 | */ | ||
| 154 | |||
| 155 | copied = skb->len; | ||
| 156 | if (copied > len) { | ||
| 157 | copied = len; | ||
| 158 | msg->msg_flags |= MSG_TRUNC; | ||
| 159 | } | ||
| 160 | |||
| 161 | /* We can't use skb_copy_datagram here */ | ||
| 162 | err = memcpy_toiovec(msg->msg_iov, skb->data, copied); | ||
| 163 | if (err) | ||
| 164 | goto out_free; | ||
| 165 | sk->sk_stamp = skb->tstamp; | ||
| 166 | |||
| 167 | if (msg->msg_name) | ||
| 168 | memcpy(msg->msg_name, skb->cb, msg->msg_namelen); | ||
| 169 | |||
| 170 | /* | ||
| 171 | * Free or return the buffer as appropriate. Again this | ||
| 172 | * hides all the races and re-entrancy issues from us. | ||
| 173 | */ | ||
| 174 | err = copied; | ||
| 175 | |||
| 176 | out_free: | ||
| 177 | skb_free_datagram(sk, skb); | ||
| 178 | out: | ||
| 179 | mutex_unlock(&econet_mutex); | ||
