/*
* An implementation of the Acorn Econet and AUN protocols.
* Philip Blundell <philb@gnu.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/in.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/route.h>
#include <linux/inet.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <linux/skbuff.h>
#include <linux/udp.h>
#include <net/sock.h>
#include <net/inet_common.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/if_ec.h>
#include <net/udp.h>
#include <net/ip.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/system.h>
static const struct proto_ops econet_ops;
static struct hlist_head econet_sklist;
static DEFINE_RWLOCK(econet_lock);
static DEFINE_MUTEX(econet_mutex);
/* Since there are only 256 possible network numbers (or fewer, depends
how you count) it makes sense to use a simple lookup table. */
static struct net_device *net2dev_map[256];
#define EC_PORT_IP 0xd2
#ifdef CONFIG_ECONET_AUNUDP
static DEFINE_SPINLOCK(aun_queue_lock);
static struct socket *udpsock;
#define AUN_PORT 0x8000
struct aunhdr
{
unsigned char code; /* AUN magic protocol byte */
unsigned char port;
unsigned char cb;
unsigned char pad;
unsigned long handle;
};
static unsigned long aun_seq;
/* Queue of packets waiting to be transmitted. */
static struct sk_buff_head aun_queue;
static struct timer_list ab_cleanup_timer;
#endif /* CONFIG_ECONET_AUNUDP */
/* Per-packet information */
struct ec_cb
{
struct sockaddr_ec sec;
unsigned long cookie; /* Supplied by user. */
#ifdef CONFIG_ECONET_AUNUDP
int done;
unsigned long seq; /* Sequencing */
unsigned long timeout; /* Timeout */
unsigned long start; /* jiffies */
#endif
#ifdef CONFIG_ECONET_NATIVE
void (*sent)(struct sk_buff *, int result);
#endif
};
static void econet_remove_socket(struct hlist_head *list, struct sock *sk)
{
write_lock_bh(&econet_lock);
sk_del_node_init(sk);
write_unlock_bh(&econet_lock);
}
static void econet_insert_socket(struct hlist_head *list, struct sock *sk)
{
write_lock_bh(&econet_lock);
sk_add_node(sk, list);
write_unlock_bh(&econet_lock);
}
/*
* Pull a packet from our receive queue and hand it to the user.
* If necessary we block.
*/
static int econet_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t len, int flags)
{
struct sock *sk = sock->sk;
struct sk_buff *skb;
size_t copied;
int err;
msg->msg_namelen = sizeof(struct sockaddr_ec);
mutex_lock(&econet_mutex);
/*
* Call the generic datagram receiver. This handles all sorts
* of horrible races and re-entrancy so we can forget about it
* in the protocol layers.
*
* Now it will return ENETDOWN, if device have just gone down,
* but then it will block.
*/
skb=skb_recv_datagram(sk,flags,flags&MSG_DONTWAIT,&err);
/*
* An error occurred so return it. Because skb_recv_datagram()
* handles the blocking we don't see and worry about blocking
* retries.
*/
if(skb