*/
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <net/ip.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
#include <net/arp.h>
#include <linux/init.h>
-int nr_ndevs = 4;
+static int nr_ndevs = 4;
int sysctl_netrom_default_path_quality = NR_DEFAULT_QUAL;
int sysctl_netrom_obsolescence_count_initialiser = NR_DEFAULT_OBS;
int sysctl_netrom_transport_no_activity_timeout = NR_DEFAULT_IDLE;
int sysctl_netrom_routing_control = NR_DEFAULT_ROUTING;
int sysctl_netrom_link_fails_count = NR_DEFAULT_FAILS;
+int sysctl_netrom_reset_circuit = NR_DEFAULT_RESET;
static unsigned short circuit = 0x101;
static HLIST_HEAD(nr_list);
-static spinlock_t nr_list_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(nr_list_lock);
-static struct proto_ops nr_proto_ops;
-void nr_init_timers(struct sock *sk);
-
-static struct sock *nr_alloc_sock(void)
-{
- nr_cb *nr;
- struct sock *sk = sk_alloc(PF_NETROM, GFP_ATOMIC, 1, NULL);
-
- if (!sk)
- goto out;
-
- nr = sk->sk_protinfo = kmalloc(sizeof(*nr), GFP_ATOMIC);
- if (!nr)
- goto frees;
-
- memset(nr, 0x00, sizeof(*nr));
- nr->sk = sk;
-out:
- return sk;
-frees:
- sk_free(sk);
- sk = NULL;
- goto out;
-}
+static const struct proto_ops nr_proto_ops;
/*
* Socket removal during an interrupt is now safe.
spin_lock_bh(&nr_list_lock);
sk_for_each(s, node, &nr_list) {
- nr_cb *nr = nr_sk(s);
+ struct nr_sock *nr = nr_sk(s);
if (nr->my_index == index && nr->my_id == id) {
bh_lock_sock(s);
spin_lock_bh(&nr_list_lock);
sk_for_each(s, node, &nr_list) {
- nr_cb *nr = nr_sk(s);
+ struct nr_sock *nr = nr_sk(s);
if (nr->your_index == index && nr->your_id == id &&
!ax25cmp(&nr->dest_addr, dest)) {
char __user *optval, int optlen)
{
struct sock *sk = sock->sk;
- nr_cb *nr = nr_sk(sk);
+ struct nr_sock *nr = nr_sk(sk);
int opt;
if (level != SOL_NETROM)
char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
- nr_cb *nr = nr_sk(sk);
+ struct nr_sock *nr = nr_sk(sk);
int val = 0;
int len;
return -EOPNOTSUPP;
}
+static struct proto nr_proto = {
+ .name = "NETROM",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct nr_sock),
+};
+
static int nr_create(struct socket *sock, int protocol)
{
struct sock *sk;
- nr_cb *nr;
+ struct nr_sock *nr;
if (sock->type != SOCK_SEQPACKET || protocol != 0)
return -ESOCKTNOSUPPORT;
- if ((sk = nr_alloc_sock()) == NULL)
+ if ((sk = sk_alloc(PF_NETROM, GFP_ATOMIC, &nr_proto, 1)) == NULL)
return -ENOMEM;
nr = nr_sk(sk);
sock_init_data(sock, sk);
- sk_set_owner(sk, THIS_MODULE);
sock->ops = &nr_proto_ops;
sk->sk_protocol = protocol;
nr_init_timers(sk);
- nr->t1 = sysctl_netrom_transport_timeout;
- nr->t2 = sysctl_netrom_transport_acknowledge_delay;
- nr->n2 = sysctl_netrom_transport_maximum_tries;
- nr->t4 = sysctl_netrom_transport_busy_delay;
- nr->idle = sysctl_netrom_transport_no_activity_timeout;
+ nr->t1 =
+ msecs_to_jiffies(sysctl_netrom_transport_timeout);
+ nr->t2 =
+ msecs_to_jiffies(sysctl_netrom_transport_acknowledge_delay);
+ nr->n2 =
+ msecs_to_jiffies(sysctl_netrom_transport_maximum_tries);
+ nr->t4 =
+ msecs_to_jiffies(sysctl_netrom_transport_busy_delay);
+ nr->idle =
+ msecs_to_jiffies(sysctl_netrom_transport_no_activity_timeout);
nr->window = sysctl_netrom_transport_requested_window_size;
nr->bpqext = 1;
static struct sock *nr_make_new(struct sock *osk)
{
struct sock *sk;
- nr_cb *nr, *onr;
+ struct nr_sock *nr, *onr;
if (osk->sk_type != SOCK_SEQPACKET)
return NULL;
- if ((sk = nr_alloc_sock()) == NULL)
+ if ((sk = sk_alloc(PF_NETROM, GFP_ATOMIC, osk->sk_prot, 1)) == NULL)
return NULL;
nr = nr_sk(sk);
sock_init_data(NULL, sk);
- sk_set_owner(sk, THIS_MODULE);
sk->sk_type = osk->sk_type;
sk->sk_socket = osk->sk_socket;
sk->sk_protocol = osk->sk_protocol;
sk->sk_rcvbuf = osk->sk_rcvbuf;
sk->sk_sndbuf = osk->sk_sndbuf;
- sk->sk_debug = osk->sk_debug;
sk->sk_state = TCP_ESTABLISHED;
sk->sk_sleep = osk->sk_sleep;
- sk->sk_zapped = osk->sk_zapped;
+ sock_copy_flags(sk, osk);
skb_queue_head_init(&nr->ack_queue);
skb_queue_head_init(&nr->reseq_queue);
static int nr_release(struct socket *sock)
{
struct sock *sk = sock->sk;
- nr_cb *nr;
+ struct nr_sock *nr;
if (sk == NULL) return 0;
static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sock *sk = sock->sk;
- nr_cb *nr = nr_sk(sk);
+ struct nr_sock *nr = nr_sk(sk);
struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
struct net_device *dev;
- ax25_address *user, *source;
+ ax25_uid_assoc *user;
+ ax25_address *source;
lock_sock(sk);
- if (!sk->sk_zapped) {
+ if (!sock_flag(sk, SOCK_ZAPPED)) {
release_sock(sk);
return -EINVAL;
}
} else {
source = &addr->fsa_ax25.sax25_call;
- if ((user = ax25_findbyuid(current->euid)) == NULL) {
+ user = ax25_findbyuid(current->euid);
+ if (user) {
+ nr->user_addr = user->call;
+ ax25_uid_put(user);
+ } else {
if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
release_sock(sk);
dev_put(dev);
return -EPERM;
}
- user = source;
+ nr->user_addr = *source;
}
- nr->user_addr = *user;
nr->source_addr = *source;
}
nr->device = dev;
nr_insert_socket(sk);
- sk->sk_zapped = 0;
+ sock_reset_flag(sk, SOCK_ZAPPED);
dev_put(dev);
release_sock(sk);
SOCK_DEBUG(sk, "NET/ROM: socket is bound\n");
int addr_len, int flags)
{
struct sock *sk = sock->sk;
- nr_cb *nr = nr_sk(sk);
+ struct nr_sock *nr = nr_sk(sk);
struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr;
- ax25_address *user, *source = NULL;
+ ax25_address *source = NULL;
+ ax25_uid_assoc *user;
struct net_device *dev;
lock_sock(sk);
release_sock(sk);
return -EINVAL;
}
- if (sk->sk_zapped) { /* Must bind first - autobinding in this may or may not work */
- sk->sk_zapped = 0;
+ if (sock_flag(sk, SOCK_ZAPPED)) { /* Must bind first - autobinding in this may or may not work */
+ sock_reset_flag(sk, SOCK_ZAPPED);
if ((dev = nr_dev_first()) == NULL) {
release_sock(sk);
}
source = (ax25_address *)dev->dev_addr;
- if ((user = ax25_findbyuid(current->euid)) == NULL) {
+ user = ax25_findbyuid(current->euid);
+ if (user) {
+ nr->user_addr = user->call;
+ ax25_uid_put(user);
+ } else {
if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) {
dev_put(dev);
release_sock(sk);
return -EPERM;
}
- user = source;
+ nr->user_addr = *source;
}
- nr->user_addr = *user;
nr->source_addr = *source;
nr->device = dev;
remove_wait_queue(sk->sk_sleep, &wait);
newsk = skb->sk;
- newsk->sk_pair = NULL;
newsk->sk_socket = newsock;
newsk->sk_sleep = &newsock->wait;
{
struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr;
struct sock *sk = sock->sk;
- nr_cb *nr = nr_sk(sk);
+ struct nr_sock *nr = nr_sk(sk);
lock_sock(sk);
if (peer != 0) {
{
struct sock *sk;
struct sock *make;
- nr_cb *nr_make;
+ struct nr_sock *nr_make;
ax25_address *src, *dest, *user;
unsigned short circuit_index, circuit_id;
unsigned short peer_circuit_index, peer_circuit_id;
frametype = skb->data[19] & 0x0F;
flags = skb->data[19] & 0xF0;
-#ifdef CONFIG_INET
/*
* Check for an incoming IP over NET/ROM frame.
*/
- if (frametype == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
+ if (frametype == NR_PROTOEXT &&
+ circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
skb->h.raw = skb->data;
return nr_rx_ip(skb, dev);
}
-#endif
/*
* Find an existing socket connection, based on circuit ID, if it's
if (frametype != NR_CONNREQ) {
/*
* Here it would be nice to be able to send a reset but
- * NET/ROM doesn't have one. The following hack would
- * have been a way to extend the protocol but apparently
- * it kills BPQ boxes... :-(
- */
-#if 0
- /*
- * Never reply to a CONNACK/CHOKE.
+ * NET/ROM doesn't have one. We've tried to extend the protocol
+ * by sending NR_CONNACK | NR_CHOKE_FLAGS replies but that
+ * apparently kills BPQ boxes... :-(
+ * So now we try to follow the established behaviour of
+ * G8PZT's Xrouter which is sending packets with command type 7
+ * as an extension of the protocol.
*/
- if (frametype != NR_CONNACK || flags != NR_CHOKE_FLAG)
- nr_transmit_refusal(skb, 1);
-#endif
+ if (sysctl_netrom_reset_circuit &&
+ (frametype != NR_RESET || flags != 0))
+ nr_transmit_reset(skb, 1);
+
return 0;
}
user = (ax25_address *)(skb->data + 21);
- if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog ||
+ if (sk == NULL || sk_acceptq_is_full(sk) ||
(make = nr_make_new(sk)) == NULL) {
nr_transmit_refusal(skb, 0);
if (sk)
nr_make->vl = 0;
nr_make->state = NR_STATE_3;
sk->sk_ack_backlog++;
- make->sk_pair = sk;
nr_insert_socket(make);
struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
- nr_cb *nr = nr_sk(sk);
+ struct nr_sock *nr = nr_sk(sk);
struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
int err;
struct sockaddr_ax25 sax;
unsigned char *asmptr;
int size;
- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR))
+ if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT))
return -EINVAL;
lock_sock(sk);
- if (sk->sk_zapped) {
+ if (sock_flag(sk, SOCK_ZAPPED)) {
err = -EADDRNOTAVAIL;
goto out;
}
static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
+ void __user *argp = (void __user *)arg;
int ret;
- lock_sock(sk);
switch (cmd) {
case TIOCOUTQ: {
long amount;
+
+ lock_sock(sk);
amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
if (amount < 0)
amount = 0;
release_sock(sk);
- return put_user(amount, (int *)arg);
+ return put_user(amount, (int __user *)argp);
}
case TIOCINQ: {
struct sk_buff *skb;
long amount = 0L;
+
+ lock_sock(sk);
/* These two are safe on a single CPU system as only user tasks fiddle here */
if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
amount = skb->len;
release_sock(sk);
- return put_user(amount, (int *)arg);
+ return put_user(amount, (int __user *)argp);
}
case SIOCGSTAMP:
- ret = -EINVAL;
- if (sk != NULL)
- ret = sock_get_timestamp(sk, (struct timeval __user *)arg);
+ lock_sock(sk);
+ ret = sock_get_timestamp(sk, argp);
release_sock(sk);
return ret;
case SIOCSIFNETMASK:
case SIOCGIFMETRIC:
case SIOCSIFMETRIC:
- release_sock(sk);
return -EINVAL;
case SIOCADDRT:
case SIOCDELRT:
case SIOCNRDECOBS:
- release_sock(sk);
if (!capable(CAP_NET_ADMIN)) return -EPERM;
- return nr_rt_ioctl(cmd, (void *)arg);
+ return nr_rt_ioctl(cmd, argp);
default:
- release_sock(sk);
- return dev_ioctl(cmd, (void __user *)arg);
+ return -ENOIOCTLCMD;
}
- release_sock(sk);
return 0;
}
{
struct sock *s = v;
struct net_device *dev;
- nr_cb *nr;
+ struct nr_sock *nr;
const char *devname;
+ char buf[11];
if (v == SEQ_START_TOKEN)
seq_puts(seq,
else
devname = dev->name;
- seq_printf(seq, "%-9s ", ax2asc(&nr->user_addr));
- seq_printf(seq, "%-9s ", ax2asc(&nr->dest_addr));
+ seq_printf(seq, "%-9s ", ax2asc(buf, &nr->user_addr));
+ seq_printf(seq, "%-9s ", ax2asc(buf, &nr->dest_addr));
seq_printf(seq,
"%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d %ld\n",
- ax2asc(&nr->source_addr),
+ ax2asc(buf, &nr->source_addr),
devname,
nr->my_index,
nr->my_id,
.owner = THIS_MODULE,
};
-static struct proto_ops nr_proto_ops = {
+static const struct proto_ops nr_proto_ops = {
.family = PF_NETROM,
.owner = THIS_MODULE,
.release = nr_release,
static struct net_device **dev_nr;
-static char banner[] __initdata = KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.4\n";
-
static int __init nr_proto_init(void)
{
int i;
+ int rc = proto_register(&nr_proto, 0);
+
+ if (rc != 0)
+ goto out;
if (nr_ndevs > 0x7fffffff/sizeof(struct net_device *)) {
printk(KERN_ERR "NET/ROM: nr_proto_init - nr_ndevs parameter to large\n");
struct net_device *dev;
sprintf(name, "nr%d", i);
- dev = alloc_netdev(sizeof(struct net_device_stats), name,
- nr_setup);
+ dev = alloc_netdev(sizeof(struct nr_private), name, nr_setup);
if (!dev) {
printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n");
goto fail;
}
register_netdevice_notifier(&nr_dev_notifier);
- printk(banner);
ax25_protocol_register(AX25_P_NETROM, nr_route_frame);
ax25_linkfail_register(nr_link_failed);
proc_net_fops_create("nr", S_IRUGO, &nr_info_fops);
proc_net_fops_create("nr_neigh", S_IRUGO, &nr_neigh_fops);
proc_net_fops_create("nr_nodes", S_IRUGO, &nr_nodes_fops);
- return 0;
-
- fail:
+out:
+ return rc;
+fail:
while (--i >= 0) {
unregister_netdev(dev_nr[i]);
free_netdev(dev_nr[i]);
}
kfree(dev_nr);
- return -1;
+ proto_unregister(&nr_proto);
+ rc = -1;
+ goto out;
}
module_init(nr_proto_init);
-
-MODULE_PARM(nr_ndevs, "i");
+module_param(nr_ndevs, int, 0);
MODULE_PARM_DESC(nr_ndevs, "number of NET/ROM devices");
MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
}
kfree(dev_nr);
+ proto_unregister(&nr_proto);
}
module_exit(nr_exit);