Release 4.11 net/ax25/af_ax25.c
/*
* 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.
*
* Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
* Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
* Copyright (C) Hans Alblas PE1AYX (hans@esrac.ele.tue.nl)
* Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
*/
#include <linux/capability.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched/signal.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/slab.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <linux/uaccess.h>
#include <linux/fcntl.h>
#include <linux/termios.h> /* For TIOCINQ/OUTQ */
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/sysctl.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <net/net_namespace.h>
#include <net/tcp_states.h>
#include <net/ip.h>
#include <net/arp.h>
HLIST_HEAD(ax25_list);
DEFINE_SPINLOCK(ax25_list_lock);
static const struct proto_ops ax25_proto_ops;
static void ax25_free_sock(struct sock *sk)
{
ax25_cb_put(sk_to_ax25(sk));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 15 | 78.95% | 1 | 25.00% |
David S. Miller | 3 | 15.79% | 2 | 50.00% |
Jeroen Vreeken | 1 | 5.26% | 1 | 25.00% |
Total | 19 | 100.00% | 4 | 100.00% |
/*
* Socket removal during an interrupt is now safe.
*/
static void ax25_cb_del(ax25_cb *ax25)
{
if (!hlist_unhashed(&ax25->ax25_node)) {
spin_lock_bh(&ax25_list_lock);
hlist_del_init(&ax25->ax25_node);
spin_unlock_bh(&ax25_list_lock);
ax25_cb_put(ax25);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 26 | 54.17% | 3 | 50.00% |
Jeroen Vreeken | 17 | 35.42% | 1 | 16.67% |
Ralf Bächle | 5 | 10.42% | 2 | 33.33% |
Total | 48 | 100.00% | 6 | 100.00% |
/*
* Kill all bound sockets on a dropped device.
*/
static void ax25_kill_by_device(struct net_device *dev)
{
ax25_dev *ax25_dev;
ax25_cb *s;
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
return;
spin_lock_bh(&ax25_list_lock);
again:
ax25_for_each(s, &ax25_list) {
if (s->ax25_dev == ax25_dev) {
s->ax25_dev = NULL;
spin_unlock_bh(&ax25_list_lock);
ax25_disconnect(s, ENETUNREACH);
spin_lock_bh(&ax25_list_lock);
/* The entry could have been deleted from the
* list meanwhile and thus the next pointer is
* no longer valid. Play it safe and restart
* the scan. Forward progress is ensured
* because we set s->ax25_dev to NULL and we
* are never passed a NULL 'dev' argument.
*/
goto again;
}
}
spin_unlock_bh(&ax25_list_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 58 | 61.70% | 4 | 50.00% |
Jarek Poplawski | 18 | 19.15% | 1 | 12.50% |
Ralf Bächle | 12 | 12.77% | 2 | 25.00% |
Jeroen Vreeken | 6 | 6.38% | 1 | 12.50% |
Total | 94 | 100.00% | 8 | 100.00% |
/*
* Handle device status changes.
*/
static int ax25_device_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
/* Reject non AX.25 devices */
if (dev->type != ARPHRD_AX25)
return NOTIFY_DONE;
switch (event) {
case NETDEV_UP:
ax25_dev_device_up(dev);
break;
case NETDEV_DOWN:
ax25_kill_by_device(dev);
ax25_rt_device_down(dev);
ax25_dev_device_down(dev);
break;
default:
break;
}
return NOTIFY_DONE;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 77 | 79.38% | 7 | 63.64% |
Eric W. Biedermann | 9 | 9.28% | 1 | 9.09% |
Hideaki Yoshifuji / 吉藤英明 | 8 | 8.25% | 2 | 18.18% |
Jiri Pirko | 3 | 3.09% | 1 | 9.09% |
Total | 97 | 100.00% | 11 | 100.00% |
/*
* Add a socket to the bound sockets list.
*/
void ax25_cb_add(ax25_cb *ax25)
{
spin_lock_bh(&ax25_list_lock);
ax25_cb_hold(ax25);
hlist_add_head(&ax25->ax25_node, &ax25_list);
spin_unlock_bh(&ax25_list_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 18 | 48.65% | 4 | 57.14% |
Jeroen Vreeken | 13 | 35.14% | 1 | 14.29% |
Ralf Bächle | 6 | 16.22% | 2 | 28.57% |
Total | 37 | 100.00% | 7 | 100.00% |
/*
* Find a socket that wants to accept the SABM we have just
* received.
*/
struct sock *ax25_find_listener(ax25_address *addr, int digi,
struct net_device *dev, int type)
{
ax25_cb *s;
spin_lock(&ax25_list_lock);
ax25_for_each(s, &ax25_list) {
if ((s->iamdigi && !digi) || (!s->iamdigi && digi))
continue;
if (s->sk && !ax25cmp(&s->source_addr, addr) &&
s->sk->sk_type == type && s->sk->sk_state == TCP_LISTEN) {
/* If device is null we match any device */
if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) {
sock_hold(s->sk);
spin_unlock(&ax25_list_lock);
return s->sk;
}
}
}
spin_unlock(&ax25_list_lock);
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 117 | 82.39% | 9 | 69.23% |
Jeroen Vreeken | 13 | 9.15% | 1 | 7.69% |
Ralf Bächle | 9 | 6.34% | 2 | 15.38% |
Arnaldo Carvalho de Melo | 3 | 2.11% | 1 | 7.69% |
Total | 142 | 100.00% | 13 | 100.00% |
/*
* Find an AX.25 socket given both ends.
*/
struct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr,
int type)
{
struct sock *sk = NULL;
ax25_cb *s;
spin_lock(&ax25_list_lock);
ax25_for_each(s, &ax25_list) {
if (s->sk && !ax25cmp(&s->source_addr, my_addr) &&
!ax25cmp(&s->dest_addr, dest_addr) &&
s->sk->sk_type == type) {
sk = s->sk;
sock_hold(sk);
break;
}
}
spin_unlock(&ax25_list_lock);
return sk;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 67 | 65.69% | 5 | 41.67% |
Ralf Bächle | 25 | 24.51% | 4 | 33.33% |
Jeroen Vreeken | 6 | 5.88% | 1 | 8.33% |
Arnaldo Carvalho de Melo | 3 | 2.94% | 1 | 8.33% |
David S. Miller | 1 | 0.98% | 1 | 8.33% |
Total | 102 | 100.00% | 12 | 100.00% |
/*
* Find an AX.25 control block given both ends. It will only pick up
* floating AX.25 control blocks or non Raw socket bound control blocks.
*/
ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr,
ax25_digi *digi, struct net_device *dev)
{
ax25_cb *s;
spin_lock_bh(&ax25_list_lock);
ax25_for_each(s, &ax25_list) {
if (s->sk && s->sk->sk_type != SOCK_SEQPACKET)
continue;
if (s->ax25_dev == NULL)
continue;
if (ax25cmp(&s->source_addr, src_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->ax25_dev->dev == dev) {
if (digi != NULL && digi->ndigi != 0) {
if (s->digipeat == NULL)
continue;
if (ax25digicmp(s->digipeat, digi) != 0)
continue;
} else {
if (s->digipeat != NULL && s->digipeat->ndigi != 0)
continue;
}
ax25_cb_hold(s);
spin_unlock_bh(&ax25_list_lock);
return s;
}
}
spin_unlock_bh(&ax25_list_lock);
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 95 | 52.49% | 6 | 54.55% |
Alan Cox | 65 | 35.91% | 1 | 9.09% |
Jeroen Vreeken | 11 | 6.08% | 1 | 9.09% |
Ralf Bächle | 9 | 4.97% | 2 | 18.18% |
Arnaldo Carvalho de Melo | 1 | 0.55% | 1 | 9.09% |
Total | 181 | 100.00% | 11 | 100.00% |
EXPORT_SYMBOL(ax25_find_cb);
void ax25_send_to_raw(ax25_address *addr, struct sk_buff *skb, int proto)
{
ax25_cb *s;
struct sk_buff *copy;
spin_lock(&ax25_list_lock);
ax25_for_each(s, &ax25_list) {
if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 &&
s->sk->sk_type == SOCK_RAW &&
s->sk->sk_protocol == proto &&
s->ax25_dev->dev == skb->dev &&
atomic_read(&s->sk->sk_rmem_alloc) <= s->sk->sk_rcvbuf) {
if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL)
continue;
if (sock_queue_rcv_skb(s->sk, copy) != 0)
kfree_skb(copy);
}
}
spin_unlock(&ax25_list_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 89 | 61.81% | 6 | 46.15% |
Jeroen Vreeken | 47 | 32.64% | 3 | 23.08% |
Ralf Bächle | 5 | 3.47% | 3 | 23.08% |
Arnaldo Carvalho de Melo | 3 | 2.08% | 1 | 7.69% |
Total | 144 | 100.00% | 13 | 100.00% |
/*
* Deferred destroy.
*/
void ax25_destroy_socket(ax25_cb *);
/*
* Handler for deferred kills.
*/
static void ax25_destroy_timer(unsigned long data)
{
ax25_cb *ax25=(ax25_cb *)data;
struct sock *sk;
sk=ax25->sk;
bh_lock_sock(sk);
sock_hold(sk);
ax25_destroy_socket(ax25);
bh_unlock_sock(sk);
sock_put(sk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jeroen Vreeken | 39 | 69.64% | 1 | 25.00% |
Linus Torvalds (pre-git) | 17 | 30.36% | 3 | 75.00% |
Total | 56 | 100.00% | 4 | 100.00% |
/*
* This is called from user mode and the timers. Thus it protects itself
* against interrupt users but doesn't worry about being called during
* work. Once it is removed from the queue no interrupt or bottom half
* will touch it and we are (fairly 8-) ) safe.
*/
void ax25_destroy_socket(ax25_cb *ax25)
{
struct sk_buff *skb;
ax25_cb_del(ax25);
ax25_stop_heartbeat(ax25);
ax25_stop_t1timer(ax25);
ax25_stop_t2timer(ax25);
ax25_stop_t3timer(ax25);
ax25_stop_idletimer(ax25);
ax25_clear_queues(ax25); /* Flush the queues */
if (ax25->sk != NULL) {
while ((skb = skb_dequeue(&ax25->sk->sk_receive_queue)) != NULL) {
if (skb->sk != ax25->sk) {
/* A pending connection */
ax25_cb *sax25 = sk_to_ax25(skb->sk);
/* Queue the unaccepted socket for death */
sock_orphan(skb->sk);
/* 9A4GL: hack to release unaccepted sockets */
skb->sk->sk_state = TCP_LISTEN;
ax25_start_heartbeat(sax25);
sax25->state = AX25_STATE_0;
}
kfree_skb(skb);
}
skb_queue_purge(&ax25->sk->sk_write_queue);
}
if (ax25->sk != NULL) {
if (sk_has_allocations(ax25->sk)) {
/* Defer: outstanding buffers */
setup_timer(&ax25->dtimer, ax25_destroy_timer,
(unsigned long)ax25);
ax25->dtimer.expires = jiffies + 2 * HZ;
add_timer(&ax25->dtimer);
} else {
struct sock *sk=ax25->sk;
ax25->sk=NULL;
sock_put(sk);
}
} else {
ax25_cb_put(ax25);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 166 | 70.34% | 8 | 42.11% |
Jeroen Vreeken | 32 | 13.56% | 2 | 10.53% |
David S. Miller | 22 | 9.32% | 3 | 15.79% |
Pavel Emelyanov | 9 | 3.81% | 1 | 5.26% |
Ralf Bächle | 3 | 1.27% | 2 | 10.53% |
James Morris | 2 | 0.85% | 1 | 5.26% |
Arnaldo Carvalho de Melo | 1 | 0.42% | 1 | 5.26% |
Eric Dumazet | 1 | 0.42% | 1 | 5.26% |
Total | 236 | 100.00% | 19 | 100.00% |
/*
* dl1bke 960311: set parameters for existing AX.25 connections,
* includes a KILL command to abort any connection.
* VERY useful for debugging ;-)
*/
static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
{
struct ax25_ctl_struct ax25_ctl;
ax25_digi digi;
ax25_dev *ax25_dev;
ax25_cb *ax25;
unsigned int k;
int ret = 0;
if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)))
return -EFAULT;
if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL)
return -ENODEV;
if (ax25_ctl.digi_count > AX25_MAX_DIGIS)
return -EINVAL;
if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL)
return -EINVAL;
digi.ndigi = ax25_ctl.digi_count;
for (k = 0; k < digi.ndigi; k++)
digi.calls[k] = ax25_ctl.digi_addr[k];
if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev)) == NULL)
return -ENOTCONN;
switch (ax25_ctl.cmd) {
case AX25_KILL:
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
#ifdef CONFIG_AX25_DAMA_SLAVE
if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
ax25_dama_off(ax25);
#endif
ax25_disconnect(ax25, ENETRESET);
break;
case AX25_WINDOW:
if (ax25->modulus == AX25_MODULUS) {
if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7)
goto einval_put;
} else {
if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63)
goto einval_put;
}
ax25->window = ax25_ctl.arg;
break;
case AX25_T1:
if (ax25_ctl.arg < 1 || ax25_ctl.arg > ULONG_MAX / HZ)
goto einval_put;
ax25->rtt = (ax25_ctl.arg * HZ) / 2;
ax25->t1 = ax25_ctl.arg * HZ;
break;
case AX25_T2:
if (ax25_ctl.arg < 1 || ax25_ctl.arg > ULONG_MAX / HZ)
goto einval_put;
ax25->t2 = ax25_ctl.arg * HZ;
break;
case AX25_N2:
if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31)
goto einval_put;
ax25->n2count = 0;
ax25->n2 = ax25_ctl.arg;
break;
case AX25_T3:
if (ax25_ctl.arg > ULONG_MAX / HZ)
goto einval_put;
ax25->t3 = ax25_ctl.arg * HZ;
break;
case AX25_IDLE:
if (ax25_ctl.arg > ULONG_MAX / (60 * HZ))
goto einval_put;
ax25->idle = ax25_ctl.arg * 60 * HZ;
break;
case AX25_PACLEN:
if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535)
goto einval_put;
ax25->paclen = ax25_ctl.arg;
break;
default:
goto einval_put;
}
out_put:
ax25_cb_put(ax25);
return ret;
einval_put:
ret = -EINVAL;
goto out_put;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 415 | 78.90% | 10 | 71.43% |
Ralf Bächle | 46 | 8.75% | 1 | 7.14% |
Jarek Poplawski | 44 | 8.37% | 1 | 7.14% |
Roel Kluin | 20 | 3.80% | 1 | 7.14% |
Al Viro | 1 | 0.19% | 1 | 7.14% |
Total | 526 | 100.00% | 14 | 100.00% |
static void ax25_fillin_cb_from_dev(ax25_cb *ax25, ax25_dev *ax25_dev)
{
ax25->rtt = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]) / 2;
ax25->t1 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]);
ax25->t2 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T2]);
ax25->t3 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T3]);
ax25->n2 = ax25_dev->values[AX25_VALUES_N2];
ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN];
ax25->idle = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_IDLE]);
ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF];
if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) {
ax25->modulus = AX25_EMODULUS;
ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW];
} else {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25_dev->values[AX25_VALUES_WINDOW];
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 150 | 89.82% | 14 | 93.33% |
Ralf Bächle | 17 | 10.18% | 1 | 6.67% |
Total | 167 | 100.00% | 15 | 100.00% |
/*
* Fill in a created AX.25 created control block with the default
* values for a particular device.
*/
void ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev)
{
ax25->ax25_dev = ax25_dev;
if (ax25->ax25_dev != NULL) {
ax25_fillin_cb_from_dev(ax25, ax25_dev);
return;
}
/*
* No device, use kernel / AX.25 spec default values
*/
ax25->rtt = msecs_to_jiffies(AX25_DEF_T1) / 2;
ax25->t1 = msecs_to_jiffies(AX25_DEF_T1);
ax25->t2 = msecs_to_jiffies(AX25_DEF_T2);
ax25->t3 = msecs_to_jiffies(AX25_DEF_T3);
ax25->n2 = AX25_DEF_N2;
ax25->paclen = AX25_DEF_PACLEN;
ax25->idle = msecs_to_jiffies(AX25_DEF_IDLE);
ax25->backoff = AX25_DEF_BACKOFF;
if (AX25_DEF_AXDEFMODE) {
ax25->modulus = AX25_EMODULUS;
ax25->window = AX25_DEF_EWINDOW;
} else {
ax25->modulus = AX25_MODULUS;
ax25->window = AX25_DEF_WINDOW;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 85 | 62.50% | 9 | 90.00% |
Ralf Bächle | 51 | 37.50% | 1 | 10.00% |
Total | 136 | 100.00% | 10 | 100.00% |
/*
* Create an empty AX.25 control block.
*/
ax25_cb *ax25_create_cb(void)
{
ax25_cb *ax25;
if ((ax25 = kzalloc(sizeof(*ax25), GFP_ATOMIC)) == NULL)
return NULL;
atomic_set(&ax25->refcount, 1);
skb_queue_head_init(&ax25->write_queue);
skb_queue_head_init(&ax25->frag_queue);
skb_queue_head_init(&ax25->ack_queue);
skb_queue_head_init(&ax25->reseq_queue);
ax25_setup_timers(ax25);
ax25_fillin_cb(ax25, NULL);
ax25->state = AX25_STATE_0;
return ax25;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 85 | 87.63% | 4 | 57.14% |
Jeroen Vreeken | 10 | 10.31% | 1 | 14.29% |
Jarek Poplawski | 1 | 1.03% | 1 | 14.29% |
Ralf Bächle | 1 | 1.03% | 1 | 14.29% |
Total | 97 | 100.00% | 7 | 100.00% |
/*
* Handling for system calls applied via the various interfaces to an
* AX25 socket object
*/
static int ax25_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
ax25_cb *ax25;
struct net_device *dev;
char devname[IFNAMSIZ];
unsigned long opt;
int res = 0;
if (level != SOL_AX25)
return -ENOPROTOOPT;
if (optlen < sizeof(unsigned int))
return -EINVAL;
if (get_user(opt, (unsigned int __user *)optval))
return -EFAULT;
lock_sock(sk);
ax25 = sk_to_ax25(sk);
switch (optname) {
case AX25_WINDOW:
if (ax25->modulus == AX25_MODULUS) {
if (opt < 1 || opt > 7) {
res = -EINVAL;
break;
}
} else {
if (opt < 1 || opt > 63) {
res = -EINVAL;
break;
}
}
ax25->window = opt;
break;
case AX25_T1:
if (opt < 1 || opt > ULONG_MAX / HZ) {
res = -EINVAL;
break;
}
ax25->rtt = (opt * HZ) >> 1;
ax25->t1 = opt * HZ;
break;
case AX25_T2:
if (opt < 1 || opt > ULONG_MAX / HZ) {
res = -EINVAL;
break;
}
ax25->t2 = opt * HZ;
break;
case AX25_N2:
if (opt < 1 || opt > 31) {
res = -EINVAL;
break;
}
ax25->n2 = opt;
break;
case AX25_T3:
if (opt < 1 || opt > ULONG_MAX / HZ) {
res = -EINVAL;
break;
}
ax25->t3 = opt * HZ;
break;
case AX25_IDLE:
if (opt > ULONG_MAX / (60 * HZ)) {
res = -EINVAL;
break;
}
ax25->idle = opt * 60 * HZ;
break;
case AX25_BACKOFF:
if (opt > 2) {
res = -EINVAL;
break;
}
ax25->backoff = opt;
break;
case AX25_EXTSEQ:
ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS;
break;
case AX25_PIDINCL:
ax25->pidincl = opt ? 1 : 0;
break;
case AX25_IAMDIGI:
ax25->iamdigi = opt ? 1 : 0;
break;
case AX25_PACLEN:
if (opt < 16 || opt > 65535) {
res = -EINVAL;
break;
}
ax25->paclen = opt;
break;
case SO_BINDTODEVICE:
if (optlen > IFNAMSIZ)
optlen = IFNAMSIZ;
if (copy_from_user(devname, optval, optlen)) {
res = -EFAULT;
break;
}
if (sk->sk_type == SOCK_SEQPACKET &&
(sock->state != SS_UNCONNECTED ||
sk->sk_state == TCP_LISTEN)) {
res = -EADDRNOTAVAIL;
break;
}
dev = dev_get_by_name(&init_net, devname);
if (!dev) {
res = -ENODEV;
break;
}
ax25->ax25_dev = ax25_dev_ax25dev(dev);
ax25_fillin_cb(ax25, ax25->ax25_dev);
dev_put(dev);
break;
default:
res = -ENOPROTOOPT;
}
release_sock(sk);
return res;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 388 | 68.55% | 16 | 57.14% |
Ralf Bächle | 154 | 27.21% | 4 | 14.29% |
Xi Wang | 9 | 1.59% | 1 | 3.57% |
David S. Miller | 6 | 1.06% | 3 | 10.71% |
Jeroen Vreeken | 3 | 0.53% | 1 | 3.57% |
Arnaldo Carvalho de Melo | 2 | 0.35% | 1 | 3.57% |
Eric Dumazet | 2 | 0.35% | 1 | 3.57% |
Al Viro | 2 | 0.35% | 1 | 3.57% |
Total | 566 | 100.00% | 28 | 100.00% |
static int ax25_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
ax25_cb *ax25;
struct ax25_dev *ax25_dev;
char devname[IFNAMSIZ];
void *valptr;
int val = 0;
int maxlen, length;
if (level != SOL_AX25)
return -ENOPROTOOPT;
if (get_user(maxlen, optlen))
return -EFAULT;
if (maxlen < 1)
return -EFAULT;
valptr = (void *) &val;
length = min_t(unsigned int, maxlen, sizeof(int));
lock_sock(sk);
ax25 = sk_to_ax25(sk);
switch (optname) {
case AX25_WINDOW:
val = ax25->window;
break;
case AX25_T1:
val = ax25->t1 / HZ;
break;
case AX25_T2:
val = ax25->t2 / HZ;
break;
case AX25_N2:
val = ax25->n2;
break;
case AX25_T3:
val = ax25->t3 / HZ;
break;
case AX25_IDLE:
val = ax25->idle / (60 * HZ);
break;
case AX25_BACKOFF:
val = ax25->backoff;
break;
case AX25_EXTSEQ:
val = (ax25->modulus == AX25_EMODULUS);
break;
case AX25_PIDINCL:
val = ax25->pidincl;
break;
case AX25_IAMDIGI:
val = ax25->iamdigi;
break;
case AX25_PACLEN:
val = ax25->paclen;
break;
case SO_BINDTODEVICE:
ax25_dev = ax25->ax25_dev;
if (ax25_dev != NULL && ax25_dev->dev != NULL) {
strlcpy(devname, ax25_dev->dev->name, sizeof(devname));
length = strlen(devname) + 1;
} else {
*devname = '\0';
length = 1;
}
valptr = (void *