12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds *
41da177e4SLinus Torvalds * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
51da177e4SLinus Torvalds * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
61da177e4SLinus Torvalds * Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
71da177e4SLinus Torvalds * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
81da177e4SLinus Torvalds * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
91da177e4SLinus Torvalds * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
101da177e4SLinus Torvalds * Copyright (C) Hans Alblas PE1AYX (hans@esrac.ele.tue.nl)
111da177e4SLinus Torvalds * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
121da177e4SLinus Torvalds */
134fc268d2SRandy Dunlap #include <linux/capability.h>
141da177e4SLinus Torvalds #include <linux/module.h>
151da177e4SLinus Torvalds #include <linux/errno.h>
161da177e4SLinus Torvalds #include <linux/types.h>
171da177e4SLinus Torvalds #include <linux/socket.h>
181da177e4SLinus Torvalds #include <linux/in.h>
191da177e4SLinus Torvalds #include <linux/kernel.h>
203f07c014SIngo Molnar #include <linux/sched/signal.h>
211da177e4SLinus Torvalds #include <linux/timer.h>
221da177e4SLinus Torvalds #include <linux/string.h>
231da177e4SLinus Torvalds #include <linux/sockios.h>
241da177e4SLinus Torvalds #include <linux/net.h>
255a0e3ad6STejun Heo #include <linux/slab.h>
261da177e4SLinus Torvalds #include <net/ax25.h>
271da177e4SLinus Torvalds #include <linux/inet.h>
281da177e4SLinus Torvalds #include <linux/netdevice.h>
291da177e4SLinus Torvalds #include <linux/if_arp.h>
301da177e4SLinus Torvalds #include <linux/skbuff.h>
311da177e4SLinus Torvalds #include <net/sock.h>
327c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
331da177e4SLinus Torvalds #include <linux/fcntl.h>
341da177e4SLinus Torvalds #include <linux/termios.h> /* For TIOCINQ/OUTQ */
351da177e4SLinus Torvalds #include <linux/mm.h>
361da177e4SLinus Torvalds #include <linux/interrupt.h>
371da177e4SLinus Torvalds #include <linux/notifier.h>
381da177e4SLinus Torvalds #include <linux/proc_fs.h>
391da177e4SLinus Torvalds #include <linux/stat.h>
401da177e4SLinus Torvalds #include <linux/sysctl.h>
411da177e4SLinus Torvalds #include <linux/init.h>
421da177e4SLinus Torvalds #include <linux/spinlock.h>
43457c4cbcSEric W. Biederman #include <net/net_namespace.h>
44c752f073SArnaldo Carvalho de Melo #include <net/tcp_states.h>
451da177e4SLinus Torvalds #include <net/ip.h>
461da177e4SLinus Torvalds #include <net/arp.h>
471da177e4SLinus Torvalds
481da177e4SLinus Torvalds
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds HLIST_HEAD(ax25_list);
511da177e4SLinus Torvalds DEFINE_SPINLOCK(ax25_list_lock);
521da177e4SLinus Torvalds
5390ddc4f0SEric Dumazet static const struct proto_ops ax25_proto_ops;
541da177e4SLinus Torvalds
ax25_free_sock(struct sock * sk)551da177e4SLinus Torvalds static void ax25_free_sock(struct sock *sk)
561da177e4SLinus Torvalds {
573200392bSDavid Miller ax25_cb_put(sk_to_ax25(sk));
581da177e4SLinus Torvalds }
591da177e4SLinus Torvalds
601da177e4SLinus Torvalds /*
611da177e4SLinus Torvalds * Socket removal during an interrupt is now safe.
621da177e4SLinus Torvalds */
ax25_cb_del(ax25_cb * ax25)631da177e4SLinus Torvalds static void ax25_cb_del(ax25_cb *ax25)
641da177e4SLinus Torvalds {
651da177e4SLinus Torvalds spin_lock_bh(&ax25_list_lock);
667d8a3a47SDuoming Zhou if (!hlist_unhashed(&ax25->ax25_node)) {
671da177e4SLinus Torvalds hlist_del_init(&ax25->ax25_node);
681da177e4SLinus Torvalds ax25_cb_put(ax25);
691da177e4SLinus Torvalds }
707d8a3a47SDuoming Zhou spin_unlock_bh(&ax25_list_lock);
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds
731da177e4SLinus Torvalds /*
741da177e4SLinus Torvalds * Kill all bound sockets on a dropped device.
751da177e4SLinus Torvalds */
ax25_kill_by_device(struct net_device * dev)761da177e4SLinus Torvalds static void ax25_kill_by_device(struct net_device *dev)
771da177e4SLinus Torvalds {
781da177e4SLinus Torvalds ax25_dev *ax25_dev;
791da177e4SLinus Torvalds ax25_cb *s;
804e0f718dSDuoming Zhou struct sock *sk;
811da177e4SLinus Torvalds
821da177e4SLinus Torvalds if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
831da177e4SLinus Torvalds return;
847d8a3a47SDuoming Zhou ax25_dev->device_up = false;
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds spin_lock_bh(&ax25_list_lock);
87ecd2ebdeSJarek Poplawski again:
88b67bfe0dSSasha Levin ax25_for_each(s, &ax25_list) {
891da177e4SLinus Torvalds if (s->ax25_dev == ax25_dev) {
904e0f718dSDuoming Zhou sk = s->sk;
9171171ac8SDuoming Zhou if (!sk) {
9271171ac8SDuoming Zhou spin_unlock_bh(&ax25_list_lock);
9371171ac8SDuoming Zhou ax25_disconnect(s, ENETUNREACH);
94fc6d01ffSDuoming Zhou s->ax25_dev = NULL;
957d8a3a47SDuoming Zhou ax25_cb_del(s);
9671171ac8SDuoming Zhou spin_lock_bh(&ax25_list_lock);
9771171ac8SDuoming Zhou goto again;
9871171ac8SDuoming Zhou }
994e0f718dSDuoming Zhou sock_hold(sk);
100ecd2ebdeSJarek Poplawski spin_unlock_bh(&ax25_list_lock);
1014e0f718dSDuoming Zhou lock_sock(sk);
102fc6d01ffSDuoming Zhou ax25_disconnect(s, ENETUNREACH);
1031ade48d0SLin Ma s->ax25_dev = NULL;
1049fd75b66SDuoming Zhou if (sk->sk_socket) {
105d62607c3SJakub Kicinski netdev_put(ax25_dev->dev,
1064fee8fa8SDuoming Zhou &s->dev_tracker);
107d01ffb9eSDuoming Zhou ax25_dev_put(ax25_dev);
1089fd75b66SDuoming Zhou }
1097d8a3a47SDuoming Zhou ax25_cb_del(s);
1107ec02f5aSDuoming Zhou release_sock(sk);
111ecd2ebdeSJarek Poplawski spin_lock_bh(&ax25_list_lock);
1124e0f718dSDuoming Zhou sock_put(sk);
113ecd2ebdeSJarek Poplawski /* The entry could have been deleted from the
114ecd2ebdeSJarek Poplawski * list meanwhile and thus the next pointer is
115ecd2ebdeSJarek Poplawski * no longer valid. Play it safe and restart
116ecd2ebdeSJarek Poplawski * the scan. Forward progress is ensured
117ecd2ebdeSJarek Poplawski * because we set s->ax25_dev to NULL and we
118ecd2ebdeSJarek Poplawski * are never passed a NULL 'dev' argument.
119ecd2ebdeSJarek Poplawski */
120ecd2ebdeSJarek Poplawski goto again;
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds spin_unlock_bh(&ax25_list_lock);
1241da177e4SLinus Torvalds }
1251da177e4SLinus Torvalds
1261da177e4SLinus Torvalds /*
1271da177e4SLinus Torvalds * Handle device status changes.
1281da177e4SLinus Torvalds */
ax25_device_event(struct notifier_block * this,unsigned long event,void * ptr)1291da177e4SLinus Torvalds static int ax25_device_event(struct notifier_block *this, unsigned long event,
1301da177e4SLinus Torvalds void *ptr)
1311da177e4SLinus Torvalds {
132351638e7SJiri Pirko struct net_device *dev = netdev_notifier_info_to_dev(ptr);
1331da177e4SLinus Torvalds
134721499e8SYOSHIFUJI Hideaki if (!net_eq(dev_net(dev), &init_net))
135e9dc8653SEric W. Biederman return NOTIFY_DONE;
136e9dc8653SEric W. Biederman
1371da177e4SLinus Torvalds /* Reject non AX.25 devices */
1381da177e4SLinus Torvalds if (dev->type != ARPHRD_AX25)
1391da177e4SLinus Torvalds return NOTIFY_DONE;
1401da177e4SLinus Torvalds
1411da177e4SLinus Torvalds switch (event) {
1421da177e4SLinus Torvalds case NETDEV_UP:
1431da177e4SLinus Torvalds ax25_dev_device_up(dev);
1441da177e4SLinus Torvalds break;
1451da177e4SLinus Torvalds case NETDEV_DOWN:
1461da177e4SLinus Torvalds ax25_kill_by_device(dev);
1471da177e4SLinus Torvalds ax25_rt_device_down(dev);
1481da177e4SLinus Torvalds ax25_dev_device_down(dev);
1491da177e4SLinus Torvalds break;
1501da177e4SLinus Torvalds default:
1511da177e4SLinus Torvalds break;
1521da177e4SLinus Torvalds }
1531da177e4SLinus Torvalds
1541da177e4SLinus Torvalds return NOTIFY_DONE;
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds
1571da177e4SLinus Torvalds /*
1581da177e4SLinus Torvalds * Add a socket to the bound sockets list.
1591da177e4SLinus Torvalds */
ax25_cb_add(ax25_cb * ax25)1601da177e4SLinus Torvalds void ax25_cb_add(ax25_cb *ax25)
1611da177e4SLinus Torvalds {
1621da177e4SLinus Torvalds spin_lock_bh(&ax25_list_lock);
1631da177e4SLinus Torvalds ax25_cb_hold(ax25);
1641da177e4SLinus Torvalds hlist_add_head(&ax25->ax25_node, &ax25_list);
1651da177e4SLinus Torvalds spin_unlock_bh(&ax25_list_lock);
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds
1681da177e4SLinus Torvalds /*
1691da177e4SLinus Torvalds * Find a socket that wants to accept the SABM we have just
1701da177e4SLinus Torvalds * received.
1711da177e4SLinus Torvalds */
ax25_find_listener(ax25_address * addr,int digi,struct net_device * dev,int type)1721da177e4SLinus Torvalds struct sock *ax25_find_listener(ax25_address *addr, int digi,
1731da177e4SLinus Torvalds struct net_device *dev, int type)
1741da177e4SLinus Torvalds {
1751da177e4SLinus Torvalds ax25_cb *s;
1761da177e4SLinus Torvalds
177c19c4b9cSRalf Baechle spin_lock(&ax25_list_lock);
178b67bfe0dSSasha Levin ax25_for_each(s, &ax25_list) {
1791da177e4SLinus Torvalds if ((s->iamdigi && !digi) || (!s->iamdigi && digi))
1801da177e4SLinus Torvalds continue;
1811da177e4SLinus Torvalds if (s->sk && !ax25cmp(&s->source_addr, addr) &&
1821da177e4SLinus Torvalds s->sk->sk_type == type && s->sk->sk_state == TCP_LISTEN) {
1831da177e4SLinus Torvalds /* If device is null we match any device */
1841da177e4SLinus Torvalds if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) {
1851da177e4SLinus Torvalds sock_hold(s->sk);
186c19c4b9cSRalf Baechle spin_unlock(&ax25_list_lock);
1871da177e4SLinus Torvalds return s->sk;
1881da177e4SLinus Torvalds }
1891da177e4SLinus Torvalds }
1901da177e4SLinus Torvalds }
191c19c4b9cSRalf Baechle spin_unlock(&ax25_list_lock);
1921da177e4SLinus Torvalds
1931da177e4SLinus Torvalds return NULL;
1941da177e4SLinus Torvalds }
1951da177e4SLinus Torvalds
1961da177e4SLinus Torvalds /*
1971da177e4SLinus Torvalds * Find an AX.25 socket given both ends.
1981da177e4SLinus Torvalds */
ax25_get_socket(ax25_address * my_addr,ax25_address * dest_addr,int type)1991da177e4SLinus Torvalds struct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr,
2001da177e4SLinus Torvalds int type)
2011da177e4SLinus Torvalds {
2021da177e4SLinus Torvalds struct sock *sk = NULL;
2031da177e4SLinus Torvalds ax25_cb *s;
2041da177e4SLinus Torvalds
205c19c4b9cSRalf Baechle spin_lock(&ax25_list_lock);
206b67bfe0dSSasha Levin ax25_for_each(s, &ax25_list) {
2071da177e4SLinus Torvalds if (s->sk && !ax25cmp(&s->source_addr, my_addr) &&
2081da177e4SLinus Torvalds !ax25cmp(&s->dest_addr, dest_addr) &&
2091da177e4SLinus Torvalds s->sk->sk_type == type) {
2101da177e4SLinus Torvalds sk = s->sk;
2111da177e4SLinus Torvalds sock_hold(sk);
2121da177e4SLinus Torvalds break;
2131da177e4SLinus Torvalds }
2141da177e4SLinus Torvalds }
2151da177e4SLinus Torvalds
216c19c4b9cSRalf Baechle spin_unlock(&ax25_list_lock);
2171da177e4SLinus Torvalds
2181da177e4SLinus Torvalds return sk;
2191da177e4SLinus Torvalds }
2201da177e4SLinus Torvalds
2211da177e4SLinus Torvalds /*
2221da177e4SLinus Torvalds * Find an AX.25 control block given both ends. It will only pick up
2231da177e4SLinus Torvalds * floating AX.25 control blocks or non Raw socket bound control blocks.
2241da177e4SLinus Torvalds */
ax25_find_cb(const ax25_address * src_addr,ax25_address * dest_addr,ax25_digi * digi,struct net_device * dev)225c045ad2cSJakub Kicinski ax25_cb *ax25_find_cb(const ax25_address *src_addr, ax25_address *dest_addr,
2261da177e4SLinus Torvalds ax25_digi *digi, struct net_device *dev)
2271da177e4SLinus Torvalds {
2281da177e4SLinus Torvalds ax25_cb *s;
2291da177e4SLinus Torvalds
2301da177e4SLinus Torvalds spin_lock_bh(&ax25_list_lock);
231b67bfe0dSSasha Levin ax25_for_each(s, &ax25_list) {
2321da177e4SLinus Torvalds if (s->sk && s->sk->sk_type != SOCK_SEQPACKET)
2331da177e4SLinus Torvalds continue;
2341da177e4SLinus Torvalds if (s->ax25_dev == NULL)
2351da177e4SLinus Torvalds continue;
2361da177e4SLinus Torvalds if (ax25cmp(&s->source_addr, src_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->ax25_dev->dev == dev) {
2371da177e4SLinus Torvalds if (digi != NULL && digi->ndigi != 0) {
2381da177e4SLinus Torvalds if (s->digipeat == NULL)
2391da177e4SLinus Torvalds continue;
2401da177e4SLinus Torvalds if (ax25digicmp(s->digipeat, digi) != 0)
2411da177e4SLinus Torvalds continue;
2421da177e4SLinus Torvalds } else {
2431da177e4SLinus Torvalds if (s->digipeat != NULL && s->digipeat->ndigi != 0)
2441da177e4SLinus Torvalds continue;
2451da177e4SLinus Torvalds }
2461da177e4SLinus Torvalds ax25_cb_hold(s);
2471da177e4SLinus Torvalds spin_unlock_bh(&ax25_list_lock);
2481da177e4SLinus Torvalds
2491da177e4SLinus Torvalds return s;
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds }
2521da177e4SLinus Torvalds spin_unlock_bh(&ax25_list_lock);
2531da177e4SLinus Torvalds
2541da177e4SLinus Torvalds return NULL;
2551da177e4SLinus Torvalds }
2561da177e4SLinus Torvalds
25770868eacSRalf Baechle EXPORT_SYMBOL(ax25_find_cb);
25870868eacSRalf Baechle
ax25_send_to_raw(ax25_address * addr,struct sk_buff * skb,int proto)2591da177e4SLinus Torvalds void ax25_send_to_raw(ax25_address *addr, struct sk_buff *skb, int proto)
2601da177e4SLinus Torvalds {
2611da177e4SLinus Torvalds ax25_cb *s;
2621da177e4SLinus Torvalds struct sk_buff *copy;
2631da177e4SLinus Torvalds
264c19c4b9cSRalf Baechle spin_lock(&ax25_list_lock);
265b67bfe0dSSasha Levin ax25_for_each(s, &ax25_list) {
2661da177e4SLinus Torvalds if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 &&
2671da177e4SLinus Torvalds s->sk->sk_type == SOCK_RAW &&
2681da177e4SLinus Torvalds s->sk->sk_protocol == proto &&
2691da177e4SLinus Torvalds s->ax25_dev->dev == skb->dev &&
2701da177e4SLinus Torvalds atomic_read(&s->sk->sk_rmem_alloc) <= s->sk->sk_rcvbuf) {
2711da177e4SLinus Torvalds if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL)
2721da177e4SLinus Torvalds continue;
2731da177e4SLinus Torvalds if (sock_queue_rcv_skb(s->sk, copy) != 0)
2741da177e4SLinus Torvalds kfree_skb(copy);
2751da177e4SLinus Torvalds }
2761da177e4SLinus Torvalds }
277c19c4b9cSRalf Baechle spin_unlock(&ax25_list_lock);
2781da177e4SLinus Torvalds }
2791da177e4SLinus Torvalds
2801da177e4SLinus Torvalds /*
2811da177e4SLinus Torvalds * Deferred destroy.
2821da177e4SLinus Torvalds */
2831da177e4SLinus Torvalds void ax25_destroy_socket(ax25_cb *);
2841da177e4SLinus Torvalds
2851da177e4SLinus Torvalds /*
2861da177e4SLinus Torvalds * Handler for deferred kills.
2871da177e4SLinus Torvalds */
ax25_destroy_timer(struct timer_list * t)2888dbd05ffSKees Cook static void ax25_destroy_timer(struct timer_list *t)
2891da177e4SLinus Torvalds {
2908dbd05ffSKees Cook ax25_cb *ax25 = from_timer(ax25, t, dtimer);
2911da177e4SLinus Torvalds struct sock *sk;
2921da177e4SLinus Torvalds
2931da177e4SLinus Torvalds sk=ax25->sk;
2941da177e4SLinus Torvalds
2951da177e4SLinus Torvalds bh_lock_sock(sk);
2961da177e4SLinus Torvalds sock_hold(sk);
2971da177e4SLinus Torvalds ax25_destroy_socket(ax25);
2981da177e4SLinus Torvalds bh_unlock_sock(sk);
2991da177e4SLinus Torvalds sock_put(sk);
3001da177e4SLinus Torvalds }
3011da177e4SLinus Torvalds
3021da177e4SLinus Torvalds /*
3031da177e4SLinus Torvalds * This is called from user mode and the timers. Thus it protects itself
3041da177e4SLinus Torvalds * against interrupt users but doesn't worry about being called during
3051da177e4SLinus Torvalds * work. Once it is removed from the queue no interrupt or bottom half
3061da177e4SLinus Torvalds * will touch it and we are (fairly 8-) ) safe.
3071da177e4SLinus Torvalds */
ax25_destroy_socket(ax25_cb * ax25)3081da177e4SLinus Torvalds void ax25_destroy_socket(ax25_cb *ax25)
3091da177e4SLinus Torvalds {
3101da177e4SLinus Torvalds struct sk_buff *skb;
3111da177e4SLinus Torvalds
3121da177e4SLinus Torvalds ax25_cb_del(ax25);
3131da177e4SLinus Torvalds
3141da177e4SLinus Torvalds ax25_stop_heartbeat(ax25);
3151da177e4SLinus Torvalds ax25_stop_t1timer(ax25);
3161da177e4SLinus Torvalds ax25_stop_t2timer(ax25);
3171da177e4SLinus Torvalds ax25_stop_t3timer(ax25);
3181da177e4SLinus Torvalds ax25_stop_idletimer(ax25);
3191da177e4SLinus Torvalds
3201da177e4SLinus Torvalds ax25_clear_queues(ax25); /* Flush the queues */
3211da177e4SLinus Torvalds
3221da177e4SLinus Torvalds if (ax25->sk != NULL) {
3231da177e4SLinus Torvalds while ((skb = skb_dequeue(&ax25->sk->sk_receive_queue)) != NULL) {
3241da177e4SLinus Torvalds if (skb->sk != ax25->sk) {
3251da177e4SLinus Torvalds /* A pending connection */
3263200392bSDavid Miller ax25_cb *sax25 = sk_to_ax25(skb->sk);
3271da177e4SLinus Torvalds
3281da177e4SLinus Torvalds /* Queue the unaccepted socket for death */
3291da177e4SLinus Torvalds sock_orphan(skb->sk);
3301da177e4SLinus Torvalds
33133d1d2c5SDavid S. Miller /* 9A4GL: hack to release unaccepted sockets */
33233d1d2c5SDavid S. Miller skb->sk->sk_state = TCP_LISTEN;
33333d1d2c5SDavid S. Miller
3341da177e4SLinus Torvalds ax25_start_heartbeat(sax25);
3351da177e4SLinus Torvalds sax25->state = AX25_STATE_0;
3361da177e4SLinus Torvalds }
3371da177e4SLinus Torvalds
3381da177e4SLinus Torvalds kfree_skb(skb);
3391da177e4SLinus Torvalds }
3401da177e4SLinus Torvalds skb_queue_purge(&ax25->sk->sk_write_queue);
3411da177e4SLinus Torvalds }
3421da177e4SLinus Torvalds
3431da177e4SLinus Torvalds if (ax25->sk != NULL) {
344c564039fSEric Dumazet if (sk_has_allocations(ax25->sk)) {
3451da177e4SLinus Torvalds /* Defer: outstanding buffers */
3468dbd05ffSKees Cook timer_setup(&ax25->dtimer, ax25_destroy_timer, 0);
3471da177e4SLinus Torvalds ax25->dtimer.expires = jiffies + 2 * HZ;
3481da177e4SLinus Torvalds add_timer(&ax25->dtimer);
3491da177e4SLinus Torvalds } else {
3501da177e4SLinus Torvalds struct sock *sk=ax25->sk;
3511da177e4SLinus Torvalds ax25->sk=NULL;
3521da177e4SLinus Torvalds sock_put(sk);
3531da177e4SLinus Torvalds }
3541da177e4SLinus Torvalds } else {
3551da177e4SLinus Torvalds ax25_cb_put(ax25);
3561da177e4SLinus Torvalds }
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds
3591da177e4SLinus Torvalds /*
3601da177e4SLinus Torvalds * dl1bke 960311: set parameters for existing AX.25 connections,
3611da177e4SLinus Torvalds * includes a KILL command to abort any connection.
3621da177e4SLinus Torvalds * VERY useful for debugging ;-)
3631da177e4SLinus Torvalds */
ax25_ctl_ioctl(const unsigned int cmd,void __user * arg)3641da177e4SLinus Torvalds static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
3651da177e4SLinus Torvalds {
3661da177e4SLinus Torvalds struct ax25_ctl_struct ax25_ctl;
3671da177e4SLinus Torvalds ax25_digi digi;
3681da177e4SLinus Torvalds ax25_dev *ax25_dev;
3691da177e4SLinus Torvalds ax25_cb *ax25;
3701da177e4SLinus Torvalds unsigned int k;
371c0181d42SJarek Poplawski int ret = 0;
3721da177e4SLinus Torvalds
3731da177e4SLinus Torvalds if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl)))
3741da177e4SLinus Torvalds return -EFAULT;
3751da177e4SLinus Torvalds
3761da177e4SLinus Torvalds if (ax25_ctl.digi_count > AX25_MAX_DIGIS)
3771da177e4SLinus Torvalds return -EINVAL;
3781da177e4SLinus Torvalds
37943ab8502Sroel kluin if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL)
38043ab8502Sroel kluin return -EINVAL;
38143ab8502Sroel kluin
38287563a04SDuoming Zhou ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr);
38387563a04SDuoming Zhou if (!ax25_dev)
38487563a04SDuoming Zhou return -ENODEV;
38587563a04SDuoming Zhou
3861da177e4SLinus Torvalds digi.ndigi = ax25_ctl.digi_count;
3871da177e4SLinus Torvalds for (k = 0; k < digi.ndigi; k++)
3881da177e4SLinus Torvalds digi.calls[k] = ax25_ctl.digi_addr[k];
3891da177e4SLinus Torvalds
39087563a04SDuoming Zhou ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev);
39187563a04SDuoming Zhou if (!ax25) {
39287563a04SDuoming Zhou ax25_dev_put(ax25_dev);
3931da177e4SLinus Torvalds return -ENOTCONN;
39487563a04SDuoming Zhou }
3951da177e4SLinus Torvalds
3961da177e4SLinus Torvalds switch (ax25_ctl.cmd) {
3971da177e4SLinus Torvalds case AX25_KILL:
3981da177e4SLinus Torvalds ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
3991da177e4SLinus Torvalds #ifdef CONFIG_AX25_DAMA_SLAVE
4001da177e4SLinus Torvalds if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
4011da177e4SLinus Torvalds ax25_dama_off(ax25);
4021da177e4SLinus Torvalds #endif
4031da177e4SLinus Torvalds ax25_disconnect(ax25, ENETRESET);
4041da177e4SLinus Torvalds break;
4051da177e4SLinus Torvalds
4061da177e4SLinus Torvalds case AX25_WINDOW:
4071da177e4SLinus Torvalds if (ax25->modulus == AX25_MODULUS) {
4081da177e4SLinus Torvalds if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7)
409c0181d42SJarek Poplawski goto einval_put;
4101da177e4SLinus Torvalds } else {
4111da177e4SLinus Torvalds if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63)
412c0181d42SJarek Poplawski goto einval_put;
4131da177e4SLinus Torvalds }
4141da177e4SLinus Torvalds ax25->window = ax25_ctl.arg;
4151da177e4SLinus Torvalds break;
4161da177e4SLinus Torvalds
4171da177e4SLinus Torvalds case AX25_T1:
418be639ac6SRalf Baechle if (ax25_ctl.arg < 1 || ax25_ctl.arg > ULONG_MAX / HZ)
419c0181d42SJarek Poplawski goto einval_put;
4201da177e4SLinus Torvalds ax25->rtt = (ax25_ctl.arg * HZ) / 2;
4211da177e4SLinus Torvalds ax25->t1 = ax25_ctl.arg * HZ;
4221da177e4SLinus Torvalds break;
4231da177e4SLinus Torvalds
4241da177e4SLinus Torvalds case AX25_T2:
425be639ac6SRalf Baechle if (ax25_ctl.arg < 1 || ax25_ctl.arg > ULONG_MAX / HZ)
426c0181d42SJarek Poplawski goto einval_put;
4271da177e4SLinus Torvalds ax25->t2 = ax25_ctl.arg * HZ;
4281da177e4SLinus Torvalds break;
4291da177e4SLinus Torvalds
4301da177e4SLinus Torvalds case AX25_N2:
4311da177e4SLinus Torvalds if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31)
432c0181d42SJarek Poplawski goto einval_put;
4331da177e4SLinus Torvalds ax25->n2count = 0;
4341da177e4SLinus Torvalds ax25->n2 = ax25_ctl.arg;
4351da177e4SLinus Torvalds break;
4361da177e4SLinus Torvalds
4371da177e4SLinus Torvalds case AX25_T3:
438be639ac6SRalf Baechle if (ax25_ctl.arg > ULONG_MAX / HZ)
439be639ac6SRalf Baechle goto einval_put;
4401da177e4SLinus Torvalds ax25->t3 = ax25_ctl.arg * HZ;
4411da177e4SLinus Torvalds break;
4421da177e4SLinus Torvalds
4431da177e4SLinus Torvalds case AX25_IDLE:
444be639ac6SRalf Baechle if (ax25_ctl.arg > ULONG_MAX / (60 * HZ))
445be639ac6SRalf Baechle goto einval_put;
446be639ac6SRalf Baechle
4471da177e4SLinus Torvalds ax25->idle = ax25_ctl.arg * 60 * HZ;
4481da177e4SLinus Torvalds break;
4491da177e4SLinus Torvalds
4501da177e4SLinus Torvalds case AX25_PACLEN:
4511da177e4SLinus Torvalds if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535)
452c0181d42SJarek Poplawski goto einval_put;
4531da177e4SLinus Torvalds ax25->paclen = ax25_ctl.arg;
4541da177e4SLinus Torvalds break;
4551da177e4SLinus Torvalds
4561da177e4SLinus Torvalds default:
457c0181d42SJarek Poplawski goto einval_put;
4581da177e4SLinus Torvalds }
4591da177e4SLinus Torvalds
460c0181d42SJarek Poplawski out_put:
461d01ffb9eSDuoming Zhou ax25_dev_put(ax25_dev);
462c0181d42SJarek Poplawski ax25_cb_put(ax25);
463c0181d42SJarek Poplawski return ret;
464c0181d42SJarek Poplawski
465c0181d42SJarek Poplawski einval_put:
466c0181d42SJarek Poplawski ret = -EINVAL;
467c0181d42SJarek Poplawski goto out_put;
4681da177e4SLinus Torvalds }
4691da177e4SLinus Torvalds
ax25_fillin_cb_from_dev(ax25_cb * ax25,const ax25_dev * ax25_dev)4707705d8a7SEric Dumazet static void ax25_fillin_cb_from_dev(ax25_cb *ax25, const ax25_dev *ax25_dev)
4711da177e4SLinus Torvalds {
472e1fdb5b3SRalf Baechle ax25->rtt = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]) / 2;
473e1fdb5b3SRalf Baechle ax25->t1 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]);
474e1fdb5b3SRalf Baechle ax25->t2 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T2]);
475e1fdb5b3SRalf Baechle ax25->t3 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T3]);
4761da177e4SLinus Torvalds ax25->n2 = ax25_dev->values[AX25_VALUES_N2];
4771da177e4SLinus Torvalds ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN];
478e1fdb5b3SRalf Baechle ax25->idle = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_IDLE]);
4791da177e4SLinus Torvalds ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF];
4801da177e4SLinus Torvalds
4811da177e4SLinus Torvalds if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) {
4821da177e4SLinus Torvalds ax25->modulus = AX25_EMODULUS;
4831da177e4SLinus Torvalds ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW];
4841da177e4SLinus Torvalds } else {
4851da177e4SLinus Torvalds ax25->modulus = AX25_MODULUS;
4861da177e4SLinus Torvalds ax25->window = ax25_dev->values[AX25_VALUES_WINDOW];
4871da177e4SLinus Torvalds }
488e1fdb5b3SRalf Baechle }
489e1fdb5b3SRalf Baechle
490e1fdb5b3SRalf Baechle /*
491e1fdb5b3SRalf Baechle * Fill in a created AX.25 created control block with the default
492e1fdb5b3SRalf Baechle * values for a particular device.
493e1fdb5b3SRalf Baechle */
ax25_fillin_cb(ax25_cb * ax25,ax25_dev * ax25_dev)494e1fdb5b3SRalf Baechle void ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev)
495e1fdb5b3SRalf Baechle {
496e1fdb5b3SRalf Baechle ax25->ax25_dev = ax25_dev;
497e1fdb5b3SRalf Baechle
498e1fdb5b3SRalf Baechle if (ax25->ax25_dev != NULL) {
499e1fdb5b3SRalf Baechle ax25_fillin_cb_from_dev(ax25, ax25_dev);
500e1fdb5b3SRalf Baechle return;
501e1fdb5b3SRalf Baechle }
502e1fdb5b3SRalf Baechle
503e1fdb5b3SRalf Baechle /*
504e1fdb5b3SRalf Baechle * No device, use kernel / AX.25 spec default values
505e1fdb5b3SRalf Baechle */
506e1fdb5b3SRalf Baechle ax25->rtt = msecs_to_jiffies(AX25_DEF_T1) / 2;
507e1fdb5b3SRalf Baechle ax25->t1 = msecs_to_jiffies(AX25_DEF_T1);
508e1fdb5b3SRalf Baechle ax25->t2 = msecs_to_jiffies(AX25_DEF_T2);
509e1fdb5b3SRalf Baechle ax25->t3 = msecs_to_jiffies(AX25_DEF_T3);
5101da177e4SLinus Torvalds ax25->n2 = AX25_DEF_N2;
5111da177e4SLinus Torvalds ax25->paclen = AX25_DEF_PACLEN;
512e1fdb5b3SRalf Baechle ax25->idle = msecs_to_jiffies(AX25_DEF_IDLE);
5131da177e4SLinus Torvalds ax25->backoff = AX25_DEF_BACKOFF;
5141da177e4SLinus Torvalds
5151da177e4SLinus Torvalds if (AX25_DEF_AXDEFMODE) {
5161da177e4SLinus Torvalds ax25->modulus = AX25_EMODULUS;
5171da177e4SLinus Torvalds ax25->window = AX25_DEF_EWINDOW;
5181da177e4SLinus Torvalds } else {
5191da177e4SLinus Torvalds ax25->modulus = AX25_MODULUS;
5201da177e4SLinus Torvalds ax25->window = AX25_DEF_WINDOW;
5211da177e4SLinus Torvalds }
5221da177e4SLinus Torvalds }
5231da177e4SLinus Torvalds
5241da177e4SLinus Torvalds /*
5251da177e4SLinus Torvalds * Create an empty AX.25 control block.
5261da177e4SLinus Torvalds */
ax25_create_cb(void)5271da177e4SLinus Torvalds ax25_cb *ax25_create_cb(void)
5281da177e4SLinus Torvalds {
5291da177e4SLinus Torvalds ax25_cb *ax25;
5301da177e4SLinus Torvalds
5311b30dd35SRalf Baechle if ((ax25 = kzalloc(sizeof(*ax25), GFP_ATOMIC)) == NULL)
5321da177e4SLinus Torvalds return NULL;
5331da177e4SLinus Torvalds
534b6d52edeSReshetova, Elena refcount_set(&ax25->refcount, 1);
5351da177e4SLinus Torvalds
5361da177e4SLinus Torvalds skb_queue_head_init(&ax25->write_queue);
5371da177e4SLinus Torvalds skb_queue_head_init(&ax25->frag_queue);
5381da177e4SLinus Torvalds skb_queue_head_init(&ax25->ack_queue);
5391da177e4SLinus Torvalds skb_queue_head_init(&ax25->reseq_queue);
5401da177e4SLinus Torvalds
54121fab4a8SJarek Poplawski ax25_setup_timers(ax25);
5421da177e4SLinus Torvalds
5431da177e4SLinus Torvalds ax25_fillin_cb(ax25, NULL);
5441da177e4SLinus Torvalds
5451da177e4SLinus Torvalds ax25->state = AX25_STATE_0;
5461da177e4SLinus Torvalds
5471da177e4SLinus Torvalds return ax25;
5481da177e4SLinus Torvalds }
5491da177e4SLinus Torvalds
5501da177e4SLinus Torvalds /*
5511da177e4SLinus Torvalds * Handling for system calls applied via the various interfaces to an
5521da177e4SLinus Torvalds * AX25 socket object
5531da177e4SLinus Torvalds */
5541da177e4SLinus Torvalds
ax25_setsockopt(struct socket * sock,int level,int optname,sockptr_t optval,unsigned int optlen)5551da177e4SLinus Torvalds static int ax25_setsockopt(struct socket *sock, int level, int optname,
556a7b75c5aSChristoph Hellwig sockptr_t optval, unsigned int optlen)
5571da177e4SLinus Torvalds {
5581da177e4SLinus Torvalds struct sock *sk = sock->sk;
5591da177e4SLinus Torvalds ax25_cb *ax25;
5601da177e4SLinus Torvalds struct net_device *dev;
5611da177e4SLinus Torvalds char devname[IFNAMSIZ];
56293719370SDan Carpenter unsigned int opt;
563ba1cffe0SXi Wang int res = 0;
5641da177e4SLinus Torvalds
5651da177e4SLinus Torvalds if (level != SOL_AX25)
5661da177e4SLinus Torvalds return -ENOPROTOOPT;
5671da177e4SLinus Torvalds
568ba1cffe0SXi Wang if (optlen < sizeof(unsigned int))
5691da177e4SLinus Torvalds return -EINVAL;
5701da177e4SLinus Torvalds
571a7b75c5aSChristoph Hellwig if (copy_from_sockptr(&opt, optval, sizeof(unsigned int)))
5721da177e4SLinus Torvalds return -EFAULT;
5731da177e4SLinus Torvalds
5741da177e4SLinus Torvalds lock_sock(sk);
5753200392bSDavid Miller ax25 = sk_to_ax25(sk);
5761da177e4SLinus Torvalds
5771da177e4SLinus Torvalds switch (optname) {
5781da177e4SLinus Torvalds case AX25_WINDOW:
5791da177e4SLinus Torvalds if (ax25->modulus == AX25_MODULUS) {
5801da177e4SLinus Torvalds if (opt < 1 || opt > 7) {
5811da177e4SLinus Torvalds res = -EINVAL;
5821da177e4SLinus Torvalds break;
5831da177e4SLinus Torvalds }
5841da177e4SLinus Torvalds } else {
5851da177e4SLinus Torvalds if (opt < 1 || opt > 63) {
5861da177e4SLinus Torvalds res = -EINVAL;
5871da177e4SLinus Torvalds break;
5881da177e4SLinus Torvalds }
5891da177e4SLinus Torvalds }
5901da177e4SLinus Torvalds ax25->window = opt;
5911da177e4SLinus Torvalds break;
5921da177e4SLinus Torvalds
5931da177e4SLinus Torvalds case AX25_T1:
59493719370SDan Carpenter if (opt < 1 || opt > UINT_MAX / HZ) {
5951da177e4SLinus Torvalds res = -EINVAL;
5961da177e4SLinus Torvalds break;
5971da177e4SLinus Torvalds }
598f16f3026SEric Dumazet ax25->rtt = (opt * HZ) >> 1;
5991da177e4SLinus Torvalds ax25->t1 = opt * HZ;
6001da177e4SLinus Torvalds break;
6011da177e4SLinus Torvalds
6021da177e4SLinus Torvalds case AX25_T2:
60393719370SDan Carpenter if (opt < 1 || opt > UINT_MAX / HZ) {
6041da177e4SLinus Torvalds res = -EINVAL;
6051da177e4SLinus Torvalds break;
6061da177e4SLinus Torvalds }
6071da177e4SLinus Torvalds ax25->t2 = opt * HZ;
6081da177e4SLinus Torvalds break;
6091da177e4SLinus Torvalds
6101da177e4SLinus Torvalds case AX25_N2:
6111da177e4SLinus Torvalds if (opt < 1 || opt > 31) {
6121da177e4SLinus Torvalds res = -EINVAL;
6131da177e4SLinus Torvalds break;
6141da177e4SLinus Torvalds }
6151da177e4SLinus Torvalds ax25->n2 = opt;
6161da177e4SLinus Torvalds break;
6171da177e4SLinus Torvalds
6181da177e4SLinus Torvalds case AX25_T3:
61993719370SDan Carpenter if (opt < 1 || opt > UINT_MAX / HZ) {
6201da177e4SLinus Torvalds res = -EINVAL;
6211da177e4SLinus Torvalds break;
6221da177e4SLinus Torvalds }
6231da177e4SLinus Torvalds ax25->t3 = opt * HZ;
6241da177e4SLinus Torvalds break;
6251da177e4SLinus Torvalds
6261da177e4SLinus Torvalds case AX25_IDLE:
62793719370SDan Carpenter if (opt > UINT_MAX / (60 * HZ)) {
6281da177e4SLinus Torvalds res = -EINVAL;
6291da177e4SLinus Torvalds break;
6301da177e4SLinus Torvalds }
6311da177e4SLinus Torvalds ax25->idle = opt * 60 * HZ;
6321da177e4SLinus Torvalds break;
6331da177e4SLinus Torvalds
6341da177e4SLinus Torvalds case AX25_BACKOFF:
635ba1cffe0SXi Wang if (opt > 2) {
6361da177e4SLinus Torvalds res = -EINVAL;
6371da177e4SLinus Torvalds break;
6381da177e4SLinus Torvalds }
6391da177e4SLinus Torvalds ax25->backoff = opt;
6401da177e4SLinus Torvalds break;
6411da177e4SLinus Torvalds
6421da177e4SLinus Torvalds case AX25_EXTSEQ:
6431da177e4SLinus Torvalds ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS;
6441da177e4SLinus Torvalds break;
6451da177e4SLinus Torvalds
6461da177e4SLinus Torvalds case AX25_PIDINCL:
6471da177e4SLinus Torvalds ax25->pidincl = opt ? 1 : 0;
6481da177e4SLinus Torvalds break;
6491da177e4SLinus Torvalds
6501da177e4SLinus Torvalds case AX25_IAMDIGI:
6511da177e4SLinus Torvalds ax25->iamdigi = opt ? 1 : 0;
6521da177e4SLinus Torvalds break;
6531da177e4SLinus Torvalds
6541da177e4SLinus Torvalds case AX25_PACLEN:
6551da177e4SLinus Torvalds if (opt < 16 || opt > 65535) {
6561da177e4SLinus Torvalds res = -EINVAL;
6571da177e4SLinus Torvalds break;
6581da177e4SLinus Torvalds }
6591da177e4SLinus Torvalds ax25->paclen = opt;
6601da177e4SLinus Torvalds break;
6611da177e4SLinus Torvalds
6621da177e4SLinus Torvalds case SO_BINDTODEVICE:
663687775ceSEric Dumazet if (optlen > IFNAMSIZ - 1)
664687775ceSEric Dumazet optlen = IFNAMSIZ - 1;
665687775ceSEric Dumazet
666687775ceSEric Dumazet memset(devname, 0, sizeof(devname));
6672f72291dSRalf Baechle
668a7b75c5aSChristoph Hellwig if (copy_from_sockptr(devname, optval, optlen)) {
6691da177e4SLinus Torvalds res = -EFAULT;
6701da177e4SLinus Torvalds break;
6711da177e4SLinus Torvalds }
6721da177e4SLinus Torvalds
6731da177e4SLinus Torvalds if (sk->sk_type == SOCK_SEQPACKET &&
6741da177e4SLinus Torvalds (sock->state != SS_UNCONNECTED ||
6751da177e4SLinus Torvalds sk->sk_state == TCP_LISTEN)) {
6761da177e4SLinus Torvalds res = -EADDRNOTAVAIL;
6772f72291dSRalf Baechle break;
6782f72291dSRalf Baechle }
6792f72291dSRalf Baechle
6807705d8a7SEric Dumazet rcu_read_lock();
6817705d8a7SEric Dumazet dev = dev_get_by_name_rcu(&init_net, devname);
6822f72291dSRalf Baechle if (!dev) {
6837705d8a7SEric Dumazet rcu_read_unlock();
6842f72291dSRalf Baechle res = -ENODEV;
6851da177e4SLinus Torvalds break;
6861da177e4SLinus Torvalds }
6871da177e4SLinus Torvalds
688*94a0de22SMurad Masimov if (ax25->ax25_dev) {
689*94a0de22SMurad Masimov if (dev == ax25->ax25_dev->dev) {
690*94a0de22SMurad Masimov rcu_read_unlock();
691*94a0de22SMurad Masimov break;
692*94a0de22SMurad Masimov }
693*94a0de22SMurad Masimov netdev_put(ax25->ax25_dev->dev, &ax25->dev_tracker);
694*94a0de22SMurad Masimov ax25_dev_put(ax25->ax25_dev);
695*94a0de22SMurad Masimov }
696*94a0de22SMurad Masimov
6971da177e4SLinus Torvalds ax25->ax25_dev = ax25_dev_ax25dev(dev);
698c4335704SCong Wang if (!ax25->ax25_dev) {
6997705d8a7SEric Dumazet rcu_read_unlock();
700c4335704SCong Wang res = -ENODEV;
701c4335704SCong Wang break;
702c4335704SCong Wang }
7031da177e4SLinus Torvalds ax25_fillin_cb(ax25, ax25->ax25_dev);
704*94a0de22SMurad Masimov netdev_hold(dev, &ax25->dev_tracker, GFP_ATOMIC);
705*94a0de22SMurad Masimov ax25_dev_hold(ax25->ax25_dev);
7067705d8a7SEric Dumazet rcu_read_unlock();
7071da177e4SLinus Torvalds break;
7081da177e4SLinus Torvalds
7091da177e4SLinus Torvalds default:
7101da177e4SLinus Torvalds res = -ENOPROTOOPT;
7111da177e4SLinus Torvalds }
7121da177e4SLinus Torvalds release_sock(sk);
7131da177e4SLinus Torvalds
7141da177e4SLinus Torvalds return res;
7151da177e4SLinus Torvalds }
7161da177e4SLinus Torvalds
ax25_getsockopt(struct socket * sock,int level,int optname,char __user * optval,int __user * optlen)7171da177e4SLinus Torvalds static int ax25_getsockopt(struct socket *sock, int level, int optname,
7181da177e4SLinus Torvalds char __user *optval, int __user *optlen)
7191da177e4SLinus Torvalds {
7201da177e4SLinus Torvalds struct sock *sk = sock->sk;
7211da177e4SLinus Torvalds ax25_cb *ax25;
7221da177e4SLinus Torvalds struct ax25_dev *ax25_dev;
7231da177e4SLinus Torvalds char devname[IFNAMSIZ];
7241da177e4SLinus Torvalds void *valptr;
7251da177e4SLinus Torvalds int val = 0;
7261da177e4SLinus Torvalds int maxlen, length;
7271da177e4SLinus Torvalds
7281da177e4SLinus Torvalds if (level != SOL_AX25)
7291da177e4SLinus Torvalds return -ENOPROTOOPT;
7301da177e4SLinus Torvalds
7311da177e4SLinus Torvalds if (get_user(maxlen, optlen))
7321da177e4SLinus Torvalds return -EFAULT;
7331da177e4SLinus Torvalds
7341da177e4SLinus Torvalds if (maxlen < 1)
7351da177e4SLinus Torvalds return -EFAULT;
7361da177e4SLinus Torvalds
7371d7322f2SLi zeming valptr = &val;
7381da177e4SLinus Torvalds length = min_t(unsigned int, maxlen, sizeof(int));
7391da177e4SLinus Torvalds
7401da177e4SLinus Torvalds lock_sock(sk);
7413200392bSDavid Miller ax25 = sk_to_ax25(sk);
7421da177e4SLinus Torvalds
7431da177e4SLinus Torvalds switch (optname) {
7441da177e4SLinus Torvalds case AX25_WINDOW:
7451da177e4SLinus Torvalds val = ax25->window;
7461da177e4SLinus Torvalds break;
7471da177e4SLinus Torvalds
7481da177e4SLinus Torvalds case AX25_T1:
7491da177e4SLinus Torvalds val = ax25->t1 / HZ;
7501da177e4SLinus Torvalds break;
7511da177e4SLinus Torvalds
7521da177e4SLinus Torvalds case AX25_T2:
7531da177e4SLinus Torvalds val = ax25->t2 / HZ;
7541da177e4SLinus Torvalds break;
7551da177e4SLinus Torvalds
7561da177e4SLinus Torvalds case AX25_N2:
7571da177e4SLinus Torvalds val = ax25->n2;
7581da177e4SLinus Torvalds break;
7591da177e4SLinus Torvalds
7601da177e4SLinus Torvalds case AX25_T3:
7611da177e4SLinus Torvalds val = ax25->t3 / HZ;
7621da177e4SLinus Torvalds break;
7631da177e4SLinus Torvalds
7641da177e4SLinus Torvalds case AX25_IDLE:
7651da177e4SLinus Torvalds val = ax25->idle / (60 * HZ);
7661da177e4SLinus Torvalds break;
7671da177e4SLinus Torvalds
7681da177e4SLinus Torvalds case AX25_BACKOFF:
7691da177e4SLinus Torvalds val = ax25->backoff;
7701da177e4SLinus Torvalds break;
7711da177e4SLinus Torvalds
7721da177e4SLinus Torvalds case AX25_EXTSEQ:
7731da177e4SLinus Torvalds val = (ax25->modulus == AX25_EMODULUS);
7741da177e4SLinus Torvalds break;
7751da177e4SLinus Torvalds
7761da177e4SLinus Torvalds case AX25_PIDINCL:
7771da177e4SLinus Torvalds val = ax25->pidincl;
7781da177e4SLinus Torvalds break;
7791da177e4SLinus Torvalds
7801da177e4SLinus Torvalds case AX25_IAMDIGI:
7811da177e4SLinus Torvalds val = ax25->iamdigi;
7821da177e4SLinus Torvalds break;
7831da177e4SLinus Torvalds
7841da177e4SLinus Torvalds case AX25_PACLEN:
7851da177e4SLinus Torvalds val = ax25->paclen;
7861da177e4SLinus Torvalds break;
7871da177e4SLinus Torvalds
7881da177e4SLinus Torvalds case SO_BINDTODEVICE:
7891da177e4SLinus Torvalds ax25_dev = ax25->ax25_dev;
7901da177e4SLinus Torvalds
7911da177e4SLinus Torvalds if (ax25_dev != NULL && ax25_dev->dev != NULL) {
7926164b5e3SWolfram Sang strscpy(devname, ax25_dev->dev->name, sizeof(devname));
7931da177e4SLinus Torvalds length = strlen(devname) + 1;
7941da177e4SLinus Torvalds } else {
7951da177e4SLinus Torvalds *devname = '\0';
7961da177e4SLinus Torvalds length = 1;
7971da177e4SLinus Torvalds }
7981da177e4SLinus Torvalds
7991d7322f2SLi zeming valptr = devname;
8001da177e4SLinus Torvalds break;
8011da177e4SLinus Torvalds
8021da177e4SLinus Torvalds default:
8031da177e4SLinus Torvalds release_sock(sk);
8041da177e4SLinus Torvalds return -ENOPROTOOPT;
8051da177e4SLinus Torvalds }
8061da177e4SLinus Torvalds release_sock(sk);
8071da177e4SLinus Torvalds
8081da177e4SLinus Torvalds if (put_user(length, optlen))
8091da177e4SLinus Torvalds return -EFAULT;
8101da177e4SLinus Torvalds
8111da177e4SLinus Torvalds return copy_to_user(optval, valptr, length) ? -EFAULT : 0;
8121da177e4SLinus Torvalds }
8131da177e4SLinus Torvalds
ax25_listen(struct socket * sock,int backlog)8141da177e4SLinus Torvalds static int ax25_listen(struct socket *sock, int backlog)
8151da177e4SLinus Torvalds {
8161da177e4SLinus Torvalds struct sock *sk = sock->sk;
8171da177e4SLinus Torvalds int res = 0;
8181da177e4SLinus Torvalds
8191da177e4SLinus Torvalds lock_sock(sk);
8201da177e4SLinus Torvalds if (sk->sk_type == SOCK_SEQPACKET && sk->sk_state != TCP_LISTEN) {
8211da177e4SLinus Torvalds sk->sk_max_ack_backlog = backlog;
8221da177e4SLinus Torvalds sk->sk_state = TCP_LISTEN;
8231da177e4SLinus Torvalds goto out;
8241da177e4SLinus Torvalds }
8251da177e4SLinus Torvalds res = -EOPNOTSUPP;
8261da177e4SLinus Torvalds
8271da177e4SLinus Torvalds out:
8281da177e4SLinus Torvalds release_sock(sk);
8291da177e4SLinus Torvalds
8301da177e4SLinus Torvalds return res;
8311da177e4SLinus Torvalds }
8321da177e4SLinus Torvalds
8331da177e4SLinus Torvalds /*
8341da177e4SLinus Torvalds * XXX: when creating ax25_sock we should update the .obj_size setting
8351da177e4SLinus Torvalds * below.
8361da177e4SLinus Torvalds */
8371da177e4SLinus Torvalds static struct proto ax25_proto = {
8381da177e4SLinus Torvalds .name = "AX25",
8391da177e4SLinus Torvalds .owner = THIS_MODULE,
8403200392bSDavid Miller .obj_size = sizeof(struct ax25_sock),
8411da177e4SLinus Torvalds };
8421da177e4SLinus Torvalds
ax25_create(struct net * net,struct socket * sock,int protocol,int kern)8433f378b68SEric Paris static int ax25_create(struct net *net, struct socket *sock, int protocol,
8443f378b68SEric Paris int kern)
8451da177e4SLinus Torvalds {
8461da177e4SLinus Torvalds struct sock *sk;
8471da177e4SLinus Torvalds ax25_cb *ax25;
8481da177e4SLinus Torvalds
849e9cdced7SMat Martineau if (protocol < 0 || protocol > U8_MAX)
85079462ad0SHannes Frederic Sowa return -EINVAL;
85179462ad0SHannes Frederic Sowa
85209ad9bc7SOctavian Purdila if (!net_eq(net, &init_net))
8531b8d7ae4SEric W. Biederman return -EAFNOSUPPORT;
8541b8d7ae4SEric W. Biederman
8551da177e4SLinus Torvalds switch (sock->type) {
8561da177e4SLinus Torvalds case SOCK_DGRAM:
8571da177e4SLinus Torvalds if (protocol == 0 || protocol == PF_AX25)
8581da177e4SLinus Torvalds protocol = AX25_P_TEXT;
8591da177e4SLinus Torvalds break;
8601da177e4SLinus Torvalds
8611da177e4SLinus Torvalds case SOCK_SEQPACKET:
8621da177e4SLinus Torvalds switch (protocol) {
8631da177e4SLinus Torvalds case 0:
8641da177e4SLinus Torvalds case PF_AX25: /* For CLX */
8651da177e4SLinus Torvalds protocol = AX25_P_TEXT;
8661da177e4SLinus Torvalds break;
8671da177e4SLinus Torvalds case AX25_P_SEGMENT:
8681da177e4SLinus Torvalds #ifdef CONFIG_INET
8691da177e4SLinus Torvalds case AX25_P_ARP:
8701da177e4SLinus Torvalds case AX25_P_IP:
8711da177e4SLinus Torvalds #endif
8721da177e4SLinus Torvalds #ifdef CONFIG_NETROM
8731da177e4SLinus Torvalds case AX25_P_NETROM:
8741da177e4SLinus Torvalds #endif
8751da177e4SLinus Torvalds #ifdef CONFIG_ROSE
8761da177e4SLinus Torvalds case AX25_P_ROSE:
8771da177e4SLinus Torvalds #endif
8781da177e4SLinus Torvalds return -ESOCKTNOSUPPORT;
8791da177e4SLinus Torvalds #ifdef CONFIG_NETROM_MODULE
8801da177e4SLinus Torvalds case AX25_P_NETROM:
8811da177e4SLinus Torvalds if (ax25_protocol_is_registered(AX25_P_NETROM))
8821da177e4SLinus Torvalds return -ESOCKTNOSUPPORT;
883ef764a13SAlan Cox break;
8841da177e4SLinus Torvalds #endif
8851da177e4SLinus Torvalds #ifdef CONFIG_ROSE_MODULE
8861da177e4SLinus Torvalds case AX25_P_ROSE:
8871da177e4SLinus Torvalds if (ax25_protocol_is_registered(AX25_P_ROSE))
8881da177e4SLinus Torvalds return -ESOCKTNOSUPPORT;
8895646fba6SGustavo A. R. Silva break;
8901da177e4SLinus Torvalds #endif
8911da177e4SLinus Torvalds default:
8921da177e4SLinus Torvalds break;
8931da177e4SLinus Torvalds }
8941da177e4SLinus Torvalds break;
8951da177e4SLinus Torvalds
8961da177e4SLinus Torvalds case SOCK_RAW:
8970614e2b7SOri Nimron if (!capable(CAP_NET_RAW))
8980614e2b7SOri Nimron return -EPERM;
8991da177e4SLinus Torvalds break;
9001da177e4SLinus Torvalds default:
9011da177e4SLinus Torvalds return -ESOCKTNOSUPPORT;
9021da177e4SLinus Torvalds }
9031da177e4SLinus Torvalds
90411aa9c28SEric W. Biederman sk = sk_alloc(net, PF_AX25, GFP_ATOMIC, &ax25_proto, kern);
9056257ff21SPavel Emelyanov if (sk == NULL)
9061da177e4SLinus Torvalds return -ENOMEM;
9071da177e4SLinus Torvalds
9083200392bSDavid Miller ax25 = ax25_sk(sk)->cb = ax25_create_cb();
9091da177e4SLinus Torvalds if (!ax25) {
9101da177e4SLinus Torvalds sk_free(sk);
9111da177e4SLinus Torvalds return -ENOMEM;
9121da177e4SLinus Torvalds }
9131da177e4SLinus Torvalds
9141da177e4SLinus Torvalds sock_init_data(sock, sk);
9151da177e4SLinus Torvalds
9161da177e4SLinus Torvalds sk->sk_destruct = ax25_free_sock;
9171da177e4SLinus Torvalds sock->ops = &ax25_proto_ops;
9181da177e4SLinus Torvalds sk->sk_protocol = protocol;
9191da177e4SLinus Torvalds
9201da177e4SLinus Torvalds ax25->sk = sk;
9211da177e4SLinus Torvalds
9221da177e4SLinus Torvalds return 0;
9231da177e4SLinus Torvalds }
9241da177e4SLinus Torvalds
ax25_make_new(struct sock * osk,struct ax25_dev * ax25_dev)9251da177e4SLinus Torvalds struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
9261da177e4SLinus Torvalds {
9271da177e4SLinus Torvalds struct sock *sk;
9281da177e4SLinus Torvalds ax25_cb *ax25, *oax25;
9291da177e4SLinus Torvalds
93011aa9c28SEric W. Biederman sk = sk_alloc(sock_net(osk), PF_AX25, GFP_ATOMIC, osk->sk_prot, 0);
9316257ff21SPavel Emelyanov if (sk == NULL)
9321da177e4SLinus Torvalds return NULL;
9331da177e4SLinus Torvalds
9341da177e4SLinus Torvalds if ((ax25 = ax25_create_cb()) == NULL) {
9351da177e4SLinus Torvalds sk_free(sk);
9361da177e4SLinus Torvalds return NULL;
9371da177e4SLinus Torvalds }
9381da177e4SLinus Torvalds
9391da177e4SLinus Torvalds switch (osk->sk_type) {
9401da177e4SLinus Torvalds case SOCK_DGRAM:
9411da177e4SLinus Torvalds break;
9421da177e4SLinus Torvalds case SOCK_SEQPACKET:
9431da177e4SLinus Torvalds break;
9441da177e4SLinus Torvalds default:
9451da177e4SLinus Torvalds sk_free(sk);
9461da177e4SLinus Torvalds ax25_cb_put(ax25);
9471da177e4SLinus Torvalds return NULL;
9481da177e4SLinus Torvalds }
9491da177e4SLinus Torvalds
9501da177e4SLinus Torvalds sock_init_data(NULL, sk);
9511da177e4SLinus Torvalds
9521da177e4SLinus Torvalds sk->sk_type = osk->sk_type;
9531da177e4SLinus Torvalds sk->sk_priority = osk->sk_priority;
9541da177e4SLinus Torvalds sk->sk_protocol = osk->sk_protocol;
9551da177e4SLinus Torvalds sk->sk_rcvbuf = osk->sk_rcvbuf;
9561da177e4SLinus Torvalds sk->sk_sndbuf = osk->sk_sndbuf;
9571da177e4SLinus Torvalds sk->sk_state = TCP_ESTABLISHED;
95853b924b3SRalf Baechle sock_copy_flags(sk, osk);
9591da177e4SLinus Torvalds
9603200392bSDavid Miller oax25 = sk_to_ax25(osk);
9611da177e4SLinus Torvalds
9621da177e4SLinus Torvalds ax25->modulus = oax25->modulus;
9631da177e4SLinus Torvalds ax25->backoff = oax25->backoff;
9641da177e4SLinus Torvalds ax25->pidincl = oax25->pidincl;
9651da177e4SLinus Torvalds ax25->iamdigi = oax25->iamdigi;
9661da177e4SLinus Torvalds ax25->rtt = oax25->rtt;
9671da177e4SLinus Torvalds ax25->t1 = oax25->t1;
9681da177e4SLinus Torvalds ax25->t2 = oax25->t2;
9691da177e4SLinus Torvalds ax25->t3 = oax25->t3;
9701da177e4SLinus Torvalds ax25->n2 = oax25->n2;
9711da177e4SLinus Torvalds ax25->idle = oax25->idle;
9721da177e4SLinus Torvalds ax25->paclen = oax25->paclen;
9731da177e4SLinus Torvalds ax25->window = oax25->window;
9741da177e4SLinus Torvalds
9751da177e4SLinus Torvalds ax25->ax25_dev = ax25_dev;
9761da177e4SLinus Torvalds ax25->source_addr = oax25->source_addr;
9771da177e4SLinus Torvalds
9781da177e4SLinus Torvalds if (oax25->digipeat != NULL) {
9790459d70aSArnaldo Carvalho de Melo ax25->digipeat = kmemdup(oax25->digipeat, sizeof(ax25_digi),
9800459d70aSArnaldo Carvalho de Melo GFP_ATOMIC);
9810459d70aSArnaldo Carvalho de Melo if (ax25->digipeat == NULL) {
9821da177e4SLinus Torvalds sk_free(sk);
9831da177e4SLinus Torvalds ax25_cb_put(ax25);
9841da177e4SLinus Torvalds return NULL;
9851da177e4SLinus Torvalds }
9861da177e4SLinus Torvalds }
9871da177e4SLinus Torvalds
9883200392bSDavid Miller ax25_sk(sk)->cb = ax25;
9898c185ab6SJarek Poplawski sk->sk_destruct = ax25_free_sock;
9901da177e4SLinus Torvalds ax25->sk = sk;
9911da177e4SLinus Torvalds
9921da177e4SLinus Torvalds return sk;
9931da177e4SLinus Torvalds }
9941da177e4SLinus Torvalds
ax25_release(struct socket * sock)9951da177e4SLinus Torvalds static int ax25_release(struct socket *sock)
9961da177e4SLinus Torvalds {
9971da177e4SLinus Torvalds struct sock *sk = sock->sk;
9981da177e4SLinus Torvalds ax25_cb *ax25;
9999fd75b66SDuoming Zhou ax25_dev *ax25_dev;
10001da177e4SLinus Torvalds
10011da177e4SLinus Torvalds if (sk == NULL)
10021da177e4SLinus Torvalds return 0;
10031da177e4SLinus Torvalds
10041da177e4SLinus Torvalds sock_hold(sk);
10051da177e4SLinus Torvalds lock_sock(sk);
10069fd75b66SDuoming Zhou sock_orphan(sk);
10073200392bSDavid Miller ax25 = sk_to_ax25(sk);
10089fd75b66SDuoming Zhou ax25_dev = ax25->ax25_dev;
10091da177e4SLinus Torvalds
10101da177e4SLinus Torvalds if (sk->sk_type == SOCK_SEQPACKET) {
10111da177e4SLinus Torvalds switch (ax25->state) {
10121da177e4SLinus Torvalds case AX25_STATE_0:
10137d8a3a47SDuoming Zhou if (!sock_flag(ax25->sk, SOCK_DEAD)) {
10141da177e4SLinus Torvalds release_sock(sk);
10151da177e4SLinus Torvalds ax25_disconnect(ax25, 0);
10161da177e4SLinus Torvalds lock_sock(sk);
10177d8a3a47SDuoming Zhou }
10181da177e4SLinus Torvalds ax25_destroy_socket(ax25);
10191da177e4SLinus Torvalds break;
10201da177e4SLinus Torvalds
10211da177e4SLinus Torvalds case AX25_STATE_1:
10221da177e4SLinus Torvalds case AX25_STATE_2:
10231da177e4SLinus Torvalds ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
10241da177e4SLinus Torvalds release_sock(sk);
10251da177e4SLinus Torvalds ax25_disconnect(ax25, 0);
10261da177e4SLinus Torvalds lock_sock(sk);
10274a7d99eaSBasil Gunn if (!sock_flag(ax25->sk, SOCK_DESTROY))
10281da177e4SLinus Torvalds ax25_destroy_socket(ax25);
10291da177e4SLinus Torvalds break;
10301da177e4SLinus Torvalds
10311da177e4SLinus Torvalds case AX25_STATE_3:
10321da177e4SLinus Torvalds case AX25_STATE_4:
10331da177e4SLinus Torvalds ax25_clear_queues(ax25);
10341da177e4SLinus Torvalds ax25->n2count = 0;
10351da177e4SLinus Torvalds
10361da177e4SLinus Torvalds switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
10371da177e4SLinus Torvalds case AX25_PROTO_STD_SIMPLEX:
10381da177e4SLinus Torvalds case AX25_PROTO_STD_DUPLEX:
10391da177e4SLinus Torvalds ax25_send_control(ax25,
10401da177e4SLinus Torvalds AX25_DISC,
10411da177e4SLinus Torvalds AX25_POLLON,
10421da177e4SLinus Torvalds AX25_COMMAND);
10431da177e4SLinus Torvalds ax25_stop_t2timer(ax25);
10441da177e4SLinus Torvalds ax25_stop_t3timer(ax25);
10451da177e4SLinus Torvalds ax25_stop_idletimer(ax25);
10461da177e4SLinus Torvalds break;
10471da177e4SLinus Torvalds #ifdef CONFIG_AX25_DAMA_SLAVE
10481da177e4SLinus Torvalds case AX25_PROTO_DAMA_SLAVE:
10491da177e4SLinus Torvalds ax25_stop_t3timer(ax25);
10501da177e4SLinus Torvalds ax25_stop_idletimer(ax25);
10511da177e4SLinus Torvalds break;
10521da177e4SLinus Torvalds #endif
10531da177e4SLinus Torvalds }
10541da177e4SLinus Torvalds ax25_calculate_t1(ax25);
10551da177e4SLinus Torvalds ax25_start_t1timer(ax25);
10561da177e4SLinus Torvalds ax25->state = AX25_STATE_2;
10571da177e4SLinus Torvalds sk->sk_state = TCP_CLOSE;
10581da177e4SLinus Torvalds sk->sk_shutdown |= SEND_SHUTDOWN;
10591da177e4SLinus Torvalds sk->sk_state_change(sk);
10601da177e4SLinus Torvalds sock_set_flag(sk, SOCK_DESTROY);
10611da177e4SLinus Torvalds break;
10621da177e4SLinus Torvalds
10631da177e4SLinus Torvalds default:
10641da177e4SLinus Torvalds break;
10651da177e4SLinus Torvalds }
10661da177e4SLinus Torvalds } else {
10671da177e4SLinus Torvalds sk->sk_state = TCP_CLOSE;
10681da177e4SLinus Torvalds sk->sk_shutdown |= SEND_SHUTDOWN;
10691da177e4SLinus Torvalds sk->sk_state_change(sk);
10701da177e4SLinus Torvalds ax25_destroy_socket(ax25);
10711da177e4SLinus Torvalds }
10725352a761SDuoming Zhou if (ax25_dev) {
10737d8a3a47SDuoming Zhou if (!ax25_dev->device_up) {
107482e31755SDuoming Zhou del_timer_sync(&ax25->timer);
107582e31755SDuoming Zhou del_timer_sync(&ax25->t1timer);
107682e31755SDuoming Zhou del_timer_sync(&ax25->t2timer);
107782e31755SDuoming Zhou del_timer_sync(&ax25->t3timer);
107882e31755SDuoming Zhou del_timer_sync(&ax25->idletimer);
10797d8a3a47SDuoming Zhou }
10807c6327c7SPaolo Abeni netdev_put(ax25_dev->dev, &ax25->dev_tracker);
10815352a761SDuoming Zhou ax25_dev_put(ax25_dev);
10825352a761SDuoming Zhou }
10831da177e4SLinus Torvalds
10841da177e4SLinus Torvalds sock->sk = NULL;
10851da177e4SLinus Torvalds release_sock(sk);
10861da177e4SLinus Torvalds sock_put(sk);
10871da177e4SLinus Torvalds
10881da177e4SLinus Torvalds return 0;
10891da177e4SLinus Torvalds }
10901da177e4SLinus Torvalds
10911da177e4SLinus Torvalds /*
10921da177e4SLinus Torvalds * We support a funny extension here so you can (as root) give any callsign
10931da177e4SLinus Torvalds * digipeated via a local address as source. This hack is obsolete now
10941da177e4SLinus Torvalds * that we've implemented support for SO_BINDTODEVICE. It is however small
10951da177e4SLinus Torvalds * and trivially backward compatible.
10961da177e4SLinus Torvalds */
ax25_bind(struct socket * sock,struct sockaddr * uaddr,int addr_len)10971da177e4SLinus Torvalds static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
10981da177e4SLinus Torvalds {
10991da177e4SLinus Torvalds struct sock *sk = sock->sk;
11001da177e4SLinus Torvalds struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
11011da177e4SLinus Torvalds ax25_dev *ax25_dev = NULL;
110201d7dd0eSRalf Baechle ax25_uid_assoc *user;
110301d7dd0eSRalf Baechle ax25_address call;
11041da177e4SLinus Torvalds ax25_cb *ax25;
11051da177e4SLinus Torvalds int err = 0;
11061da177e4SLinus Torvalds
11071da177e4SLinus Torvalds if (addr_len != sizeof(struct sockaddr_ax25) &&
11081987e7b4Smaximilian attems addr_len != sizeof(struct full_sockaddr_ax25))
11091987e7b4Smaximilian attems /* support for old structure may go away some time
11101987e7b4Smaximilian attems * ax25_bind(): uses old (6 digipeater) socket structure.
11111987e7b4Smaximilian attems */
11121da177e4SLinus Torvalds if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
11131987e7b4Smaximilian attems (addr_len > sizeof(struct full_sockaddr_ax25)))
11141da177e4SLinus Torvalds return -EINVAL;
11151da177e4SLinus Torvalds
11161da177e4SLinus Torvalds if (addr->fsa_ax25.sax25_family != AF_AX25)
11171da177e4SLinus Torvalds return -EINVAL;
11181da177e4SLinus Torvalds
111973400407SDavid Howells user = ax25_findbyuid(current_euid());
112001d7dd0eSRalf Baechle if (user) {
112101d7dd0eSRalf Baechle call = user->call;
112201d7dd0eSRalf Baechle ax25_uid_put(user);
112301d7dd0eSRalf Baechle } else {
112401d7dd0eSRalf Baechle if (ax25_uid_policy && !capable(CAP_NET_ADMIN))
11251da177e4SLinus Torvalds return -EACCES;
112601d7dd0eSRalf Baechle
112701d7dd0eSRalf Baechle call = addr->fsa_ax25.sax25_call;
11281da177e4SLinus Torvalds }
11291da177e4SLinus Torvalds
11301da177e4SLinus Torvalds lock_sock(sk);
11311da177e4SLinus Torvalds
11323200392bSDavid Miller ax25 = sk_to_ax25(sk);
11331da177e4SLinus Torvalds if (!sock_flag(sk, SOCK_ZAPPED)) {
11341da177e4SLinus Torvalds err = -EINVAL;
11351da177e4SLinus Torvalds goto out;
11361da177e4SLinus Torvalds }
11371da177e4SLinus Torvalds
113801d7dd0eSRalf Baechle ax25->source_addr = call;
11391da177e4SLinus Torvalds
11401da177e4SLinus Torvalds /*
11411da177e4SLinus Torvalds * User already set interface with SO_BINDTODEVICE
11421da177e4SLinus Torvalds */
11431da177e4SLinus Torvalds if (ax25->ax25_dev != NULL)
11441da177e4SLinus Torvalds goto done;
11451da177e4SLinus Torvalds
11461da177e4SLinus Torvalds if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) {
11471da177e4SLinus Torvalds if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 &&
11481da177e4SLinus Torvalds (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) {
11491da177e4SLinus Torvalds err = -EADDRNOTAVAIL;
11501da177e4SLinus Torvalds goto out;
11511da177e4SLinus Torvalds }
11521da177e4SLinus Torvalds } else {
11531da177e4SLinus Torvalds if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) {
11541da177e4SLinus Torvalds err = -EADDRNOTAVAIL;
11551da177e4SLinus Torvalds goto out;
11561da177e4SLinus Torvalds }
11571da177e4SLinus Torvalds }
11581da177e4SLinus Torvalds
1159feef318cSDuoming Zhou if (ax25_dev) {
11601da177e4SLinus Torvalds ax25_fillin_cb(ax25, ax25_dev);
11617c6327c7SPaolo Abeni netdev_hold(ax25_dev->dev, &ax25->dev_tracker, GFP_ATOMIC);
1162feef318cSDuoming Zhou }
11631da177e4SLinus Torvalds
11641da177e4SLinus Torvalds done:
11651da177e4SLinus Torvalds ax25_cb_add(ax25);
11661da177e4SLinus Torvalds sock_reset_flag(sk, SOCK_ZAPPED);
11671da177e4SLinus Torvalds
11681da177e4SLinus Torvalds out:
11691da177e4SLinus Torvalds release_sock(sk);
11701da177e4SLinus Torvalds
117149339ccaSJulia Lawall return err;
11721da177e4SLinus Torvalds }
11731da177e4SLinus Torvalds
11741da177e4SLinus Torvalds /*
11751da177e4SLinus Torvalds * FIXME: nonblock behaviour looks like it may have a bug.
11761da177e4SLinus Torvalds */
ax25_connect(struct socket * sock,struct sockaddr * uaddr,int addr_len,int flags)1177c9266b99SRalf Baechle static int __must_check ax25_connect(struct socket *sock,
1178c9266b99SRalf Baechle struct sockaddr *uaddr, int addr_len, int flags)
11791da177e4SLinus Torvalds {
11801da177e4SLinus Torvalds struct sock *sk = sock->sk;
11813200392bSDavid Miller ax25_cb *ax25 = sk_to_ax25(sk), *ax25t;
11821da177e4SLinus Torvalds struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
11831da177e4SLinus Torvalds ax25_digi *digi = NULL;
11841da177e4SLinus Torvalds int ct = 0, err = 0;
11851da177e4SLinus Torvalds
11861da177e4SLinus Torvalds /*
11871da177e4SLinus Torvalds * some sanity checks. code further down depends on this
11881da177e4SLinus Torvalds */
11891da177e4SLinus Torvalds
119027d1cba2Smaximilian attems if (addr_len == sizeof(struct sockaddr_ax25))
119127d1cba2Smaximilian attems /* support for this will go away in early 2.5.x
119227d1cba2Smaximilian attems * ax25_connect(): uses obsolete socket structure
119327d1cba2Smaximilian attems */
119427d1cba2Smaximilian attems ;
119527d1cba2Smaximilian attems else if (addr_len != sizeof(struct full_sockaddr_ax25))
119627d1cba2Smaximilian attems /* support for old structure may go away some time
119727d1cba2Smaximilian attems * ax25_connect(): uses old (6 digipeater) socket structure.
119827d1cba2Smaximilian attems */
11991da177e4SLinus Torvalds if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
120027d1cba2Smaximilian attems (addr_len > sizeof(struct full_sockaddr_ax25)))
12011da177e4SLinus Torvalds return -EINVAL;
12021da177e4SLinus Torvalds
12031da177e4SLinus Torvalds
12041da177e4SLinus Torvalds if (fsa->fsa_ax25.sax25_family != AF_AX25)
12051da177e4SLinus Torvalds return -EINVAL;
12061da177e4SLinus Torvalds
12071da177e4SLinus Torvalds lock_sock(sk);
12081da177e4SLinus Torvalds
12091da177e4SLinus Torvalds /* deal with restarts */
12101da177e4SLinus Torvalds if (sock->state == SS_CONNECTING) {
12111da177e4SLinus Torvalds switch (sk->sk_state) {
12121da177e4SLinus Torvalds case TCP_SYN_SENT: /* still trying */
12131da177e4SLinus Torvalds err = -EINPROGRESS;
121475606dc6SRalf Baechle goto out_release;
12151da177e4SLinus Torvalds
12161da177e4SLinus Torvalds case TCP_ESTABLISHED: /* connection established */
12171da177e4SLinus Torvalds sock->state = SS_CONNECTED;
121875606dc6SRalf Baechle goto out_release;
12191da177e4SLinus Torvalds
12201da177e4SLinus Torvalds case TCP_CLOSE: /* connection refused */
12211da177e4SLinus Torvalds sock->state = SS_UNCONNECTED;
12221da177e4SLinus Torvalds err = -ECONNREFUSED;
122375606dc6SRalf Baechle goto out_release;
12241da177e4SLinus Torvalds }
12251da177e4SLinus Torvalds }
12261da177e4SLinus Torvalds
12271da177e4SLinus Torvalds if (sk->sk_state == TCP_ESTABLISHED && sk->sk_type == SOCK_SEQPACKET) {
12281da177e4SLinus Torvalds err = -EISCONN; /* No reconnect on a seqpacket socket */
122975606dc6SRalf Baechle goto out_release;
12301da177e4SLinus Torvalds }
12311da177e4SLinus Torvalds
12321da177e4SLinus Torvalds sk->sk_state = TCP_CLOSE;
12331da177e4SLinus Torvalds sock->state = SS_UNCONNECTED;
12341da177e4SLinus Torvalds
12351da177e4SLinus Torvalds kfree(ax25->digipeat);
12361da177e4SLinus Torvalds ax25->digipeat = NULL;
12371da177e4SLinus Torvalds
12381da177e4SLinus Torvalds /*
12391da177e4SLinus Torvalds * Handle digi-peaters to be used.
12401da177e4SLinus Torvalds */
12411da177e4SLinus Torvalds if (addr_len > sizeof(struct sockaddr_ax25) &&
12421da177e4SLinus Torvalds fsa->fsa_ax25.sax25_ndigis != 0) {
12431da177e4SLinus Torvalds /* Valid number of digipeaters ? */
12442f2a7ffaSPeilin Ye if (fsa->fsa_ax25.sax25_ndigis < 1 ||
124517ad73e9SDan Carpenter fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS ||
12462f2a7ffaSPeilin Ye addr_len < sizeof(struct sockaddr_ax25) +
12472f2a7ffaSPeilin Ye sizeof(ax25_address) * fsa->fsa_ax25.sax25_ndigis) {
12481da177e4SLinus Torvalds err = -EINVAL;
124975606dc6SRalf Baechle goto out_release;
12501da177e4SLinus Torvalds }
12511da177e4SLinus Torvalds
12521da177e4SLinus Torvalds if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
12531da177e4SLinus Torvalds err = -ENOBUFS;
125475606dc6SRalf Baechle goto out_release;
12551da177e4SLinus Torvalds }
12561da177e4SLinus Torvalds
12571da177e4SLinus Torvalds digi->ndigi = fsa->fsa_ax25.sax25_ndigis;
12581da177e4SLinus Torvalds digi->lastrepeat = -1;
12591da177e4SLinus Torvalds
12601da177e4SLinus Torvalds while (ct < fsa->fsa_ax25.sax25_ndigis) {
12611da177e4SLinus Torvalds if ((fsa->fsa_digipeater[ct].ax25_call[6] &
12621da177e4SLinus Torvalds AX25_HBIT) && ax25->iamdigi) {
12631da177e4SLinus Torvalds digi->repeated[ct] = 1;
12641da177e4SLinus Torvalds digi->lastrepeat = ct;
12651da177e4SLinus Torvalds } else {
12661da177e4SLinus Torvalds digi->repeated[ct] = 0;
12671da177e4SLinus Torvalds }
12681da177e4SLinus Torvalds digi->calls[ct] = fsa->fsa_digipeater[ct];
12691da177e4SLinus Torvalds ct++;
12701da177e4SLinus Torvalds }
12711da177e4SLinus Torvalds }
12721da177e4SLinus Torvalds
12731da177e4SLinus Torvalds /*
12741da177e4SLinus Torvalds * Must bind first - autobinding in this may or may not work. If
12751da177e4SLinus Torvalds * the socket is already bound, check to see if the device has
12761da177e4SLinus Torvalds * been filled in, error if it hasn't.
12771da177e4SLinus Torvalds */
12781da177e4SLinus Torvalds if (sock_flag(sk, SOCK_ZAPPED)) {
12791da177e4SLinus Torvalds /* check if we can remove this feature. It is broken. */
12801da177e4SLinus Torvalds printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@yaina.de\n",
12811da177e4SLinus Torvalds current->comm);
12821da177e4SLinus Torvalds if ((err = ax25_rt_autobind(ax25, &fsa->fsa_ax25.sax25_call)) < 0) {
12831da177e4SLinus Torvalds kfree(digi);
128475606dc6SRalf Baechle goto out_release;
12851da177e4SLinus Torvalds }
12861da177e4SLinus Torvalds
12871da177e4SLinus Torvalds ax25_fillin_cb(ax25, ax25->ax25_dev);
12881da177e4SLinus Torvalds ax25_cb_add(ax25);
12891da177e4SLinus Torvalds } else {
12901da177e4SLinus Torvalds if (ax25->ax25_dev == NULL) {
12911da177e4SLinus Torvalds kfree(digi);
12921da177e4SLinus Torvalds err = -EHOSTUNREACH;
129375606dc6SRalf Baechle goto out_release;
12941da177e4SLinus Torvalds }
12951da177e4SLinus Torvalds }
12961da177e4SLinus Torvalds
12971da177e4SLinus Torvalds if (sk->sk_type == SOCK_SEQPACKET &&
12981da177e4SLinus Torvalds (ax25t=ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi,
12991da177e4SLinus Torvalds ax25->ax25_dev->dev))) {
13001da177e4SLinus Torvalds kfree(digi);
13011da177e4SLinus Torvalds err = -EADDRINUSE; /* Already such a connection */
13021da177e4SLinus Torvalds ax25_cb_put(ax25t);
130375606dc6SRalf Baechle goto out_release;
13041da177e4SLinus Torvalds }
13051da177e4SLinus Torvalds
13061da177e4SLinus Torvalds ax25->dest_addr = fsa->fsa_ax25.sax25_call;
13071da177e4SLinus Torvalds ax25->digipeat = digi;
13081da177e4SLinus Torvalds
13091da177e4SLinus Torvalds /* First the easy one */
13101da177e4SLinus Torvalds if (sk->sk_type != SOCK_SEQPACKET) {
13111da177e4SLinus Torvalds sock->state = SS_CONNECTED;
13121da177e4SLinus Torvalds sk->sk_state = TCP_ESTABLISHED;
131375606dc6SRalf Baechle goto out_release;
13141da177e4SLinus Torvalds }
13151da177e4SLinus Torvalds
13161da177e4SLinus Torvalds /* Move to connecting socket, ax.25 lapb WAIT_UA.. */
13171da177e4SLinus Torvalds sock->state = SS_CONNECTING;
13181da177e4SLinus Torvalds sk->sk_state = TCP_SYN_SENT;
13191da177e4SLinus Torvalds
13201da177e4SLinus Torvalds switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
13211da177e4SLinus Torvalds case AX25_PROTO_STD_SIMPLEX:
13221da177e4SLinus Torvalds case AX25_PROTO_STD_DUPLEX:
13231da177e4SLinus Torvalds ax25_std_establish_data_link(ax25);
13241da177e4SLinus Torvalds break;
13251da177e4SLinus Torvalds
13261da177e4SLinus Torvalds #ifdef CONFIG_AX25_DAMA_SLAVE
13271da177e4SLinus Torvalds case AX25_PROTO_DAMA_SLAVE:
13281da177e4SLinus Torvalds ax25->modulus = AX25_MODULUS;
13291da177e4SLinus Torvalds ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
13301da177e4SLinus Torvalds if (ax25->ax25_dev->dama.slave)
13311da177e4SLinus Torvalds ax25_ds_establish_data_link(ax25);
13321da177e4SLinus Torvalds else
13331da177e4SLinus Torvalds ax25_std_establish_data_link(ax25);
13341da177e4SLinus Torvalds break;
13351da177e4SLinus Torvalds #endif
13361da177e4SLinus Torvalds }
13371da177e4SLinus Torvalds
13381da177e4SLinus Torvalds ax25->state = AX25_STATE_1;
13391da177e4SLinus Torvalds
13401da177e4SLinus Torvalds ax25_start_heartbeat(ax25);
13411da177e4SLinus Torvalds
13421da177e4SLinus Torvalds /* Now the loop */
13431da177e4SLinus Torvalds if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
13441da177e4SLinus Torvalds err = -EINPROGRESS;
134575606dc6SRalf Baechle goto out_release;
13461da177e4SLinus Torvalds }
13471da177e4SLinus Torvalds
13481da177e4SLinus Torvalds if (sk->sk_state == TCP_SYN_SENT) {
134975606dc6SRalf Baechle DEFINE_WAIT(wait);
13501da177e4SLinus Torvalds
13511da177e4SLinus Torvalds for (;;) {
1352aa395145SEric Dumazet prepare_to_wait(sk_sleep(sk), &wait,
135375606dc6SRalf Baechle TASK_INTERRUPTIBLE);
13541da177e4SLinus Torvalds if (sk->sk_state != TCP_SYN_SENT)
13551da177e4SLinus Torvalds break;
135675606dc6SRalf Baechle if (!signal_pending(current)) {
13571da177e4SLinus Torvalds release_sock(sk);
13581da177e4SLinus Torvalds schedule();
13591da177e4SLinus Torvalds lock_sock(sk);
13601da177e4SLinus Torvalds continue;
13611da177e4SLinus Torvalds }
136275606dc6SRalf Baechle err = -ERESTARTSYS;
136375606dc6SRalf Baechle break;
13641da177e4SLinus Torvalds }
1365aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait);
136675606dc6SRalf Baechle
136775606dc6SRalf Baechle if (err)
136875606dc6SRalf Baechle goto out_release;
13691da177e4SLinus Torvalds }
13701da177e4SLinus Torvalds
13711da177e4SLinus Torvalds if (sk->sk_state != TCP_ESTABLISHED) {
13721da177e4SLinus Torvalds /* Not in ABM, not in WAIT_UA -> failed */
13731da177e4SLinus Torvalds sock->state = SS_UNCONNECTED;
13741da177e4SLinus Torvalds err = sock_error(sk); /* Always set at this point */
137575606dc6SRalf Baechle goto out_release;
13761da177e4SLinus Torvalds }
13771da177e4SLinus Torvalds
13781da177e4SLinus Torvalds sock->state = SS_CONNECTED;
13791da177e4SLinus Torvalds
13801da177e4SLinus Torvalds err = 0;
138175606dc6SRalf Baechle out_release:
13821da177e4SLinus Torvalds release_sock(sk);
13831da177e4SLinus Torvalds
13841da177e4SLinus Torvalds return err;
13851da177e4SLinus Torvalds }
13861da177e4SLinus Torvalds
ax25_accept(struct socket * sock,struct socket * newsock,int flags,bool kern)1387cdfbabfbSDavid Howells static int ax25_accept(struct socket *sock, struct socket *newsock, int flags,
1388cdfbabfbSDavid Howells bool kern)
13891da177e4SLinus Torvalds {
13901da177e4SLinus Torvalds struct sk_buff *skb;
13911da177e4SLinus Torvalds struct sock *newsk;
139252100fd7SLars Kellogg-Stedman ax25_dev *ax25_dev;
139375606dc6SRalf Baechle DEFINE_WAIT(wait);
13941da177e4SLinus Torvalds struct sock *sk;
139552100fd7SLars Kellogg-Stedman ax25_cb *ax25;
13961da177e4SLinus Torvalds int err = 0;
13971da177e4SLinus Torvalds
13981da177e4SLinus Torvalds if (sock->state != SS_UNCONNECTED)
13991da177e4SLinus Torvalds return -EINVAL;
14001da177e4SLinus Torvalds
14011da177e4SLinus Torvalds if ((sk = sock->sk) == NULL)
14021da177e4SLinus Torvalds return -EINVAL;
14031da177e4SLinus Torvalds
14041da177e4SLinus Torvalds lock_sock(sk);
14051da177e4SLinus Torvalds if (sk->sk_type != SOCK_SEQPACKET) {
14061da177e4SLinus Torvalds err = -EOPNOTSUPP;
14071da177e4SLinus Torvalds goto out;
14081da177e4SLinus Torvalds }
14091da177e4SLinus Torvalds
14101da177e4SLinus Torvalds if (sk->sk_state != TCP_LISTEN) {
14111da177e4SLinus Torvalds err = -EINVAL;
14121da177e4SLinus Torvalds goto out;
14131da177e4SLinus Torvalds }
14141da177e4SLinus Torvalds
14151da177e4SLinus Torvalds /*
14161da177e4SLinus Torvalds * The read queue this time is holding sockets ready to use
14171da177e4SLinus Torvalds * hooked into the SABM we saved
14181da177e4SLinus Torvalds */
14191da177e4SLinus Torvalds for (;;) {
1420aa395145SEric Dumazet prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
14211da177e4SLinus Torvalds skb = skb_dequeue(&sk->sk_receive_queue);
14221da177e4SLinus Torvalds if (skb)
14231da177e4SLinus Torvalds break;
14241da177e4SLinus Torvalds
14251da177e4SLinus Torvalds if (flags & O_NONBLOCK) {
142675606dc6SRalf Baechle err = -EWOULDBLOCK;
142775606dc6SRalf Baechle break;
14281da177e4SLinus Torvalds }
142975606dc6SRalf Baechle if (!signal_pending(current)) {
143075606dc6SRalf Baechle release_sock(sk);
14311da177e4SLinus Torvalds schedule();
14321da177e4SLinus Torvalds lock_sock(sk);
14331da177e4SLinus Torvalds continue;
14341da177e4SLinus Torvalds }
143575606dc6SRalf Baechle err = -ERESTARTSYS;
143675606dc6SRalf Baechle break;
14371da177e4SLinus Torvalds }
1438aa395145SEric Dumazet finish_wait(sk_sleep(sk), &wait);
143975606dc6SRalf Baechle
144075606dc6SRalf Baechle if (err)
144175606dc6SRalf Baechle goto out;
14421da177e4SLinus Torvalds
14431da177e4SLinus Torvalds newsk = skb->sk;
14449375cb8aSDavid S. Miller sock_graft(newsk, newsock);
14451da177e4SLinus Torvalds
14461da177e4SLinus Torvalds /* Now attach up the new socket */
14471da177e4SLinus Torvalds kfree_skb(skb);
14487976a11bSEric Dumazet sk_acceptq_removed(sk);
14491da177e4SLinus Torvalds newsock->state = SS_CONNECTED;
145052100fd7SLars Kellogg-Stedman ax25 = sk_to_ax25(newsk);
145152100fd7SLars Kellogg-Stedman ax25_dev = ax25->ax25_dev;
145252100fd7SLars Kellogg-Stedman netdev_hold(ax25_dev->dev, &ax25->dev_tracker, GFP_ATOMIC);
145352100fd7SLars Kellogg-Stedman ax25_dev_hold(ax25_dev);
14541da177e4SLinus Torvalds
14551da177e4SLinus Torvalds out:
14561da177e4SLinus Torvalds release_sock(sk);
14571da177e4SLinus Torvalds
14581da177e4SLinus Torvalds return err;
14591da177e4SLinus Torvalds }
14601da177e4SLinus Torvalds
ax25_getname(struct socket * sock,struct sockaddr * uaddr,int peer)14611da177e4SLinus Torvalds static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,
14629b2c45d4SDenys Vlasenko int peer)
14631da177e4SLinus Torvalds {
14641da177e4SLinus Torvalds struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
14651da177e4SLinus Torvalds struct sock *sk = sock->sk;
14661da177e4SLinus Torvalds unsigned char ndigi, i;
14671da177e4SLinus Torvalds ax25_cb *ax25;
14681da177e4SLinus Torvalds int err = 0;
14691da177e4SLinus Torvalds
14705b919f83SKees Cook memset(fsa, 0, sizeof(*fsa));
14711da177e4SLinus Torvalds lock_sock(sk);
14723200392bSDavid Miller ax25 = sk_to_ax25(sk);
14731da177e4SLinus Torvalds
14741da177e4SLinus Torvalds if (peer != 0) {
14751da177e4SLinus Torvalds if (sk->sk_state != TCP_ESTABLISHED) {
14761da177e4SLinus Torvalds err = -ENOTCONN;
14771da177e4SLinus Torvalds goto out;
14781da177e4SLinus Torvalds }
14791da177e4SLinus Torvalds
14801da177e4SLinus Torvalds fsa->fsa_ax25.sax25_family = AF_AX25;
14811da177e4SLinus Torvalds fsa->fsa_ax25.sax25_call = ax25->dest_addr;
14821da177e4SLinus Torvalds
14831da177e4SLinus Torvalds if (ax25->digipeat != NULL) {
14841da177e4SLinus Torvalds ndigi = ax25->digipeat->ndigi;
14851da177e4SLinus Torvalds fsa->fsa_ax25.sax25_ndigis = ndigi;
14861da177e4SLinus Torvalds for (i = 0; i < ndigi; i++)
14871da177e4SLinus Torvalds fsa->fsa_digipeater[i] =
14881da177e4SLinus Torvalds ax25->digipeat->calls[i];
14891da177e4SLinus Torvalds }
14901da177e4SLinus Torvalds } else {
14911da177e4SLinus Torvalds fsa->fsa_ax25.sax25_family = AF_AX25;
14921da177e4SLinus Torvalds fsa->fsa_ax25.sax25_call = ax25->source_addr;
14931da177e4SLinus Torvalds fsa->fsa_ax25.sax25_ndigis = 1;
14941da177e4SLinus Torvalds if (ax25->ax25_dev != NULL) {
14951da177e4SLinus Torvalds memcpy(&fsa->fsa_digipeater[0],
14961da177e4SLinus Torvalds ax25->ax25_dev->dev->dev_addr, AX25_ADDR_LEN);
14971da177e4SLinus Torvalds } else {
14981da177e4SLinus Torvalds fsa->fsa_digipeater[0] = null_ax25_address;
14991da177e4SLinus Torvalds }
15001da177e4SLinus Torvalds }
15019b2c45d4SDenys Vlasenko err = sizeof (struct full_sockaddr_ax25);
15021da177e4SLinus Torvalds
15031da177e4SLinus Torvalds out:
15041da177e4SLinus Torvalds release_sock(sk);
15051da177e4SLinus Torvalds
15061da177e4SLinus Torvalds return err;
15071da177e4SLinus Torvalds }
15081da177e4SLinus Torvalds
ax25_sendmsg(struct socket * sock,struct msghdr * msg,size_t len)15091b784140SYing Xue static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
15101da177e4SLinus Torvalds {
1511342dfc30SSteffen Hurrle DECLARE_SOCKADDR(struct sockaddr_ax25 *, usax, msg->msg_name);
15121da177e4SLinus Torvalds struct sock *sk = sock->sk;
15131da177e4SLinus Torvalds struct sockaddr_ax25 sax;
15141da177e4SLinus Torvalds struct sk_buff *skb;
15151da177e4SLinus Torvalds ax25_digi dtmp, *dp;
15161da177e4SLinus Torvalds ax25_cb *ax25;
15171da177e4SLinus Torvalds size_t size;
15181da177e4SLinus Torvalds int lv, err, addr_len = msg->msg_namelen;
15191da177e4SLinus Torvalds
15201da177e4SLinus Torvalds if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT))
15211da177e4SLinus Torvalds return -EINVAL;
15221da177e4SLinus Torvalds
15231da177e4SLinus Torvalds lock_sock(sk);
15243200392bSDavid Miller ax25 = sk_to_ax25(sk);
15251da177e4SLinus Torvalds
15261da177e4SLinus Torvalds if (sock_flag(sk, SOCK_ZAPPED)) {
15271da177e4SLinus Torvalds err = -EADDRNOTAVAIL;
15281da177e4SLinus Torvalds goto out;
15291da177e4SLinus Torvalds }
15301da177e4SLinus Torvalds
15311da177e4SLinus Torvalds if (sk->sk_shutdown & SEND_SHUTDOWN) {
15321da177e4SLinus Torvalds send_sig(SIGPIPE, current, 0);
15331da177e4SLinus Torvalds err = -EPIPE;
15341da177e4SLinus Torvalds goto out;
15351da177e4SLinus Torvalds }
15361da177e4SLinus Torvalds
15371da177e4SLinus Torvalds if (ax25->ax25_dev == NULL) {
15381da177e4SLinus Torvalds err = -ENETUNREACH;
15391da177e4SLinus Torvalds goto out;
15401da177e4SLinus Torvalds }
15411da177e4SLinus Torvalds
15421da177e4SLinus Torvalds if (len > ax25->ax25_dev->dev->mtu) {
15431da177e4SLinus Torvalds err = -EMSGSIZE;
15441da177e4SLinus Torvalds goto out;
15451da177e4SLinus Torvalds }
15461da177e4SLinus Torvalds
15471da177e4SLinus Torvalds if (usax != NULL) {
15481da177e4SLinus Torvalds if (usax->sax25_family != AF_AX25) {
15491da177e4SLinus Torvalds err = -EINVAL;
15501da177e4SLinus Torvalds goto out;
15511da177e4SLinus Torvalds }
15521da177e4SLinus Torvalds
155327d1cba2Smaximilian attems if (addr_len == sizeof(struct sockaddr_ax25))
155427d1cba2Smaximilian attems /* ax25_sendmsg(): uses obsolete socket structure */
155527d1cba2Smaximilian attems ;
155627d1cba2Smaximilian attems else if (addr_len != sizeof(struct full_sockaddr_ax25))
155727d1cba2Smaximilian attems /* support for old structure may go away some time
155827d1cba2Smaximilian attems * ax25_sendmsg(): uses old (6 digipeater)
155927d1cba2Smaximilian attems * socket structure.
156027d1cba2Smaximilian attems */
15611da177e4SLinus Torvalds if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
15621da177e4SLinus Torvalds (addr_len > sizeof(struct full_sockaddr_ax25))) {
15631da177e4SLinus Torvalds err = -EINVAL;
15641da177e4SLinus Torvalds goto out;
15651da177e4SLinus Torvalds }
15661da177e4SLinus Torvalds
15671da177e4SLinus Torvalds
15681da177e4SLinus Torvalds if (addr_len > sizeof(struct sockaddr_ax25) && usax->sax25_ndigis != 0) {
15691da177e4SLinus Torvalds int ct = 0;
15701da177e4SLinus Torvalds struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax;
15711da177e4SLinus Torvalds
15721da177e4SLinus Torvalds /* Valid number of digipeaters ? */
157317ad73e9SDan Carpenter if (usax->sax25_ndigis < 1 ||
157417ad73e9SDan Carpenter usax->sax25_ndigis > AX25_MAX_DIGIS ||
157517ad73e9SDan Carpenter addr_len < sizeof(struct sockaddr_ax25) +
15768885bb06SPeilin Ye sizeof(ax25_address) * usax->sax25_ndigis) {
15771da177e4SLinus Torvalds err = -EINVAL;
15781da177e4SLinus Torvalds goto out;
15791da177e4SLinus Torvalds }
15801da177e4SLinus Torvalds
15811da177e4SLinus Torvalds dtmp.ndigi = usax->sax25_ndigis;
15821da177e4SLinus Torvalds
15831da177e4SLinus Torvalds while (ct < usax->sax25_ndigis) {
15841da177e4SLinus Torvalds dtmp.repeated[ct] = 0;
15851da177e4SLinus Torvalds dtmp.calls[ct] = fsa->fsa_digipeater[ct];
15861da177e4SLinus Torvalds ct++;
15871da177e4SLinus Torvalds }
15881da177e4SLinus Torvalds
15891da177e4SLinus Torvalds dtmp.lastrepeat = 0;
15901da177e4SLinus Torvalds }
15911da177e4SLinus Torvalds
15921da177e4SLinus Torvalds sax = *usax;
15931da177e4SLinus Torvalds if (sk->sk_type == SOCK_SEQPACKET &&
15941da177e4SLinus Torvalds ax25cmp(&ax25->dest_addr, &sax.sax25_call)) {
15951da177e4SLinus Torvalds err = -EISCONN;
15961da177e4SLinus Torvalds goto out;
15971da177e4SLinus Torvalds }
15981da177e4SLinus Torvalds if (usax->sax25_ndigis == 0)
15991da177e4SLinus Torvalds dp = NULL;
16001da177e4SLinus Torvalds else
16011da177e4SLinus Torvalds dp = &dtmp;
16021da177e4SLinus Torvalds } else {
16031da177e4SLinus Torvalds /*
16041da177e4SLinus Torvalds * FIXME: 1003.1g - if the socket is like this because
16051da177e4SLinus Torvalds * it has become closed (not started closed) and is VC
16061da177e4SLinus Torvalds * we ought to SIGPIPE, EPIPE
16071da177e4SLinus Torvalds */
16081da177e4SLinus Torvalds if (sk->sk_state != TCP_ESTABLISHED) {
16091da177e4SLinus Torvalds err = -ENOTCONN;
16101da177e4SLinus Torvalds goto out;
16111da177e4SLinus Torvalds }
16121da177e4SLinus Torvalds sax.sax25_family = AF_AX25;
16131da177e4SLinus Torvalds sax.sax25_call = ax25->dest_addr;
16141da177e4SLinus Torvalds dp = ax25->digipeat;
16151da177e4SLinus Torvalds }
16161da177e4SLinus Torvalds
16171da177e4SLinus Torvalds /* Build a packet */
16181da177e4SLinus Torvalds /* Assume the worst case */
16191da177e4SLinus Torvalds size = len + ax25->ax25_dev->dev->hard_header_len;
16201da177e4SLinus Torvalds
16211da177e4SLinus Torvalds skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT, &err);
16221da177e4SLinus Torvalds if (skb == NULL)
16231da177e4SLinus Torvalds goto out;
16241da177e4SLinus Torvalds
16251da177e4SLinus Torvalds skb_reserve(skb, size - len);
16261da177e4SLinus Torvalds
16271da177e4SLinus Torvalds /* User data follows immediately after the AX.25 data */
16286ce8e9ceSAl Viro if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
16291da177e4SLinus Torvalds err = -EFAULT;
16301da177e4SLinus Torvalds kfree_skb(skb);
16311da177e4SLinus Torvalds goto out;
16321da177e4SLinus Torvalds }
16331da177e4SLinus Torvalds
1634c1d2bbe1SArnaldo Carvalho de Melo skb_reset_network_header(skb);
16351da177e4SLinus Torvalds
16361da177e4SLinus Torvalds /* Add the PID if one is not supplied by the user in the skb */
1637967b05f6SArnaldo Carvalho de Melo if (!ax25->pidincl)
1638d58ff351SJohannes Berg *(u8 *)skb_push(skb, 1) = sk->sk_protocol;
16391da177e4SLinus Torvalds
16401da177e4SLinus Torvalds if (sk->sk_type == SOCK_SEQPACKET) {
16411da177e4SLinus Torvalds /* Connected mode sockets go via the LAPB machine */
16421da177e4SLinus Torvalds if (sk->sk_state != TCP_ESTABLISHED) {
16431da177e4SLinus Torvalds kfree_skb(skb);
16441da177e4SLinus Torvalds err = -ENOTCONN;
16451da177e4SLinus Torvalds goto out;
16461da177e4SLinus Torvalds }
16471da177e4SLinus Torvalds
16481da177e4SLinus Torvalds /* Shove it onto the queue and kick */
16491da177e4SLinus Torvalds ax25_output(ax25, ax25->paclen, skb);
16501da177e4SLinus Torvalds
16511da177e4SLinus Torvalds err = len;
16521da177e4SLinus Torvalds goto out;
16531da177e4SLinus Torvalds }
16541da177e4SLinus Torvalds
1655967b05f6SArnaldo Carvalho de Melo skb_push(skb, 1 + ax25_addr_size(dp));
16561da177e4SLinus Torvalds
16578849b720SRalf Baechle /* Building AX.25 Header */
16581da177e4SLinus Torvalds
16591da177e4SLinus Torvalds /* Build an AX.25 header */
1660967b05f6SArnaldo Carvalho de Melo lv = ax25_addr_build(skb->data, &ax25->source_addr, &sax.sax25_call,
1661967b05f6SArnaldo Carvalho de Melo dp, AX25_COMMAND, AX25_MODULUS);
16621da177e4SLinus Torvalds
1663967b05f6SArnaldo Carvalho de Melo skb_set_transport_header(skb, lv);
16641da177e4SLinus Torvalds
16659c70220bSArnaldo Carvalho de Melo *skb_transport_header(skb) = AX25_UI;
16661da177e4SLinus Torvalds
16671da177e4SLinus Torvalds /* Datagram frames go straight out of the door as UI */
166829c4be51SArnaldo Carvalho de Melo ax25_queue_xmit(skb, ax25->ax25_dev->dev);
16691da177e4SLinus Torvalds
16701da177e4SLinus Torvalds err = len;
16711da177e4SLinus Torvalds
16721da177e4SLinus Torvalds out:
16731da177e4SLinus Torvalds release_sock(sk);
16741da177e4SLinus Torvalds
16751da177e4SLinus Torvalds return err;
16761da177e4SLinus Torvalds }
16771da177e4SLinus Torvalds
ax25_recvmsg(struct socket * sock,struct msghdr * msg,size_t size,int flags)16781b784140SYing Xue static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
16791b784140SYing Xue int flags)
16801da177e4SLinus Torvalds {
16811da177e4SLinus Torvalds struct sock *sk = sock->sk;
1682219b51a6SDuoming Zhou struct sk_buff *skb, *last;
1683219b51a6SDuoming Zhou struct sk_buff_head *sk_queue;
16841da177e4SLinus Torvalds int copied;
16851da177e4SLinus Torvalds int err = 0;
1686219b51a6SDuoming Zhou int off = 0;
1687219b51a6SDuoming Zhou long timeo;
16881da177e4SLinus Torvalds
16891da177e4SLinus Torvalds lock_sock(sk);
16901da177e4SLinus Torvalds /*
16911da177e4SLinus Torvalds * This works for seqpacket too. The receiver has ordered the
16921da177e4SLinus Torvalds * queue for us! We do one quick check first though
16931da177e4SLinus Torvalds */
16941da177e4SLinus Torvalds if (sk->sk_type == SOCK_SEQPACKET && sk->sk_state != TCP_ESTABLISHED) {
16951da177e4SLinus Torvalds err = -ENOTCONN;
16961da177e4SLinus Torvalds goto out;
16971da177e4SLinus Torvalds }
16981da177e4SLinus Torvalds
1699219b51a6SDuoming Zhou /* We need support for non-blocking reads. */
1700219b51a6SDuoming Zhou sk_queue = &sk->sk_receive_queue;
1701219b51a6SDuoming Zhou skb = __skb_try_recv_datagram(sk, sk_queue, flags, &off, &err, &last);
1702219b51a6SDuoming Zhou /* If no packet is available, release_sock(sk) and try again. */
1703219b51a6SDuoming Zhou if (!skb) {
1704219b51a6SDuoming Zhou if (err != -EAGAIN)
17051da177e4SLinus Torvalds goto out;
1706219b51a6SDuoming Zhou release_sock(sk);
1707219b51a6SDuoming Zhou timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
1708219b51a6SDuoming Zhou while (timeo && !__skb_wait_for_more_packets(sk, sk_queue, &err,
1709219b51a6SDuoming Zhou &timeo, last)) {
1710219b51a6SDuoming Zhou skb = __skb_try_recv_datagram(sk, sk_queue, flags, &off,
1711219b51a6SDuoming Zhou &err, &last);
1712219b51a6SDuoming Zhou if (skb)
1713219b51a6SDuoming Zhou break;
1714219b51a6SDuoming Zhou
1715219b51a6SDuoming Zhou if (err != -EAGAIN)
1716219b51a6SDuoming Zhou goto done;
1717219b51a6SDuoming Zhou }
1718219b51a6SDuoming Zhou if (!skb)
1719219b51a6SDuoming Zhou goto done;
1720219b51a6SDuoming Zhou lock_sock(sk);
1721219b51a6SDuoming Zhou }
17221da177e4SLinus Torvalds
17233200392bSDavid Miller if (!sk_to_ax25(sk)->pidincl)
17241da177e4SLinus Torvalds skb_pull(skb, 1); /* Remove PID */
17251da177e4SLinus Torvalds
1726badff6d0SArnaldo Carvalho de Melo skb_reset_transport_header(skb);
17271da177e4SLinus Torvalds copied = skb->len;
17281da177e4SLinus Torvalds
17291da177e4SLinus Torvalds if (copied > size) {
17301da177e4SLinus Torvalds copied = size;
17311da177e4SLinus Torvalds msg->msg_flags |= MSG_TRUNC;
17321da177e4SLinus Torvalds }
17331da177e4SLinus Torvalds
173451f3d02bSDavid S. Miller skb_copy_datagram_msg(skb, 0, msg, copied);
17351da177e4SLinus Torvalds
1736f3d33426SHannes Frederic Sowa if (msg->msg_name) {
17371da177e4SLinus Torvalds ax25_digi digi;
17381da177e4SLinus Torvalds ax25_address src;
173998e399f8SArnaldo Carvalho de Melo const unsigned char *mac = skb_mac_header(skb);
1740342dfc30SSteffen Hurrle DECLARE_SOCKADDR(struct sockaddr_ax25 *, sax, msg->msg_name);
17411da177e4SLinus Torvalds
1742ef3313e8SMathias Krause memset(sax, 0, sizeof(struct full_sockaddr_ax25));
174398e399f8SArnaldo Carvalho de Melo ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL,
174498e399f8SArnaldo Carvalho de Melo &digi, NULL, NULL);
17451da177e4SLinus Torvalds sax->sax25_family = AF_AX25;
17461da177e4SLinus Torvalds /* We set this correctly, even though we may not let the
17471da177e4SLinus Torvalds application know the digi calls further down (because it
17481da177e4SLinus Torvalds did NOT ask to know them). This could get political... **/
17491da177e4SLinus Torvalds sax->sax25_ndigis = digi.ndigi;
17501da177e4SLinus Torvalds sax->sax25_call = src;
17511da177e4SLinus Torvalds
17521da177e4SLinus Torvalds if (sax->sax25_ndigis != 0) {
17531da177e4SLinus Torvalds int ct;
17541da177e4SLinus Torvalds struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)sax;
17551da177e4SLinus Torvalds
17561da177e4SLinus Torvalds for (ct = 0; ct < digi.ndigi; ct++)
17571da177e4SLinus Torvalds fsa->fsa_digipeater[ct] = digi.calls[ct];
17581da177e4SLinus Torvalds }
17591da177e4SLinus Torvalds msg->msg_namelen = sizeof(struct full_sockaddr_ax25);
17601da177e4SLinus Torvalds }
17611da177e4SLinus Torvalds
17621da177e4SLinus Torvalds skb_free_datagram(sk, skb);
17631da177e4SLinus Torvalds err = copied;
17641da177e4SLinus Torvalds
17651da177e4SLinus Torvalds out:
17661da177e4SLinus Torvalds release_sock(sk);
17671da177e4SLinus Torvalds
1768219b51a6SDuoming Zhou done:
17691da177e4SLinus Torvalds return err;
17701da177e4SLinus Torvalds }
17711da177e4SLinus Torvalds
ax25_shutdown(struct socket * sk,int how)17721da177e4SLinus Torvalds static int ax25_shutdown(struct socket *sk, int how)
17731da177e4SLinus Torvalds {
17741da177e4SLinus Torvalds /* FIXME - generate DM and RNR states */
17751da177e4SLinus Torvalds return -EOPNOTSUPP;
17761da177e4SLinus Torvalds }
17771da177e4SLinus Torvalds
ax25_ioctl(struct socket * sock,unsigned int cmd,unsigned long arg)17781da177e4SLinus Torvalds static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
17791da177e4SLinus Torvalds {
17801da177e4SLinus Torvalds struct sock *sk = sock->sk;
17811da177e4SLinus Torvalds void __user *argp = (void __user *)arg;
17821da177e4SLinus Torvalds int res = 0;
17831da177e4SLinus Torvalds
17841da177e4SLinus Torvalds lock_sock(sk);
17851da177e4SLinus Torvalds switch (cmd) {
17861da177e4SLinus Torvalds case TIOCOUTQ: {
17871da177e4SLinus Torvalds long amount;
178831e6d363SEric Dumazet
178931e6d363SEric Dumazet amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
17901da177e4SLinus Torvalds if (amount < 0)
17911da177e4SLinus Torvalds amount = 0;
17921da177e4SLinus Torvalds res = put_user(amount, (int __user *)argp);
17931da177e4SLinus Torvalds break;
17941da177e4SLinus Torvalds }
17951da177e4SLinus Torvalds
17961da177e4SLinus Torvalds case TIOCINQ: {
17971da177e4SLinus Torvalds struct sk_buff *skb;
17981da177e4SLinus Torvalds long amount = 0L;
17991da177e4SLinus Torvalds /* These two are safe on a single CPU system as only user tasks fiddle here */
18001da177e4SLinus Torvalds if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
18011da177e4SLinus Torvalds amount = skb->len;
18021da177e4SLinus Torvalds res = put_user(amount, (int __user *) argp);
18031da177e4SLinus Torvalds break;
18041da177e4SLinus Torvalds }
18051da177e4SLinus Torvalds
18061da177e4SLinus Torvalds case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */
18071da177e4SLinus Torvalds case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */
18081da177e4SLinus Torvalds case SIOCAX25GETUID: {
18091da177e4SLinus Torvalds struct sockaddr_ax25 sax25;
18101da177e4SLinus Torvalds if (copy_from_user(&sax25, argp, sizeof(sax25))) {
18111da177e4SLinus Torvalds res = -EFAULT;
18121da177e4SLinus Torvalds break;
18131da177e4SLinus Torvalds }
18141da177e4SLinus Torvalds res = ax25_uid_ioctl(cmd, &sax25);
18151da177e4SLinus Torvalds break;
18161da177e4SLinus Torvalds }
18171da177e4SLinus Torvalds
18181da177e4SLinus Torvalds case SIOCAX25NOUID: { /* Set the default policy (default/bar) */
18191da177e4SLinus Torvalds long amount;
18201da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) {
18211da177e4SLinus Torvalds res = -EPERM;
18221da177e4SLinus Torvalds break;
18231da177e4SLinus Torvalds }
18241da177e4SLinus Torvalds if (get_user(amount, (long __user *)argp)) {
18251da177e4SLinus Torvalds res = -EFAULT;
18261da177e4SLinus Torvalds break;
18271da177e4SLinus Torvalds }
182876887753SDan Carpenter if (amount < 0 || amount > AX25_NOUID_BLOCK) {
18291da177e4SLinus Torvalds res = -EINVAL;
18301da177e4SLinus Torvalds break;
18311da177e4SLinus Torvalds }
18321da177e4SLinus Torvalds ax25_uid_policy = amount;
18331da177e4SLinus Torvalds res = 0;
18341da177e4SLinus Torvalds break;
18351da177e4SLinus Torvalds }
18361da177e4SLinus Torvalds
18371da177e4SLinus Torvalds case SIOCADDRT:
18381da177e4SLinus Torvalds case SIOCDELRT:
18391da177e4SLinus Torvalds case SIOCAX25OPTRT:
18401da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) {
18411da177e4SLinus Torvalds res = -EPERM;
18421da177e4SLinus Torvalds break;
18431da177e4SLinus Torvalds }
18441da177e4SLinus Torvalds res = ax25_rt_ioctl(cmd, argp);
18451da177e4SLinus Torvalds break;
18461da177e4SLinus Torvalds
18471da177e4SLinus Torvalds case SIOCAX25CTLCON:
18481da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) {
18491da177e4SLinus Torvalds res = -EPERM;
18501da177e4SLinus Torvalds break;
18511da177e4SLinus Torvalds }
18521da177e4SLinus Torvalds res = ax25_ctl_ioctl(cmd, argp);
18531da177e4SLinus Torvalds break;
18541da177e4SLinus Torvalds
18551da177e4SLinus Torvalds case SIOCAX25GETINFO:
18561da177e4SLinus Torvalds case SIOCAX25GETINFOOLD: {
18573200392bSDavid Miller ax25_cb *ax25 = sk_to_ax25(sk);
18581da177e4SLinus Torvalds struct ax25_info_struct ax25_info;
18591da177e4SLinus Torvalds
18601da177e4SLinus Torvalds ax25_info.t1 = ax25->t1 / HZ;
18611da177e4SLinus Torvalds ax25_info.t2 = ax25->t2 / HZ;
18621da177e4SLinus Torvalds ax25_info.t3 = ax25->t3 / HZ;
18631da177e4SLinus Torvalds ax25_info.idle = ax25->idle / (60 * HZ);
18641da177e4SLinus Torvalds ax25_info.n2 = ax25->n2;
18651da177e4SLinus Torvalds ax25_info.t1timer = ax25_display_timer(&ax25->t1timer) / HZ;
18661da177e4SLinus Torvalds ax25_info.t2timer = ax25_display_timer(&ax25->t2timer) / HZ;
18671da177e4SLinus Torvalds ax25_info.t3timer = ax25_display_timer(&ax25->t3timer) / HZ;
18681da177e4SLinus Torvalds ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ);
18691da177e4SLinus Torvalds ax25_info.n2count = ax25->n2count;
18701da177e4SLinus Torvalds ax25_info.state = ax25->state;
1871407fc5cfSEric Dumazet ax25_info.rcv_q = sk_rmem_alloc_get(sk);
1872407fc5cfSEric Dumazet ax25_info.snd_q = sk_wmem_alloc_get(sk);
18731da177e4SLinus Torvalds ax25_info.vs = ax25->vs;
18741da177e4SLinus Torvalds ax25_info.vr = ax25->vr;
18751da177e4SLinus Torvalds ax25_info.va = ax25->va;
18761da177e4SLinus Torvalds ax25_info.vs_max = ax25->vs; /* reserved */
18771da177e4SLinus Torvalds ax25_info.paclen = ax25->paclen;
18781da177e4SLinus Torvalds ax25_info.window = ax25->window;
18791da177e4SLinus Torvalds
18801da177e4SLinus Torvalds /* old structure? */
18811da177e4SLinus Torvalds if (cmd == SIOCAX25GETINFOOLD) {
18821da177e4SLinus Torvalds static int warned = 0;
18831da177e4SLinus Torvalds if (!warned) {
18841da177e4SLinus Torvalds printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n",
18851da177e4SLinus Torvalds current->comm);
18861da177e4SLinus Torvalds warned=1;
18871da177e4SLinus Torvalds }
18881da177e4SLinus Torvalds
18891da177e4SLinus Torvalds if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct_deprecated))) {
18901da177e4SLinus Torvalds res = -EFAULT;
18911da177e4SLinus Torvalds break;
18921da177e4SLinus Torvalds }
18931da177e4SLinus Torvalds } else {
18941da177e4SLinus Torvalds if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct))) {
18951da177e4SLinus Torvalds res = -EINVAL;
18961da177e4SLinus Torvalds break;
18971da177e4SLinus Torvalds }
18981da177e4SLinus Torvalds }
18991da177e4SLinus Torvalds res = 0;
19001da177e4SLinus Torvalds break;
19011da177e4SLinus Torvalds }
19021da177e4SLinus Torvalds
19031da177e4SLinus Torvalds case SIOCAX25ADDFWD:
19041da177e4SLinus Torvalds case SIOCAX25DELFWD: {
19051da177e4SLinus Torvalds struct ax25_fwd_struct ax25_fwd;
19061da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) {
19071da177e4SLinus Torvalds res = -EPERM;
19081da177e4SLinus Torvalds break;
19091da177e4SLinus Torvalds }
19101da177e4SLinus Torvalds if (copy_from_user(&ax25_fwd, argp, sizeof(ax25_fwd))) {
19111da177e4SLinus Torvalds res = -EFAULT;
19121da177e4SLinus Torvalds break;
19131da177e4SLinus Torvalds }
19141da177e4SLinus Torvalds res = ax25_fwd_ioctl(cmd, &ax25_fwd);
19151da177e4SLinus Torvalds break;
19161da177e4SLinus Torvalds }
19171da177e4SLinus Torvalds
19181da177e4SLinus Torvalds case SIOCGIFADDR:
19191da177e4SLinus Torvalds case SIOCSIFADDR:
19201da177e4SLinus Torvalds case SIOCGIFDSTADDR:
19211da177e4SLinus Torvalds case SIOCSIFDSTADDR:
19221da177e4SLinus Torvalds case SIOCGIFBRDADDR:
19231da177e4SLinus Torvalds case SIOCSIFBRDADDR:
19241da177e4SLinus Torvalds case SIOCGIFNETMASK:
19251da177e4SLinus Torvalds case SIOCSIFNETMASK:
19261da177e4SLinus Torvalds case SIOCGIFMETRIC:
19271da177e4SLinus Torvalds case SIOCSIFMETRIC:
19281da177e4SLinus Torvalds res = -EINVAL;
19291da177e4SLinus Torvalds break;
19301da177e4SLinus Torvalds
19311da177e4SLinus Torvalds default:
1932b5e5fa5eSChristoph Hellwig res = -ENOIOCTLCMD;
19331da177e4SLinus Torvalds break;
19341da177e4SLinus Torvalds }
19351da177e4SLinus Torvalds release_sock(sk);
19361da177e4SLinus Torvalds
19371da177e4SLinus Torvalds return res;
19381da177e4SLinus Torvalds }
19391da177e4SLinus Torvalds
19401da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
19411da177e4SLinus Torvalds
ax25_info_start(struct seq_file * seq,loff_t * pos)19421da177e4SLinus Torvalds static void *ax25_info_start(struct seq_file *seq, loff_t *pos)
1943f16f3026SEric Dumazet __acquires(ax25_list_lock)
19441da177e4SLinus Torvalds {
19451da177e4SLinus Torvalds spin_lock_bh(&ax25_list_lock);
1946b512f3d8SLi Zefan return seq_hlist_start(&ax25_list, *pos);
19471da177e4SLinus Torvalds }
19481da177e4SLinus Torvalds
ax25_info_next(struct seq_file * seq,void * v,loff_t * pos)19491da177e4SLinus Torvalds static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos)
19501da177e4SLinus Torvalds {
1951b512f3d8SLi Zefan return seq_hlist_next(v, &ax25_list, pos);
19521da177e4SLinus Torvalds }
19531da177e4SLinus Torvalds
ax25_info_stop(struct seq_file * seq,void * v)19541da177e4SLinus Torvalds static void ax25_info_stop(struct seq_file *seq, void *v)
1955f16f3026SEric Dumazet __releases(ax25_list_lock)
19561da177e4SLinus Torvalds {
19571da177e4SLinus Torvalds spin_unlock_bh(&ax25_list_lock);
19581da177e4SLinus Torvalds }
19591da177e4SLinus Torvalds
ax25_info_show(struct seq_file * seq,void * v)19601da177e4SLinus Torvalds static int ax25_info_show(struct seq_file *seq, void *v)
19611da177e4SLinus Torvalds {
1962b512f3d8SLi Zefan ax25_cb *ax25 = hlist_entry(v, struct ax25_cb, ax25_node);
1963f75268cdSRalf Baechle char buf[11];
19641da177e4SLinus Torvalds int k;
19651da177e4SLinus Torvalds
19661da177e4SLinus Torvalds
19671da177e4SLinus Torvalds /*
19681da177e4SLinus Torvalds * New format:
19691da177e4SLinus Torvalds * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode
19701da177e4SLinus Torvalds */
19711da177e4SLinus Torvalds
1972966cddefSFuqian Huang seq_printf(seq, "%p %s %s%s ",
1973966cddefSFuqian Huang ax25,
19741da177e4SLinus Torvalds ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name,
1975f75268cdSRalf Baechle ax2asc(buf, &ax25->source_addr),
19761da177e4SLinus Torvalds ax25->iamdigi? "*":"");
1977f75268cdSRalf Baechle seq_printf(seq, "%s", ax2asc(buf, &ax25->dest_addr));
19781da177e4SLinus Torvalds
19791da177e4SLinus Torvalds for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) {
19801da177e4SLinus Torvalds seq_printf(seq, ",%s%s",
1981f75268cdSRalf Baechle ax2asc(buf, &ax25->digipeat->calls[k]),
19821da177e4SLinus Torvalds ax25->digipeat->repeated[k]? "*":"");
19831da177e4SLinus Torvalds }
19841da177e4SLinus Torvalds
19851da177e4SLinus Torvalds seq_printf(seq, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d",
19861da177e4SLinus Torvalds ax25->state,
19871da177e4SLinus Torvalds ax25->vs, ax25->vr, ax25->va,
19881da177e4SLinus Torvalds ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ,
19891da177e4SLinus Torvalds ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ,
19901da177e4SLinus Torvalds ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ,
19911da177e4SLinus Torvalds ax25_display_timer(&ax25->idletimer) / (60 * HZ),
19921da177e4SLinus Torvalds ax25->idle / (60 * HZ),
19931da177e4SLinus Torvalds ax25->n2count, ax25->n2,
19941da177e4SLinus Torvalds ax25->rtt / HZ,
19951da177e4SLinus Torvalds ax25->window,
19961da177e4SLinus Torvalds ax25->paclen);
19971da177e4SLinus Torvalds
19981da177e4SLinus Torvalds if (ax25->sk != NULL) {
19991105b5d1SJarek Poplawski seq_printf(seq, " %d %d %lu\n",
200031e6d363SEric Dumazet sk_wmem_alloc_get(ax25->sk),
200131e6d363SEric Dumazet sk_rmem_alloc_get(ax25->sk),
20021105b5d1SJarek Poplawski sock_i_ino(ax25->sk));
20031da177e4SLinus Torvalds } else {
20041da177e4SLinus Torvalds seq_puts(seq, " * * *\n");
20051da177e4SLinus Torvalds }
20061da177e4SLinus Torvalds return 0;
20071da177e4SLinus Torvalds }
20081da177e4SLinus Torvalds
200956b3d975SPhilippe De Muyter static const struct seq_operations ax25_info_seqops = {
20101da177e4SLinus Torvalds .start = ax25_info_start,
20111da177e4SLinus Torvalds .next = ax25_info_next,
20121da177e4SLinus Torvalds .stop = ax25_info_stop,
20131da177e4SLinus Torvalds .show = ax25_info_show,
20141da177e4SLinus Torvalds };
20151da177e4SLinus Torvalds #endif
20161da177e4SLinus Torvalds
2017ec1b4cf7SStephen Hemminger static const struct net_proto_family ax25_family_ops = {
20181da177e4SLinus Torvalds .family = PF_AX25,
20191da177e4SLinus Torvalds .create = ax25_create,
20201da177e4SLinus Torvalds .owner = THIS_MODULE,
20211da177e4SLinus Torvalds };
20221da177e4SLinus Torvalds
202390ddc4f0SEric Dumazet static const struct proto_ops ax25_proto_ops = {
20241da177e4SLinus Torvalds .family = PF_AX25,
20251da177e4SLinus Torvalds .owner = THIS_MODULE,
20261da177e4SLinus Torvalds .release = ax25_release,
20271da177e4SLinus Torvalds .bind = ax25_bind,
20281da177e4SLinus Torvalds .connect = ax25_connect,
20291da177e4SLinus Torvalds .socketpair = sock_no_socketpair,
20301da177e4SLinus Torvalds .accept = ax25_accept,
20311da177e4SLinus Torvalds .getname = ax25_getname,
2032a11e1d43SLinus Torvalds .poll = datagram_poll,
20331da177e4SLinus Torvalds .ioctl = ax25_ioctl,
2034c7cbdbf2SArnd Bergmann .gettstamp = sock_gettstamp,
20351da177e4SLinus Torvalds .listen = ax25_listen,
20361da177e4SLinus Torvalds .shutdown = ax25_shutdown,
20371da177e4SLinus Torvalds .setsockopt = ax25_setsockopt,
20381da177e4SLinus Torvalds .getsockopt = ax25_getsockopt,
20391da177e4SLinus Torvalds .sendmsg = ax25_sendmsg,
20401da177e4SLinus Torvalds .recvmsg = ax25_recvmsg,
20411da177e4SLinus Torvalds .mmap = sock_no_mmap,
20421da177e4SLinus Torvalds };
20431da177e4SLinus Torvalds
20441da177e4SLinus Torvalds /*
20451da177e4SLinus Torvalds * Called by socket.c on kernel start up
20461da177e4SLinus Torvalds */
20477546dd97SStephen Hemminger static struct packet_type ax25_packet_type __read_mostly = {
204809640e63SHarvey Harrison .type = cpu_to_be16(ETH_P_AX25),
20491da177e4SLinus Torvalds .func = ax25_kiss_rcv,
20501da177e4SLinus Torvalds };
20511da177e4SLinus Torvalds
20521da177e4SLinus Torvalds static struct notifier_block ax25_dev_notifier = {
20531da177e4SLinus Torvalds .notifier_call = ax25_device_event,
20541da177e4SLinus Torvalds };
20551da177e4SLinus Torvalds
ax25_init(void)20561da177e4SLinus Torvalds static int __init ax25_init(void)
20571da177e4SLinus Torvalds {
20581da177e4SLinus Torvalds int rc = proto_register(&ax25_proto, 0);
20591da177e4SLinus Torvalds
20601da177e4SLinus Torvalds if (rc != 0)
20611da177e4SLinus Torvalds goto out;
20621da177e4SLinus Torvalds
20631da177e4SLinus Torvalds sock_register(&ax25_family_ops);
20641da177e4SLinus Torvalds dev_add_pack(&ax25_packet_type);
20651da177e4SLinus Torvalds register_netdevice_notifier(&ax25_dev_notifier);
20661da177e4SLinus Torvalds
2067fddda2b7SChristoph Hellwig proc_create_seq("ax25_route", 0444, init_net.proc_net, &ax25_rt_seqops);
2068fddda2b7SChristoph Hellwig proc_create_seq("ax25", 0444, init_net.proc_net, &ax25_info_seqops);
2069fddda2b7SChristoph Hellwig proc_create_seq("ax25_calls", 0444, init_net.proc_net,
2070fddda2b7SChristoph Hellwig &ax25_uid_seqops);
20711da177e4SLinus Torvalds out:
20721da177e4SLinus Torvalds return rc;
20731da177e4SLinus Torvalds }
20741da177e4SLinus Torvalds module_init(ax25_init);
20751da177e4SLinus Torvalds
20761da177e4SLinus Torvalds
20771da177e4SLinus Torvalds MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
20781da177e4SLinus Torvalds MODULE_DESCRIPTION("The amateur radio AX.25 link layer protocol");
20791da177e4SLinus Torvalds MODULE_LICENSE("GPL");
20801da177e4SLinus Torvalds MODULE_ALIAS_NETPROTO(PF_AX25);
20811da177e4SLinus Torvalds
ax25_exit(void)20821da177e4SLinus Torvalds static void __exit ax25_exit(void)
20831da177e4SLinus Torvalds {
2084ece31ffdSGao feng remove_proc_entry("ax25_route", init_net.proc_net);
2085ece31ffdSGao feng remove_proc_entry("ax25", init_net.proc_net);
2086ece31ffdSGao feng remove_proc_entry("ax25_calls", init_net.proc_net);
20871da177e4SLinus Torvalds
20881da177e4SLinus Torvalds unregister_netdevice_notifier(&ax25_dev_notifier);
20891da177e4SLinus Torvalds
20901da177e4SLinus Torvalds dev_remove_pack(&ax25_packet_type);
20911da177e4SLinus Torvalds
20921da177e4SLinus Torvalds sock_unregister(PF_AX25);
20931da177e4SLinus Torvalds proto_unregister(&ax25_proto);
20943adadc08SEric W. Biederman
20953adadc08SEric W. Biederman ax25_rt_free();
20963adadc08SEric W. Biederman ax25_uid_free();
20973adadc08SEric W. Biederman ax25_dev_free();
20981da177e4SLinus Torvalds }
20991da177e4SLinus Torvalds module_exit(ax25_exit);
2100