* Copyright (C) Terry Dawson VK2KTJ (terry@animats.net)
* Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi)
*/
+
#include <linux/config.h>
+#include <linux/capability.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <net/rose.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
#include <net/ip.h>
#include <net/arp.h>
int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC;
int sysctl_rose_window_size = ROSE_DEFAULT_WINDOW_SIZE;
-HLIST_HEAD(rose_list);
-spinlock_t rose_list_lock = SPIN_LOCK_UNLOCKED;
+static HLIST_HEAD(rose_list);
+static DEFINE_SPINLOCK(rose_list_lock);
static struct proto_ops rose_proto_ops;
return 0;
}
-static struct sock *rose_alloc_sock(void)
-{
- rose_cb *rose;
- struct sock *sk = sk_alloc(PF_ROSE, GFP_ATOMIC, 1, NULL);
-
- if (!sk)
- goto out;
-
- rose = sk->sk_protinfo = kmalloc(sizeof(*rose), GFP_ATOMIC);
- if (!rose)
- goto frees;
-
- memset(rose, 0x00, sizeof(*rose));
- rose->sk = sk;
-out:
- return sk;
-frees:
- sk_free(sk);
- sk = NULL;
- goto out;
-}
-
/*
* Socket removal during an interrupt is now safe.
*/
spin_lock_bh(&rose_list_lock);
sk_for_each(s, node, &rose_list) {
- rose_cb *rose = rose_sk(s);
+ struct rose_sock *rose = rose_sk(s);
if (rose->neighbour == neigh) {
rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
spin_lock_bh(&rose_list_lock);
sk_for_each(s, node, &rose_list) {
- rose_cb *rose = rose_sk(s);
+ struct rose_sock *rose = rose_sk(s);
if (rose->device == dev) {
rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);
spin_lock_bh(&rose_list_lock);
sk_for_each(s, node, &rose_list) {
- rose_cb *rose = rose_sk(s);
+ struct rose_sock *rose = rose_sk(s);
if (!rosecmp(&rose->source_addr, addr) &&
!ax25cmp(&rose->source_call, call) &&
}
sk_for_each(s, node, &rose_list) {
- rose_cb *rose = rose_sk(s);
+ struct rose_sock *rose = rose_sk(s);
if (!rosecmp(&rose->source_addr, addr) &&
!ax25cmp(&rose->source_call, &null_ax25_address) &&
spin_lock_bh(&rose_list_lock);
sk_for_each(s, node, &rose_list) {
- rose_cb *rose = rose_sk(s);
+ struct rose_sock *rose = rose_sk(s);
if (rose->lci == lci && rose->neighbour == neigh)
goto found;
*/
static int rose_setsockopt(struct socket *sock, int level, int optname,
- char *optval, int optlen)
+ char __user *optval, int optlen)
{
struct sock *sk = sock->sk;
- rose_cb *rose = rose_sk(sk);
+ struct rose_sock *rose = rose_sk(sk);
int opt;
if (level != SOL_ROSE)
if (optlen < sizeof(int))
return -EINVAL;
- if (get_user(opt, (int *)optval))
+ if (get_user(opt, (int __user *)optval))
return -EFAULT;
switch (optname) {
}
static int rose_getsockopt(struct socket *sock, int level, int optname,
- char *optval, int *optlen)
+ char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
- rose_cb *rose = rose_sk(sk);
+ struct rose_sock *rose = rose_sk(sk);
int val = 0;
int len;
struct sock *sk = sock->sk;
if (sk->sk_state != TCP_LISTEN) {
- rose_cb *rose = rose_sk(sk);
+ struct rose_sock *rose = rose_sk(sk);
rose->dest_ndigis = 0;
memset(&rose->dest_addr, 0, ROSE_ADDR_LEN);
return -EOPNOTSUPP;
}
+static struct proto rose_proto = {
+ .name = "ROSE",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct rose_sock),
+};
+
static int rose_create(struct socket *sock, int protocol)
{
struct sock *sk;
- rose_cb *rose;
+ struct rose_sock *rose;
if (sock->type != SOCK_SEQPACKET || protocol != 0)
return -ESOCKTNOSUPPORT;
- if ((sk = rose_alloc_sock()) == NULL)
+ if ((sk = sk_alloc(PF_ROSE, GFP_ATOMIC, &rose_proto, 1)) == NULL)
return -ENOMEM;
rose = rose_sk(sk);
sock_init_data(sock, sk);
- sk_set_owner(sk, THIS_MODULE);
skb_queue_head_init(&rose->ack_queue);
#ifdef M_BIT
static struct sock *rose_make_new(struct sock *osk)
{
struct sock *sk;
- rose_cb *rose, *orose;
+ struct rose_sock *rose, *orose;
if (osk->sk_type != SOCK_SEQPACKET)
return NULL;
- if ((sk = rose_alloc_sock()) == NULL)
+ if ((sk = sk_alloc(PF_ROSE, GFP_ATOMIC, &rose_proto, 1)) == NULL)
return NULL;
rose = rose_sk(sk);
sock_init_data(NULL, sk);
- sk_set_owner(sk, THIS_MODULE);
skb_queue_head_init(&rose->ack_queue);
#ifdef M_BIT
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);
init_timer(&rose->timer);
init_timer(&rose->idletimer);
static int rose_release(struct socket *sock)
{
struct sock *sk = sock->sk;
- rose_cb *rose;
+ struct rose_sock *rose;
if (sk == NULL) return 0;
static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sock *sk = sock->sk;
- rose_cb *rose = rose_sk(sk);
+ struct rose_sock *rose = rose_sk(sk);
struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
struct net_device *dev;
- ax25_address *user, *source;
+ ax25_address *source;
+ ax25_uid_assoc *user;
int n;
- if (!sk->sk_zapped)
+ if (!sock_flag(sk, SOCK_ZAPPED))
return -EINVAL;
if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose))
source = &addr->srose_call;
- if ((user = ax25_findbyuid(current->euid)) == NULL) {
+ user = ax25_findbyuid(current->euid);
+ if (user) {
+ rose->source_call = user->call;
+ ax25_uid_put(user);
+ } else {
if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE))
return -EACCES;
- user = source;
+ rose->source_call = *source;
}
rose->source_addr = addr->srose_addr;
- rose->source_call = *user;
rose->device = dev;
rose->source_ndigis = addr->srose_ndigis;
rose_insert_socket(sk);
- sk->sk_zapped = 0;
+ sock_reset_flag(sk, SOCK_ZAPPED);
SOCK_DEBUG(sk, "ROSE: socket is bound\n");
return 0;
}
static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
{
struct sock *sk = sock->sk;
- rose_cb *rose = rose_sk(sk);
+ struct rose_sock *rose = rose_sk(sk);
struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
unsigned char cause, diagnostic;
- ax25_address *user;
struct net_device *dev;
+ ax25_uid_assoc *user;
int n;
if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
if (!rose->lci)
return -ENETUNREACH;
- 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 = rose_dev_first()) == NULL)
return -ENETUNREACH;
- if ((user = ax25_findbyuid(current->euid)) == NULL)
+ user = ax25_findbyuid(current->euid);
+ if (!user)
return -EINVAL;
memcpy(&rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN);
- rose->source_call = *user;
+ rose->source_call = user->call;
rose->device = dev;
+ ax25_uid_put(user);
rose_insert_socket(sk); /* Finish the bind */
}
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_rose *srose = (struct full_sockaddr_rose *)uaddr;
struct sock *sk = sock->sk;
- rose_cb *rose = rose_sk(sk);
+ struct rose_sock *rose = rose_sk(sk);
int n;
if (peer != 0) {
{
struct sock *sk;
struct sock *make;
- rose_cb *make_rose;
+ struct rose_sock *make_rose;
struct rose_facilities_struct facilities;
int n, len;
/*
* We can't accept the Call Request.
*/
- if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog ||
+ if (sk == NULL || sk_acceptq_is_full(sk) ||
(make = rose_make_new(sk)) == NULL) {
rose_transmit_clear_request(neigh, lci, ROSE_NETWORK_CONGESTION, 120);
return 0;
make_rose->vr = 0;
make_rose->vl = 0;
sk->sk_ack_backlog++;
- make->sk_pair = sk;
rose_insert_socket(make);
struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
- rose_cb *rose = rose_sk(sk);
+ struct rose_sock *rose = rose_sk(sk);
struct sockaddr_rose *usrose = (struct sockaddr_rose *)msg->msg_name;
int err;
struct full_sockaddr_rose srose;
unsigned char *asmptr;
int n, size, qbit = 0;
- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR))
+ if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT))
return -EINVAL;
- if (sk->sk_zapped)
+ if (sock_flag(sk, SOCK_ZAPPED))
return -EADDRNOTAVAIL;
if (sk->sk_shutdown & SEND_SHUTDOWN) {
struct msghdr *msg, size_t size, int flags)
{
struct sock *sk = sock->sk;
- rose_cb *rose = rose_sk(sk);
+ struct rose_sock *rose = rose_sk(sk);
struct sockaddr_rose *srose = (struct sockaddr_rose *)msg->msg_name;
size_t copied;
unsigned char *asmptr;
static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
- rose_cb *rose = rose_sk(sk);
+ struct rose_sock *rose = rose_sk(sk);
+ void __user *argp = (void __user *)arg;
switch (cmd) {
case TIOCOUTQ: {
amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
if (amount < 0)
amount = 0;
- return put_user(amount, (unsigned int *)arg);
+ return put_user(amount, (unsigned int __user *) argp);
}
case TIOCINQ: {
/* 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;
- return put_user(amount, (unsigned int *)arg);
+ return put_user(amount, (unsigned int __user *) argp);
}
case SIOCGSTAMP:
- if (sk != NULL)
- return sock_get_timestamp(sk, (struct timeval *)arg);
- return -EINVAL;
+ return sock_get_timestamp(sk, (struct timeval __user *) argp);
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCRSCLRRT:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- return rose_rt_ioctl(cmd, (void *)arg);
+ return rose_rt_ioctl(cmd, argp);
case SIOCRSGCAUSE: {
struct rose_cause_struct rose_cause;
rose_cause.cause = rose->cause;
rose_cause.diagnostic = rose->diagnostic;
- return copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0;
+ return copy_to_user(argp, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0;
}
case SIOCRSSCAUSE: {
struct rose_cause_struct rose_cause;
- if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct)))
+ if (copy_from_user(&rose_cause, argp, sizeof(struct rose_cause_struct)))
return -EFAULT;
rose->cause = rose_cause.cause;
rose->diagnostic = rose_cause.diagnostic;
if (!capable(CAP_NET_ADMIN)) return -EPERM;
if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
ax25_listen_release(&rose_callsign, NULL);
- if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address)))
+ if (copy_from_user(&rose_callsign, argp, sizeof(ax25_address)))
return -EFAULT;
if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
ax25_listen_register(&rose_callsign, NULL);
return 0;
case SIOCRSGL2CALL:
- return copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0;
+ return copy_to_user(argp, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0;
case SIOCRSACCEPT:
if (rose->state == ROSE_STATE_5) {
return 0;
default:
- return dev_ioctl(cmd, (void *)arg);
+ return -ENOIOCTLCMD;
}
return 0;
static int rose_info_show(struct seq_file *seq, void *v)
{
+ char buf[11];
+
if (v == SEQ_START_TOKEN)
seq_puts(seq,
"dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n");
else {
struct sock *s = v;
- rose_cb *rose = rose_sk(s);
+ struct rose_sock *rose = rose_sk(s);
const char *devname, *callsign;
const struct net_device *dev = rose->device;
seq_printf(seq, "%-10s %-9s ",
rose2asc(&rose->dest_addr),
- ax2asc(&rose->dest_call));
+ ax2asc(buf, &rose->dest_call));
if (ax25cmp(&rose->source_call, &null_ax25_address) == 0)
callsign = "??????-?";
else
- callsign = ax2asc(&rose->source_call);
+ callsign = ax2asc(buf, &rose->source_call);
seq_printf(seq,
"%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
static int __init rose_proto_init(void)
{
int i;
-
- rose_callsign = null_ax25_address;
+ int rc;
if (rose_ndevs > 0x7FFFFFFF/sizeof(struct net_device *)) {
printk(KERN_ERR "ROSE: rose_proto_init - rose_ndevs parameter to large\n");
- return -1;
+ rc = -EINVAL;
+ goto out;
}
+ rc = proto_register(&rose_proto, 0);
+ if (rc != 0)
+ goto out;
+
+ rose_callsign = null_ax25_address;
+
dev_rose = kmalloc(rose_ndevs * sizeof(struct net_device *), GFP_KERNEL);
if (dev_rose == NULL) {
printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate device structure\n");
- return -1;
+ rc = -ENOMEM;
+ goto out_proto_unregister;
}
memset(dev_rose, 0x00, rose_ndevs * sizeof(struct net_device*));
name, rose_setup);
if (!dev) {
printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate memory\n");
+ rc = -ENOMEM;
goto fail;
}
- if (register_netdev(dev)) {
- printk(KERN_ERR "ROSE: netdevice regeistration failed\n");
+ rc = register_netdev(dev);
+ if (rc) {
+ printk(KERN_ERR "ROSE: netdevice registration failed\n");
free_netdev(dev);
goto fail;
}
proc_net_fops_create("rose_neigh", S_IRUGO, &rose_neigh_fops);
proc_net_fops_create("rose_nodes", S_IRUGO, &rose_nodes_fops);
proc_net_fops_create("rose_routes", S_IRUGO, &rose_routes_fops);
-
- return 0;
+out:
+ return rc;
fail:
while (--i >= 0) {
unregister_netdev(dev_rose[i]);
free_netdev(dev_rose[i]);
}
kfree(dev_rose);
- return -ENOMEM;
+out_proto_unregister:
+ proto_unregister(&rose_proto);
+ goto out;
}
module_init(rose_proto_init);
-MODULE_PARM(rose_ndevs, "i");
+module_param(rose_ndevs, int, 0);
MODULE_PARM_DESC(rose_ndevs, "number of ROSE devices");
MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
}
kfree(dev_rose);
+ proto_unregister(&rose_proto);
}
module_exit(rose_exit);