162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk) 562306a36Sopenharmony_ci * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 662306a36Sopenharmony_ci * Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk) 762306a36Sopenharmony_ci * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org) 862306a36Sopenharmony_ci * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de) 962306a36Sopenharmony_ci * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de) 1062306a36Sopenharmony_ci * Copyright (C) Hans Alblas PE1AYX (hans@esrac.ele.tue.nl) 1162306a36Sopenharmony_ci * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr) 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#include <linux/capability.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci#include <linux/types.h> 1762306a36Sopenharmony_ci#include <linux/socket.h> 1862306a36Sopenharmony_ci#include <linux/in.h> 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/sched/signal.h> 2162306a36Sopenharmony_ci#include <linux/timer.h> 2262306a36Sopenharmony_ci#include <linux/string.h> 2362306a36Sopenharmony_ci#include <linux/sockios.h> 2462306a36Sopenharmony_ci#include <linux/net.h> 2562306a36Sopenharmony_ci#include <linux/slab.h> 2662306a36Sopenharmony_ci#include <net/ax25.h> 2762306a36Sopenharmony_ci#include <linux/inet.h> 2862306a36Sopenharmony_ci#include <linux/netdevice.h> 2962306a36Sopenharmony_ci#include <linux/if_arp.h> 3062306a36Sopenharmony_ci#include <linux/skbuff.h> 3162306a36Sopenharmony_ci#include <net/sock.h> 3262306a36Sopenharmony_ci#include <linux/uaccess.h> 3362306a36Sopenharmony_ci#include <linux/fcntl.h> 3462306a36Sopenharmony_ci#include <linux/termios.h> /* For TIOCINQ/OUTQ */ 3562306a36Sopenharmony_ci#include <linux/mm.h> 3662306a36Sopenharmony_ci#include <linux/interrupt.h> 3762306a36Sopenharmony_ci#include <linux/notifier.h> 3862306a36Sopenharmony_ci#include <linux/proc_fs.h> 3962306a36Sopenharmony_ci#include <linux/stat.h> 4062306a36Sopenharmony_ci#include <linux/sysctl.h> 4162306a36Sopenharmony_ci#include <linux/init.h> 4262306a36Sopenharmony_ci#include <linux/spinlock.h> 4362306a36Sopenharmony_ci#include <net/net_namespace.h> 4462306a36Sopenharmony_ci#include <net/tcp_states.h> 4562306a36Sopenharmony_ci#include <net/ip.h> 4662306a36Sopenharmony_ci#include <net/arp.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciHLIST_HEAD(ax25_list); 5162306a36Sopenharmony_ciDEFINE_SPINLOCK(ax25_list_lock); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic const struct proto_ops ax25_proto_ops; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void ax25_free_sock(struct sock *sk) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci ax25_cb_put(sk_to_ax25(sk)); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * Socket removal during an interrupt is now safe. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_cistatic void ax25_cb_del(ax25_cb *ax25) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci spin_lock_bh(&ax25_list_lock); 6662306a36Sopenharmony_ci if (!hlist_unhashed(&ax25->ax25_node)) { 6762306a36Sopenharmony_ci hlist_del_init(&ax25->ax25_node); 6862306a36Sopenharmony_ci ax25_cb_put(ax25); 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci spin_unlock_bh(&ax25_list_lock); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* 7462306a36Sopenharmony_ci * Kill all bound sockets on a dropped device. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_cistatic void ax25_kill_by_device(struct net_device *dev) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci ax25_dev *ax25_dev; 7962306a36Sopenharmony_ci ax25_cb *s; 8062306a36Sopenharmony_ci struct sock *sk; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) 8362306a36Sopenharmony_ci return; 8462306a36Sopenharmony_ci ax25_dev->device_up = false; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci spin_lock_bh(&ax25_list_lock); 8762306a36Sopenharmony_ciagain: 8862306a36Sopenharmony_ci ax25_for_each(s, &ax25_list) { 8962306a36Sopenharmony_ci if (s->ax25_dev == ax25_dev) { 9062306a36Sopenharmony_ci sk = s->sk; 9162306a36Sopenharmony_ci if (!sk) { 9262306a36Sopenharmony_ci spin_unlock_bh(&ax25_list_lock); 9362306a36Sopenharmony_ci ax25_disconnect(s, ENETUNREACH); 9462306a36Sopenharmony_ci s->ax25_dev = NULL; 9562306a36Sopenharmony_ci ax25_cb_del(s); 9662306a36Sopenharmony_ci spin_lock_bh(&ax25_list_lock); 9762306a36Sopenharmony_ci goto again; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci sock_hold(sk); 10062306a36Sopenharmony_ci spin_unlock_bh(&ax25_list_lock); 10162306a36Sopenharmony_ci lock_sock(sk); 10262306a36Sopenharmony_ci ax25_disconnect(s, ENETUNREACH); 10362306a36Sopenharmony_ci s->ax25_dev = NULL; 10462306a36Sopenharmony_ci if (sk->sk_socket) { 10562306a36Sopenharmony_ci netdev_put(ax25_dev->dev, 10662306a36Sopenharmony_ci &ax25_dev->dev_tracker); 10762306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci ax25_cb_del(s); 11062306a36Sopenharmony_ci release_sock(sk); 11162306a36Sopenharmony_ci spin_lock_bh(&ax25_list_lock); 11262306a36Sopenharmony_ci sock_put(sk); 11362306a36Sopenharmony_ci /* The entry could have been deleted from the 11462306a36Sopenharmony_ci * list meanwhile and thus the next pointer is 11562306a36Sopenharmony_ci * no longer valid. Play it safe and restart 11662306a36Sopenharmony_ci * the scan. Forward progress is ensured 11762306a36Sopenharmony_ci * because we set s->ax25_dev to NULL and we 11862306a36Sopenharmony_ci * are never passed a NULL 'dev' argument. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci goto again; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci spin_unlock_bh(&ax25_list_lock); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* 12762306a36Sopenharmony_ci * Handle device status changes. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_cistatic int ax25_device_event(struct notifier_block *this, unsigned long event, 13062306a36Sopenharmony_ci void *ptr) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (!net_eq(dev_net(dev), &init_net)) 13562306a36Sopenharmony_ci return NOTIFY_DONE; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Reject non AX.25 devices */ 13862306a36Sopenharmony_ci if (dev->type != ARPHRD_AX25) 13962306a36Sopenharmony_ci return NOTIFY_DONE; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci switch (event) { 14262306a36Sopenharmony_ci case NETDEV_UP: 14362306a36Sopenharmony_ci ax25_dev_device_up(dev); 14462306a36Sopenharmony_ci break; 14562306a36Sopenharmony_ci case NETDEV_DOWN: 14662306a36Sopenharmony_ci ax25_kill_by_device(dev); 14762306a36Sopenharmony_ci ax25_rt_device_down(dev); 14862306a36Sopenharmony_ci ax25_dev_device_down(dev); 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci default: 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return NOTIFY_DONE; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/* 15862306a36Sopenharmony_ci * Add a socket to the bound sockets list. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_civoid ax25_cb_add(ax25_cb *ax25) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci spin_lock_bh(&ax25_list_lock); 16362306a36Sopenharmony_ci ax25_cb_hold(ax25); 16462306a36Sopenharmony_ci hlist_add_head(&ax25->ax25_node, &ax25_list); 16562306a36Sopenharmony_ci spin_unlock_bh(&ax25_list_lock); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/* 16962306a36Sopenharmony_ci * Find a socket that wants to accept the SABM we have just 17062306a36Sopenharmony_ci * received. 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_cistruct sock *ax25_find_listener(ax25_address *addr, int digi, 17362306a36Sopenharmony_ci struct net_device *dev, int type) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci ax25_cb *s; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci spin_lock(&ax25_list_lock); 17862306a36Sopenharmony_ci ax25_for_each(s, &ax25_list) { 17962306a36Sopenharmony_ci if ((s->iamdigi && !digi) || (!s->iamdigi && digi)) 18062306a36Sopenharmony_ci continue; 18162306a36Sopenharmony_ci if (s->sk && !ax25cmp(&s->source_addr, addr) && 18262306a36Sopenharmony_ci s->sk->sk_type == type && s->sk->sk_state == TCP_LISTEN) { 18362306a36Sopenharmony_ci /* If device is null we match any device */ 18462306a36Sopenharmony_ci if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) { 18562306a36Sopenharmony_ci sock_hold(s->sk); 18662306a36Sopenharmony_ci spin_unlock(&ax25_list_lock); 18762306a36Sopenharmony_ci return s->sk; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci spin_unlock(&ax25_list_lock); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return NULL; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/* 19762306a36Sopenharmony_ci * Find an AX.25 socket given both ends. 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_cistruct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr, 20062306a36Sopenharmony_ci int type) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct sock *sk = NULL; 20362306a36Sopenharmony_ci ax25_cb *s; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci spin_lock(&ax25_list_lock); 20662306a36Sopenharmony_ci ax25_for_each(s, &ax25_list) { 20762306a36Sopenharmony_ci if (s->sk && !ax25cmp(&s->source_addr, my_addr) && 20862306a36Sopenharmony_ci !ax25cmp(&s->dest_addr, dest_addr) && 20962306a36Sopenharmony_ci s->sk->sk_type == type) { 21062306a36Sopenharmony_ci sk = s->sk; 21162306a36Sopenharmony_ci sock_hold(sk); 21262306a36Sopenharmony_ci break; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci spin_unlock(&ax25_list_lock); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return sk; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/* 22262306a36Sopenharmony_ci * Find an AX.25 control block given both ends. It will only pick up 22362306a36Sopenharmony_ci * floating AX.25 control blocks or non Raw socket bound control blocks. 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ciax25_cb *ax25_find_cb(const ax25_address *src_addr, ax25_address *dest_addr, 22662306a36Sopenharmony_ci ax25_digi *digi, struct net_device *dev) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci ax25_cb *s; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci spin_lock_bh(&ax25_list_lock); 23162306a36Sopenharmony_ci ax25_for_each(s, &ax25_list) { 23262306a36Sopenharmony_ci if (s->sk && s->sk->sk_type != SOCK_SEQPACKET) 23362306a36Sopenharmony_ci continue; 23462306a36Sopenharmony_ci if (s->ax25_dev == NULL) 23562306a36Sopenharmony_ci continue; 23662306a36Sopenharmony_ci if (ax25cmp(&s->source_addr, src_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->ax25_dev->dev == dev) { 23762306a36Sopenharmony_ci if (digi != NULL && digi->ndigi != 0) { 23862306a36Sopenharmony_ci if (s->digipeat == NULL) 23962306a36Sopenharmony_ci continue; 24062306a36Sopenharmony_ci if (ax25digicmp(s->digipeat, digi) != 0) 24162306a36Sopenharmony_ci continue; 24262306a36Sopenharmony_ci } else { 24362306a36Sopenharmony_ci if (s->digipeat != NULL && s->digipeat->ndigi != 0) 24462306a36Sopenharmony_ci continue; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci ax25_cb_hold(s); 24762306a36Sopenharmony_ci spin_unlock_bh(&ax25_list_lock); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci return s; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci spin_unlock_bh(&ax25_list_lock); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return NULL; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ciEXPORT_SYMBOL(ax25_find_cb); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_civoid ax25_send_to_raw(ax25_address *addr, struct sk_buff *skb, int proto) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci ax25_cb *s; 26262306a36Sopenharmony_ci struct sk_buff *copy; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci spin_lock(&ax25_list_lock); 26562306a36Sopenharmony_ci ax25_for_each(s, &ax25_list) { 26662306a36Sopenharmony_ci if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && 26762306a36Sopenharmony_ci s->sk->sk_type == SOCK_RAW && 26862306a36Sopenharmony_ci s->sk->sk_protocol == proto && 26962306a36Sopenharmony_ci s->ax25_dev->dev == skb->dev && 27062306a36Sopenharmony_ci atomic_read(&s->sk->sk_rmem_alloc) <= s->sk->sk_rcvbuf) { 27162306a36Sopenharmony_ci if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL) 27262306a36Sopenharmony_ci continue; 27362306a36Sopenharmony_ci if (sock_queue_rcv_skb(s->sk, copy) != 0) 27462306a36Sopenharmony_ci kfree_skb(copy); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci spin_unlock(&ax25_list_lock); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci/* 28162306a36Sopenharmony_ci * Deferred destroy. 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_civoid ax25_destroy_socket(ax25_cb *); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci/* 28662306a36Sopenharmony_ci * Handler for deferred kills. 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_cistatic void ax25_destroy_timer(struct timer_list *t) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci ax25_cb *ax25 = from_timer(ax25, t, dtimer); 29162306a36Sopenharmony_ci struct sock *sk; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci sk=ax25->sk; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci bh_lock_sock(sk); 29662306a36Sopenharmony_ci sock_hold(sk); 29762306a36Sopenharmony_ci ax25_destroy_socket(ax25); 29862306a36Sopenharmony_ci bh_unlock_sock(sk); 29962306a36Sopenharmony_ci sock_put(sk); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/* 30362306a36Sopenharmony_ci * This is called from user mode and the timers. Thus it protects itself 30462306a36Sopenharmony_ci * against interrupt users but doesn't worry about being called during 30562306a36Sopenharmony_ci * work. Once it is removed from the queue no interrupt or bottom half 30662306a36Sopenharmony_ci * will touch it and we are (fairly 8-) ) safe. 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_civoid ax25_destroy_socket(ax25_cb *ax25) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct sk_buff *skb; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci ax25_cb_del(ax25); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci ax25_stop_heartbeat(ax25); 31562306a36Sopenharmony_ci ax25_stop_t1timer(ax25); 31662306a36Sopenharmony_ci ax25_stop_t2timer(ax25); 31762306a36Sopenharmony_ci ax25_stop_t3timer(ax25); 31862306a36Sopenharmony_ci ax25_stop_idletimer(ax25); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci ax25_clear_queues(ax25); /* Flush the queues */ 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (ax25->sk != NULL) { 32362306a36Sopenharmony_ci while ((skb = skb_dequeue(&ax25->sk->sk_receive_queue)) != NULL) { 32462306a36Sopenharmony_ci if (skb->sk != ax25->sk) { 32562306a36Sopenharmony_ci /* A pending connection */ 32662306a36Sopenharmony_ci ax25_cb *sax25 = sk_to_ax25(skb->sk); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* Queue the unaccepted socket for death */ 32962306a36Sopenharmony_ci sock_orphan(skb->sk); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* 9A4GL: hack to release unaccepted sockets */ 33262306a36Sopenharmony_ci skb->sk->sk_state = TCP_LISTEN; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci ax25_start_heartbeat(sax25); 33562306a36Sopenharmony_ci sax25->state = AX25_STATE_0; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci kfree_skb(skb); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci skb_queue_purge(&ax25->sk->sk_write_queue); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (ax25->sk != NULL) { 34462306a36Sopenharmony_ci if (sk_has_allocations(ax25->sk)) { 34562306a36Sopenharmony_ci /* Defer: outstanding buffers */ 34662306a36Sopenharmony_ci timer_setup(&ax25->dtimer, ax25_destroy_timer, 0); 34762306a36Sopenharmony_ci ax25->dtimer.expires = jiffies + 2 * HZ; 34862306a36Sopenharmony_ci add_timer(&ax25->dtimer); 34962306a36Sopenharmony_ci } else { 35062306a36Sopenharmony_ci struct sock *sk=ax25->sk; 35162306a36Sopenharmony_ci ax25->sk=NULL; 35262306a36Sopenharmony_ci sock_put(sk); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci } else { 35562306a36Sopenharmony_ci ax25_cb_put(ax25); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci/* 36062306a36Sopenharmony_ci * dl1bke 960311: set parameters for existing AX.25 connections, 36162306a36Sopenharmony_ci * includes a KILL command to abort any connection. 36262306a36Sopenharmony_ci * VERY useful for debugging ;-) 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_cistatic int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct ax25_ctl_struct ax25_ctl; 36762306a36Sopenharmony_ci ax25_digi digi; 36862306a36Sopenharmony_ci ax25_dev *ax25_dev; 36962306a36Sopenharmony_ci ax25_cb *ax25; 37062306a36Sopenharmony_ci unsigned int k; 37162306a36Sopenharmony_ci int ret = 0; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl))) 37462306a36Sopenharmony_ci return -EFAULT; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (ax25_ctl.digi_count > AX25_MAX_DIGIS) 37762306a36Sopenharmony_ci return -EINVAL; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (ax25_ctl.arg > ULONG_MAX / HZ && ax25_ctl.cmd != AX25_KILL) 38062306a36Sopenharmony_ci return -EINVAL; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr); 38362306a36Sopenharmony_ci if (!ax25_dev) 38462306a36Sopenharmony_ci return -ENODEV; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci digi.ndigi = ax25_ctl.digi_count; 38762306a36Sopenharmony_ci for (k = 0; k < digi.ndigi; k++) 38862306a36Sopenharmony_ci digi.calls[k] = ax25_ctl.digi_addr[k]; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev); 39162306a36Sopenharmony_ci if (!ax25) { 39262306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 39362306a36Sopenharmony_ci return -ENOTCONN; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci switch (ax25_ctl.cmd) { 39762306a36Sopenharmony_ci case AX25_KILL: 39862306a36Sopenharmony_ci ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); 39962306a36Sopenharmony_ci#ifdef CONFIG_AX25_DAMA_SLAVE 40062306a36Sopenharmony_ci if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE) 40162306a36Sopenharmony_ci ax25_dama_off(ax25); 40262306a36Sopenharmony_ci#endif 40362306a36Sopenharmony_ci ax25_disconnect(ax25, ENETRESET); 40462306a36Sopenharmony_ci break; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci case AX25_WINDOW: 40762306a36Sopenharmony_ci if (ax25->modulus == AX25_MODULUS) { 40862306a36Sopenharmony_ci if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7) 40962306a36Sopenharmony_ci goto einval_put; 41062306a36Sopenharmony_ci } else { 41162306a36Sopenharmony_ci if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63) 41262306a36Sopenharmony_ci goto einval_put; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci ax25->window = ax25_ctl.arg; 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci case AX25_T1: 41862306a36Sopenharmony_ci if (ax25_ctl.arg < 1 || ax25_ctl.arg > ULONG_MAX / HZ) 41962306a36Sopenharmony_ci goto einval_put; 42062306a36Sopenharmony_ci ax25->rtt = (ax25_ctl.arg * HZ) / 2; 42162306a36Sopenharmony_ci ax25->t1 = ax25_ctl.arg * HZ; 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci case AX25_T2: 42562306a36Sopenharmony_ci if (ax25_ctl.arg < 1 || ax25_ctl.arg > ULONG_MAX / HZ) 42662306a36Sopenharmony_ci goto einval_put; 42762306a36Sopenharmony_ci ax25->t2 = ax25_ctl.arg * HZ; 42862306a36Sopenharmony_ci break; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci case AX25_N2: 43162306a36Sopenharmony_ci if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31) 43262306a36Sopenharmony_ci goto einval_put; 43362306a36Sopenharmony_ci ax25->n2count = 0; 43462306a36Sopenharmony_ci ax25->n2 = ax25_ctl.arg; 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci case AX25_T3: 43862306a36Sopenharmony_ci if (ax25_ctl.arg > ULONG_MAX / HZ) 43962306a36Sopenharmony_ci goto einval_put; 44062306a36Sopenharmony_ci ax25->t3 = ax25_ctl.arg * HZ; 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci case AX25_IDLE: 44462306a36Sopenharmony_ci if (ax25_ctl.arg > ULONG_MAX / (60 * HZ)) 44562306a36Sopenharmony_ci goto einval_put; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci ax25->idle = ax25_ctl.arg * 60 * HZ; 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci case AX25_PACLEN: 45162306a36Sopenharmony_ci if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535) 45262306a36Sopenharmony_ci goto einval_put; 45362306a36Sopenharmony_ci ax25->paclen = ax25_ctl.arg; 45462306a36Sopenharmony_ci break; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci default: 45762306a36Sopenharmony_ci goto einval_put; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ciout_put: 46162306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 46262306a36Sopenharmony_ci ax25_cb_put(ax25); 46362306a36Sopenharmony_ci return ret; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cieinval_put: 46662306a36Sopenharmony_ci ret = -EINVAL; 46762306a36Sopenharmony_ci goto out_put; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic void ax25_fillin_cb_from_dev(ax25_cb *ax25, ax25_dev *ax25_dev) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci ax25->rtt = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]) / 2; 47362306a36Sopenharmony_ci ax25->t1 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]); 47462306a36Sopenharmony_ci ax25->t2 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T2]); 47562306a36Sopenharmony_ci ax25->t3 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T3]); 47662306a36Sopenharmony_ci ax25->n2 = ax25_dev->values[AX25_VALUES_N2]; 47762306a36Sopenharmony_ci ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN]; 47862306a36Sopenharmony_ci ax25->idle = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_IDLE]); 47962306a36Sopenharmony_ci ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF]; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) { 48262306a36Sopenharmony_ci ax25->modulus = AX25_EMODULUS; 48362306a36Sopenharmony_ci ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; 48462306a36Sopenharmony_ci } else { 48562306a36Sopenharmony_ci ax25->modulus = AX25_MODULUS; 48662306a36Sopenharmony_ci ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/* 49162306a36Sopenharmony_ci * Fill in a created AX.25 created control block with the default 49262306a36Sopenharmony_ci * values for a particular device. 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_civoid ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci ax25->ax25_dev = ax25_dev; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (ax25->ax25_dev != NULL) { 49962306a36Sopenharmony_ci ax25_fillin_cb_from_dev(ax25, ax25_dev); 50062306a36Sopenharmony_ci return; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* 50462306a36Sopenharmony_ci * No device, use kernel / AX.25 spec default values 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_ci ax25->rtt = msecs_to_jiffies(AX25_DEF_T1) / 2; 50762306a36Sopenharmony_ci ax25->t1 = msecs_to_jiffies(AX25_DEF_T1); 50862306a36Sopenharmony_ci ax25->t2 = msecs_to_jiffies(AX25_DEF_T2); 50962306a36Sopenharmony_ci ax25->t3 = msecs_to_jiffies(AX25_DEF_T3); 51062306a36Sopenharmony_ci ax25->n2 = AX25_DEF_N2; 51162306a36Sopenharmony_ci ax25->paclen = AX25_DEF_PACLEN; 51262306a36Sopenharmony_ci ax25->idle = msecs_to_jiffies(AX25_DEF_IDLE); 51362306a36Sopenharmony_ci ax25->backoff = AX25_DEF_BACKOFF; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (AX25_DEF_AXDEFMODE) { 51662306a36Sopenharmony_ci ax25->modulus = AX25_EMODULUS; 51762306a36Sopenharmony_ci ax25->window = AX25_DEF_EWINDOW; 51862306a36Sopenharmony_ci } else { 51962306a36Sopenharmony_ci ax25->modulus = AX25_MODULUS; 52062306a36Sopenharmony_ci ax25->window = AX25_DEF_WINDOW; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci/* 52562306a36Sopenharmony_ci * Create an empty AX.25 control block. 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_ciax25_cb *ax25_create_cb(void) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci ax25_cb *ax25; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if ((ax25 = kzalloc(sizeof(*ax25), GFP_ATOMIC)) == NULL) 53262306a36Sopenharmony_ci return NULL; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci refcount_set(&ax25->refcount, 1); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci skb_queue_head_init(&ax25->write_queue); 53762306a36Sopenharmony_ci skb_queue_head_init(&ax25->frag_queue); 53862306a36Sopenharmony_ci skb_queue_head_init(&ax25->ack_queue); 53962306a36Sopenharmony_ci skb_queue_head_init(&ax25->reseq_queue); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci ax25_setup_timers(ax25); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci ax25_fillin_cb(ax25, NULL); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci ax25->state = AX25_STATE_0; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci return ax25; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci/* 55162306a36Sopenharmony_ci * Handling for system calls applied via the various interfaces to an 55262306a36Sopenharmony_ci * AX25 socket object 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic int ax25_setsockopt(struct socket *sock, int level, int optname, 55662306a36Sopenharmony_ci sockptr_t optval, unsigned int optlen) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct sock *sk = sock->sk; 55962306a36Sopenharmony_ci ax25_cb *ax25; 56062306a36Sopenharmony_ci struct net_device *dev; 56162306a36Sopenharmony_ci char devname[IFNAMSIZ]; 56262306a36Sopenharmony_ci unsigned int opt; 56362306a36Sopenharmony_ci int res = 0; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (level != SOL_AX25) 56662306a36Sopenharmony_ci return -ENOPROTOOPT; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (optlen < sizeof(unsigned int)) 56962306a36Sopenharmony_ci return -EINVAL; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (copy_from_sockptr(&opt, optval, sizeof(unsigned int))) 57262306a36Sopenharmony_ci return -EFAULT; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci lock_sock(sk); 57562306a36Sopenharmony_ci ax25 = sk_to_ax25(sk); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci switch (optname) { 57862306a36Sopenharmony_ci case AX25_WINDOW: 57962306a36Sopenharmony_ci if (ax25->modulus == AX25_MODULUS) { 58062306a36Sopenharmony_ci if (opt < 1 || opt > 7) { 58162306a36Sopenharmony_ci res = -EINVAL; 58262306a36Sopenharmony_ci break; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci } else { 58562306a36Sopenharmony_ci if (opt < 1 || opt > 63) { 58662306a36Sopenharmony_ci res = -EINVAL; 58762306a36Sopenharmony_ci break; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci ax25->window = opt; 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci case AX25_T1: 59462306a36Sopenharmony_ci if (opt < 1 || opt > UINT_MAX / HZ) { 59562306a36Sopenharmony_ci res = -EINVAL; 59662306a36Sopenharmony_ci break; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci ax25->rtt = (opt * HZ) >> 1; 59962306a36Sopenharmony_ci ax25->t1 = opt * HZ; 60062306a36Sopenharmony_ci break; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci case AX25_T2: 60362306a36Sopenharmony_ci if (opt < 1 || opt > UINT_MAX / HZ) { 60462306a36Sopenharmony_ci res = -EINVAL; 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci ax25->t2 = opt * HZ; 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci case AX25_N2: 61162306a36Sopenharmony_ci if (opt < 1 || opt > 31) { 61262306a36Sopenharmony_ci res = -EINVAL; 61362306a36Sopenharmony_ci break; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci ax25->n2 = opt; 61662306a36Sopenharmony_ci break; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci case AX25_T3: 61962306a36Sopenharmony_ci if (opt < 1 || opt > UINT_MAX / HZ) { 62062306a36Sopenharmony_ci res = -EINVAL; 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci ax25->t3 = opt * HZ; 62462306a36Sopenharmony_ci break; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci case AX25_IDLE: 62762306a36Sopenharmony_ci if (opt > UINT_MAX / (60 * HZ)) { 62862306a36Sopenharmony_ci res = -EINVAL; 62962306a36Sopenharmony_ci break; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci ax25->idle = opt * 60 * HZ; 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci case AX25_BACKOFF: 63562306a36Sopenharmony_ci if (opt > 2) { 63662306a36Sopenharmony_ci res = -EINVAL; 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci ax25->backoff = opt; 64062306a36Sopenharmony_ci break; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci case AX25_EXTSEQ: 64362306a36Sopenharmony_ci ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS; 64462306a36Sopenharmony_ci break; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci case AX25_PIDINCL: 64762306a36Sopenharmony_ci ax25->pidincl = opt ? 1 : 0; 64862306a36Sopenharmony_ci break; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci case AX25_IAMDIGI: 65162306a36Sopenharmony_ci ax25->iamdigi = opt ? 1 : 0; 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci case AX25_PACLEN: 65562306a36Sopenharmony_ci if (opt < 16 || opt > 65535) { 65662306a36Sopenharmony_ci res = -EINVAL; 65762306a36Sopenharmony_ci break; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci ax25->paclen = opt; 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci case SO_BINDTODEVICE: 66362306a36Sopenharmony_ci if (optlen > IFNAMSIZ - 1) 66462306a36Sopenharmony_ci optlen = IFNAMSIZ - 1; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci memset(devname, 0, sizeof(devname)); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (copy_from_sockptr(devname, optval, optlen)) { 66962306a36Sopenharmony_ci res = -EFAULT; 67062306a36Sopenharmony_ci break; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (sk->sk_type == SOCK_SEQPACKET && 67462306a36Sopenharmony_ci (sock->state != SS_UNCONNECTED || 67562306a36Sopenharmony_ci sk->sk_state == TCP_LISTEN)) { 67662306a36Sopenharmony_ci res = -EADDRNOTAVAIL; 67762306a36Sopenharmony_ci break; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci rtnl_lock(); 68162306a36Sopenharmony_ci dev = __dev_get_by_name(&init_net, devname); 68262306a36Sopenharmony_ci if (!dev) { 68362306a36Sopenharmony_ci rtnl_unlock(); 68462306a36Sopenharmony_ci res = -ENODEV; 68562306a36Sopenharmony_ci break; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci ax25->ax25_dev = ax25_dev_ax25dev(dev); 68962306a36Sopenharmony_ci if (!ax25->ax25_dev) { 69062306a36Sopenharmony_ci rtnl_unlock(); 69162306a36Sopenharmony_ci res = -ENODEV; 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci ax25_fillin_cb(ax25, ax25->ax25_dev); 69562306a36Sopenharmony_ci rtnl_unlock(); 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci default: 69962306a36Sopenharmony_ci res = -ENOPROTOOPT; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci release_sock(sk); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci return res; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic int ax25_getsockopt(struct socket *sock, int level, int optname, 70762306a36Sopenharmony_ci char __user *optval, int __user *optlen) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci struct sock *sk = sock->sk; 71062306a36Sopenharmony_ci ax25_cb *ax25; 71162306a36Sopenharmony_ci struct ax25_dev *ax25_dev; 71262306a36Sopenharmony_ci char devname[IFNAMSIZ]; 71362306a36Sopenharmony_ci void *valptr; 71462306a36Sopenharmony_ci int val = 0; 71562306a36Sopenharmony_ci int maxlen, length; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci if (level != SOL_AX25) 71862306a36Sopenharmony_ci return -ENOPROTOOPT; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (get_user(maxlen, optlen)) 72162306a36Sopenharmony_ci return -EFAULT; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (maxlen < 1) 72462306a36Sopenharmony_ci return -EFAULT; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci valptr = &val; 72762306a36Sopenharmony_ci length = min_t(unsigned int, maxlen, sizeof(int)); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci lock_sock(sk); 73062306a36Sopenharmony_ci ax25 = sk_to_ax25(sk); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci switch (optname) { 73362306a36Sopenharmony_ci case AX25_WINDOW: 73462306a36Sopenharmony_ci val = ax25->window; 73562306a36Sopenharmony_ci break; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci case AX25_T1: 73862306a36Sopenharmony_ci val = ax25->t1 / HZ; 73962306a36Sopenharmony_ci break; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci case AX25_T2: 74262306a36Sopenharmony_ci val = ax25->t2 / HZ; 74362306a36Sopenharmony_ci break; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci case AX25_N2: 74662306a36Sopenharmony_ci val = ax25->n2; 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci case AX25_T3: 75062306a36Sopenharmony_ci val = ax25->t3 / HZ; 75162306a36Sopenharmony_ci break; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci case AX25_IDLE: 75462306a36Sopenharmony_ci val = ax25->idle / (60 * HZ); 75562306a36Sopenharmony_ci break; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci case AX25_BACKOFF: 75862306a36Sopenharmony_ci val = ax25->backoff; 75962306a36Sopenharmony_ci break; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci case AX25_EXTSEQ: 76262306a36Sopenharmony_ci val = (ax25->modulus == AX25_EMODULUS); 76362306a36Sopenharmony_ci break; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci case AX25_PIDINCL: 76662306a36Sopenharmony_ci val = ax25->pidincl; 76762306a36Sopenharmony_ci break; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci case AX25_IAMDIGI: 77062306a36Sopenharmony_ci val = ax25->iamdigi; 77162306a36Sopenharmony_ci break; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci case AX25_PACLEN: 77462306a36Sopenharmony_ci val = ax25->paclen; 77562306a36Sopenharmony_ci break; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci case SO_BINDTODEVICE: 77862306a36Sopenharmony_ci ax25_dev = ax25->ax25_dev; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (ax25_dev != NULL && ax25_dev->dev != NULL) { 78162306a36Sopenharmony_ci strscpy(devname, ax25_dev->dev->name, sizeof(devname)); 78262306a36Sopenharmony_ci length = strlen(devname) + 1; 78362306a36Sopenharmony_ci } else { 78462306a36Sopenharmony_ci *devname = '\0'; 78562306a36Sopenharmony_ci length = 1; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci valptr = devname; 78962306a36Sopenharmony_ci break; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci default: 79262306a36Sopenharmony_ci release_sock(sk); 79362306a36Sopenharmony_ci return -ENOPROTOOPT; 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci release_sock(sk); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (put_user(length, optlen)) 79862306a36Sopenharmony_ci return -EFAULT; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci return copy_to_user(optval, valptr, length) ? -EFAULT : 0; 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic int ax25_listen(struct socket *sock, int backlog) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci struct sock *sk = sock->sk; 80662306a36Sopenharmony_ci int res = 0; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci lock_sock(sk); 80962306a36Sopenharmony_ci if (sk->sk_type == SOCK_SEQPACKET && sk->sk_state != TCP_LISTEN) { 81062306a36Sopenharmony_ci sk->sk_max_ack_backlog = backlog; 81162306a36Sopenharmony_ci sk->sk_state = TCP_LISTEN; 81262306a36Sopenharmony_ci goto out; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci res = -EOPNOTSUPP; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ciout: 81762306a36Sopenharmony_ci release_sock(sk); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci return res; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci/* 82362306a36Sopenharmony_ci * XXX: when creating ax25_sock we should update the .obj_size setting 82462306a36Sopenharmony_ci * below. 82562306a36Sopenharmony_ci */ 82662306a36Sopenharmony_cistatic struct proto ax25_proto = { 82762306a36Sopenharmony_ci .name = "AX25", 82862306a36Sopenharmony_ci .owner = THIS_MODULE, 82962306a36Sopenharmony_ci .obj_size = sizeof(struct ax25_sock), 83062306a36Sopenharmony_ci}; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic int ax25_create(struct net *net, struct socket *sock, int protocol, 83362306a36Sopenharmony_ci int kern) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci struct sock *sk; 83662306a36Sopenharmony_ci ax25_cb *ax25; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (protocol < 0 || protocol > U8_MAX) 83962306a36Sopenharmony_ci return -EINVAL; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci if (!net_eq(net, &init_net)) 84262306a36Sopenharmony_ci return -EAFNOSUPPORT; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci switch (sock->type) { 84562306a36Sopenharmony_ci case SOCK_DGRAM: 84662306a36Sopenharmony_ci if (protocol == 0 || protocol == PF_AX25) 84762306a36Sopenharmony_ci protocol = AX25_P_TEXT; 84862306a36Sopenharmony_ci break; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci case SOCK_SEQPACKET: 85162306a36Sopenharmony_ci switch (protocol) { 85262306a36Sopenharmony_ci case 0: 85362306a36Sopenharmony_ci case PF_AX25: /* For CLX */ 85462306a36Sopenharmony_ci protocol = AX25_P_TEXT; 85562306a36Sopenharmony_ci break; 85662306a36Sopenharmony_ci case AX25_P_SEGMENT: 85762306a36Sopenharmony_ci#ifdef CONFIG_INET 85862306a36Sopenharmony_ci case AX25_P_ARP: 85962306a36Sopenharmony_ci case AX25_P_IP: 86062306a36Sopenharmony_ci#endif 86162306a36Sopenharmony_ci#ifdef CONFIG_NETROM 86262306a36Sopenharmony_ci case AX25_P_NETROM: 86362306a36Sopenharmony_ci#endif 86462306a36Sopenharmony_ci#ifdef CONFIG_ROSE 86562306a36Sopenharmony_ci case AX25_P_ROSE: 86662306a36Sopenharmony_ci#endif 86762306a36Sopenharmony_ci return -ESOCKTNOSUPPORT; 86862306a36Sopenharmony_ci#ifdef CONFIG_NETROM_MODULE 86962306a36Sopenharmony_ci case AX25_P_NETROM: 87062306a36Sopenharmony_ci if (ax25_protocol_is_registered(AX25_P_NETROM)) 87162306a36Sopenharmony_ci return -ESOCKTNOSUPPORT; 87262306a36Sopenharmony_ci break; 87362306a36Sopenharmony_ci#endif 87462306a36Sopenharmony_ci#ifdef CONFIG_ROSE_MODULE 87562306a36Sopenharmony_ci case AX25_P_ROSE: 87662306a36Sopenharmony_ci if (ax25_protocol_is_registered(AX25_P_ROSE)) 87762306a36Sopenharmony_ci return -ESOCKTNOSUPPORT; 87862306a36Sopenharmony_ci break; 87962306a36Sopenharmony_ci#endif 88062306a36Sopenharmony_ci default: 88162306a36Sopenharmony_ci break; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci break; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci case SOCK_RAW: 88662306a36Sopenharmony_ci if (!capable(CAP_NET_RAW)) 88762306a36Sopenharmony_ci return -EPERM; 88862306a36Sopenharmony_ci break; 88962306a36Sopenharmony_ci default: 89062306a36Sopenharmony_ci return -ESOCKTNOSUPPORT; 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci sk = sk_alloc(net, PF_AX25, GFP_ATOMIC, &ax25_proto, kern); 89462306a36Sopenharmony_ci if (sk == NULL) 89562306a36Sopenharmony_ci return -ENOMEM; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci ax25 = ax25_sk(sk)->cb = ax25_create_cb(); 89862306a36Sopenharmony_ci if (!ax25) { 89962306a36Sopenharmony_ci sk_free(sk); 90062306a36Sopenharmony_ci return -ENOMEM; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci sock_init_data(sock, sk); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci sk->sk_destruct = ax25_free_sock; 90662306a36Sopenharmony_ci sock->ops = &ax25_proto_ops; 90762306a36Sopenharmony_ci sk->sk_protocol = protocol; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci ax25->sk = sk; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return 0; 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistruct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci struct sock *sk; 91762306a36Sopenharmony_ci ax25_cb *ax25, *oax25; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci sk = sk_alloc(sock_net(osk), PF_AX25, GFP_ATOMIC, osk->sk_prot, 0); 92062306a36Sopenharmony_ci if (sk == NULL) 92162306a36Sopenharmony_ci return NULL; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if ((ax25 = ax25_create_cb()) == NULL) { 92462306a36Sopenharmony_ci sk_free(sk); 92562306a36Sopenharmony_ci return NULL; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci switch (osk->sk_type) { 92962306a36Sopenharmony_ci case SOCK_DGRAM: 93062306a36Sopenharmony_ci break; 93162306a36Sopenharmony_ci case SOCK_SEQPACKET: 93262306a36Sopenharmony_ci break; 93362306a36Sopenharmony_ci default: 93462306a36Sopenharmony_ci sk_free(sk); 93562306a36Sopenharmony_ci ax25_cb_put(ax25); 93662306a36Sopenharmony_ci return NULL; 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci sock_init_data(NULL, sk); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci sk->sk_type = osk->sk_type; 94262306a36Sopenharmony_ci sk->sk_priority = osk->sk_priority; 94362306a36Sopenharmony_ci sk->sk_protocol = osk->sk_protocol; 94462306a36Sopenharmony_ci sk->sk_rcvbuf = osk->sk_rcvbuf; 94562306a36Sopenharmony_ci sk->sk_sndbuf = osk->sk_sndbuf; 94662306a36Sopenharmony_ci sk->sk_state = TCP_ESTABLISHED; 94762306a36Sopenharmony_ci sock_copy_flags(sk, osk); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci oax25 = sk_to_ax25(osk); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci ax25->modulus = oax25->modulus; 95262306a36Sopenharmony_ci ax25->backoff = oax25->backoff; 95362306a36Sopenharmony_ci ax25->pidincl = oax25->pidincl; 95462306a36Sopenharmony_ci ax25->iamdigi = oax25->iamdigi; 95562306a36Sopenharmony_ci ax25->rtt = oax25->rtt; 95662306a36Sopenharmony_ci ax25->t1 = oax25->t1; 95762306a36Sopenharmony_ci ax25->t2 = oax25->t2; 95862306a36Sopenharmony_ci ax25->t3 = oax25->t3; 95962306a36Sopenharmony_ci ax25->n2 = oax25->n2; 96062306a36Sopenharmony_ci ax25->idle = oax25->idle; 96162306a36Sopenharmony_ci ax25->paclen = oax25->paclen; 96262306a36Sopenharmony_ci ax25->window = oax25->window; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci ax25->ax25_dev = ax25_dev; 96562306a36Sopenharmony_ci ax25->source_addr = oax25->source_addr; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci if (oax25->digipeat != NULL) { 96862306a36Sopenharmony_ci ax25->digipeat = kmemdup(oax25->digipeat, sizeof(ax25_digi), 96962306a36Sopenharmony_ci GFP_ATOMIC); 97062306a36Sopenharmony_ci if (ax25->digipeat == NULL) { 97162306a36Sopenharmony_ci sk_free(sk); 97262306a36Sopenharmony_ci ax25_cb_put(ax25); 97362306a36Sopenharmony_ci return NULL; 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci ax25_sk(sk)->cb = ax25; 97862306a36Sopenharmony_ci sk->sk_destruct = ax25_free_sock; 97962306a36Sopenharmony_ci ax25->sk = sk; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci return sk; 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_cistatic int ax25_release(struct socket *sock) 98562306a36Sopenharmony_ci{ 98662306a36Sopenharmony_ci struct sock *sk = sock->sk; 98762306a36Sopenharmony_ci ax25_cb *ax25; 98862306a36Sopenharmony_ci ax25_dev *ax25_dev; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (sk == NULL) 99162306a36Sopenharmony_ci return 0; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci sock_hold(sk); 99462306a36Sopenharmony_ci lock_sock(sk); 99562306a36Sopenharmony_ci sock_orphan(sk); 99662306a36Sopenharmony_ci ax25 = sk_to_ax25(sk); 99762306a36Sopenharmony_ci ax25_dev = ax25->ax25_dev; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci if (sk->sk_type == SOCK_SEQPACKET) { 100062306a36Sopenharmony_ci switch (ax25->state) { 100162306a36Sopenharmony_ci case AX25_STATE_0: 100262306a36Sopenharmony_ci if (!sock_flag(ax25->sk, SOCK_DEAD)) { 100362306a36Sopenharmony_ci release_sock(sk); 100462306a36Sopenharmony_ci ax25_disconnect(ax25, 0); 100562306a36Sopenharmony_ci lock_sock(sk); 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci ax25_destroy_socket(ax25); 100862306a36Sopenharmony_ci break; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci case AX25_STATE_1: 101162306a36Sopenharmony_ci case AX25_STATE_2: 101262306a36Sopenharmony_ci ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); 101362306a36Sopenharmony_ci release_sock(sk); 101462306a36Sopenharmony_ci ax25_disconnect(ax25, 0); 101562306a36Sopenharmony_ci lock_sock(sk); 101662306a36Sopenharmony_ci if (!sock_flag(ax25->sk, SOCK_DESTROY)) 101762306a36Sopenharmony_ci ax25_destroy_socket(ax25); 101862306a36Sopenharmony_ci break; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci case AX25_STATE_3: 102162306a36Sopenharmony_ci case AX25_STATE_4: 102262306a36Sopenharmony_ci ax25_clear_queues(ax25); 102362306a36Sopenharmony_ci ax25->n2count = 0; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { 102662306a36Sopenharmony_ci case AX25_PROTO_STD_SIMPLEX: 102762306a36Sopenharmony_ci case AX25_PROTO_STD_DUPLEX: 102862306a36Sopenharmony_ci ax25_send_control(ax25, 102962306a36Sopenharmony_ci AX25_DISC, 103062306a36Sopenharmony_ci AX25_POLLON, 103162306a36Sopenharmony_ci AX25_COMMAND); 103262306a36Sopenharmony_ci ax25_stop_t2timer(ax25); 103362306a36Sopenharmony_ci ax25_stop_t3timer(ax25); 103462306a36Sopenharmony_ci ax25_stop_idletimer(ax25); 103562306a36Sopenharmony_ci break; 103662306a36Sopenharmony_ci#ifdef CONFIG_AX25_DAMA_SLAVE 103762306a36Sopenharmony_ci case AX25_PROTO_DAMA_SLAVE: 103862306a36Sopenharmony_ci ax25_stop_t3timer(ax25); 103962306a36Sopenharmony_ci ax25_stop_idletimer(ax25); 104062306a36Sopenharmony_ci break; 104162306a36Sopenharmony_ci#endif 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci ax25_calculate_t1(ax25); 104462306a36Sopenharmony_ci ax25_start_t1timer(ax25); 104562306a36Sopenharmony_ci ax25->state = AX25_STATE_2; 104662306a36Sopenharmony_ci sk->sk_state = TCP_CLOSE; 104762306a36Sopenharmony_ci sk->sk_shutdown |= SEND_SHUTDOWN; 104862306a36Sopenharmony_ci sk->sk_state_change(sk); 104962306a36Sopenharmony_ci sock_set_flag(sk, SOCK_DESTROY); 105062306a36Sopenharmony_ci break; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci default: 105362306a36Sopenharmony_ci break; 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci } else { 105662306a36Sopenharmony_ci sk->sk_state = TCP_CLOSE; 105762306a36Sopenharmony_ci sk->sk_shutdown |= SEND_SHUTDOWN; 105862306a36Sopenharmony_ci sk->sk_state_change(sk); 105962306a36Sopenharmony_ci ax25_destroy_socket(ax25); 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci if (ax25_dev) { 106262306a36Sopenharmony_ci if (!ax25_dev->device_up) { 106362306a36Sopenharmony_ci del_timer_sync(&ax25->timer); 106462306a36Sopenharmony_ci del_timer_sync(&ax25->t1timer); 106562306a36Sopenharmony_ci del_timer_sync(&ax25->t2timer); 106662306a36Sopenharmony_ci del_timer_sync(&ax25->t3timer); 106762306a36Sopenharmony_ci del_timer_sync(&ax25->idletimer); 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci netdev_put(ax25_dev->dev, &ax25->dev_tracker); 107062306a36Sopenharmony_ci ax25_dev_put(ax25_dev); 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci sock->sk = NULL; 107462306a36Sopenharmony_ci release_sock(sk); 107562306a36Sopenharmony_ci sock_put(sk); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci return 0; 107862306a36Sopenharmony_ci} 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci/* 108162306a36Sopenharmony_ci * We support a funny extension here so you can (as root) give any callsign 108262306a36Sopenharmony_ci * digipeated via a local address as source. This hack is obsolete now 108362306a36Sopenharmony_ci * that we've implemented support for SO_BINDTODEVICE. It is however small 108462306a36Sopenharmony_ci * and trivially backward compatible. 108562306a36Sopenharmony_ci */ 108662306a36Sopenharmony_cistatic int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci struct sock *sk = sock->sk; 108962306a36Sopenharmony_ci struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; 109062306a36Sopenharmony_ci ax25_dev *ax25_dev = NULL; 109162306a36Sopenharmony_ci ax25_uid_assoc *user; 109262306a36Sopenharmony_ci ax25_address call; 109362306a36Sopenharmony_ci ax25_cb *ax25; 109462306a36Sopenharmony_ci int err = 0; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (addr_len != sizeof(struct sockaddr_ax25) && 109762306a36Sopenharmony_ci addr_len != sizeof(struct full_sockaddr_ax25)) 109862306a36Sopenharmony_ci /* support for old structure may go away some time 109962306a36Sopenharmony_ci * ax25_bind(): uses old (6 digipeater) socket structure. 110062306a36Sopenharmony_ci */ 110162306a36Sopenharmony_ci if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || 110262306a36Sopenharmony_ci (addr_len > sizeof(struct full_sockaddr_ax25))) 110362306a36Sopenharmony_ci return -EINVAL; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (addr->fsa_ax25.sax25_family != AF_AX25) 110662306a36Sopenharmony_ci return -EINVAL; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci user = ax25_findbyuid(current_euid()); 110962306a36Sopenharmony_ci if (user) { 111062306a36Sopenharmony_ci call = user->call; 111162306a36Sopenharmony_ci ax25_uid_put(user); 111262306a36Sopenharmony_ci } else { 111362306a36Sopenharmony_ci if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) 111462306a36Sopenharmony_ci return -EACCES; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci call = addr->fsa_ax25.sax25_call; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci lock_sock(sk); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci ax25 = sk_to_ax25(sk); 112262306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_ZAPPED)) { 112362306a36Sopenharmony_ci err = -EINVAL; 112462306a36Sopenharmony_ci goto out; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci ax25->source_addr = call; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci /* 113062306a36Sopenharmony_ci * User already set interface with SO_BINDTODEVICE 113162306a36Sopenharmony_ci */ 113262306a36Sopenharmony_ci if (ax25->ax25_dev != NULL) 113362306a36Sopenharmony_ci goto done; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) { 113662306a36Sopenharmony_ci if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 && 113762306a36Sopenharmony_ci (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) { 113862306a36Sopenharmony_ci err = -EADDRNOTAVAIL; 113962306a36Sopenharmony_ci goto out; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci } else { 114262306a36Sopenharmony_ci if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) { 114362306a36Sopenharmony_ci err = -EADDRNOTAVAIL; 114462306a36Sopenharmony_ci goto out; 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci } 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci if (ax25_dev) { 114962306a36Sopenharmony_ci ax25_fillin_cb(ax25, ax25_dev); 115062306a36Sopenharmony_ci netdev_hold(ax25_dev->dev, &ax25->dev_tracker, GFP_ATOMIC); 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_cidone: 115462306a36Sopenharmony_ci ax25_cb_add(ax25); 115562306a36Sopenharmony_ci sock_reset_flag(sk, SOCK_ZAPPED); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ciout: 115862306a36Sopenharmony_ci release_sock(sk); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci return err; 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci/* 116462306a36Sopenharmony_ci * FIXME: nonblock behaviour looks like it may have a bug. 116562306a36Sopenharmony_ci */ 116662306a36Sopenharmony_cistatic int __must_check ax25_connect(struct socket *sock, 116762306a36Sopenharmony_ci struct sockaddr *uaddr, int addr_len, int flags) 116862306a36Sopenharmony_ci{ 116962306a36Sopenharmony_ci struct sock *sk = sock->sk; 117062306a36Sopenharmony_ci ax25_cb *ax25 = sk_to_ax25(sk), *ax25t; 117162306a36Sopenharmony_ci struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr; 117262306a36Sopenharmony_ci ax25_digi *digi = NULL; 117362306a36Sopenharmony_ci int ct = 0, err = 0; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci /* 117662306a36Sopenharmony_ci * some sanity checks. code further down depends on this 117762306a36Sopenharmony_ci */ 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci if (addr_len == sizeof(struct sockaddr_ax25)) 118062306a36Sopenharmony_ci /* support for this will go away in early 2.5.x 118162306a36Sopenharmony_ci * ax25_connect(): uses obsolete socket structure 118262306a36Sopenharmony_ci */ 118362306a36Sopenharmony_ci ; 118462306a36Sopenharmony_ci else if (addr_len != sizeof(struct full_sockaddr_ax25)) 118562306a36Sopenharmony_ci /* support for old structure may go away some time 118662306a36Sopenharmony_ci * ax25_connect(): uses old (6 digipeater) socket structure. 118762306a36Sopenharmony_ci */ 118862306a36Sopenharmony_ci if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || 118962306a36Sopenharmony_ci (addr_len > sizeof(struct full_sockaddr_ax25))) 119062306a36Sopenharmony_ci return -EINVAL; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci if (fsa->fsa_ax25.sax25_family != AF_AX25) 119462306a36Sopenharmony_ci return -EINVAL; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci lock_sock(sk); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci /* deal with restarts */ 119962306a36Sopenharmony_ci if (sock->state == SS_CONNECTING) { 120062306a36Sopenharmony_ci switch (sk->sk_state) { 120162306a36Sopenharmony_ci case TCP_SYN_SENT: /* still trying */ 120262306a36Sopenharmony_ci err = -EINPROGRESS; 120362306a36Sopenharmony_ci goto out_release; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci case TCP_ESTABLISHED: /* connection established */ 120662306a36Sopenharmony_ci sock->state = SS_CONNECTED; 120762306a36Sopenharmony_ci goto out_release; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci case TCP_CLOSE: /* connection refused */ 121062306a36Sopenharmony_ci sock->state = SS_UNCONNECTED; 121162306a36Sopenharmony_ci err = -ECONNREFUSED; 121262306a36Sopenharmony_ci goto out_release; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (sk->sk_state == TCP_ESTABLISHED && sk->sk_type == SOCK_SEQPACKET) { 121762306a36Sopenharmony_ci err = -EISCONN; /* No reconnect on a seqpacket socket */ 121862306a36Sopenharmony_ci goto out_release; 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci sk->sk_state = TCP_CLOSE; 122262306a36Sopenharmony_ci sock->state = SS_UNCONNECTED; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci kfree(ax25->digipeat); 122562306a36Sopenharmony_ci ax25->digipeat = NULL; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci /* 122862306a36Sopenharmony_ci * Handle digi-peaters to be used. 122962306a36Sopenharmony_ci */ 123062306a36Sopenharmony_ci if (addr_len > sizeof(struct sockaddr_ax25) && 123162306a36Sopenharmony_ci fsa->fsa_ax25.sax25_ndigis != 0) { 123262306a36Sopenharmony_ci /* Valid number of digipeaters ? */ 123362306a36Sopenharmony_ci if (fsa->fsa_ax25.sax25_ndigis < 1 || 123462306a36Sopenharmony_ci fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS || 123562306a36Sopenharmony_ci addr_len < sizeof(struct sockaddr_ax25) + 123662306a36Sopenharmony_ci sizeof(ax25_address) * fsa->fsa_ax25.sax25_ndigis) { 123762306a36Sopenharmony_ci err = -EINVAL; 123862306a36Sopenharmony_ci goto out_release; 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) { 124262306a36Sopenharmony_ci err = -ENOBUFS; 124362306a36Sopenharmony_ci goto out_release; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci digi->ndigi = fsa->fsa_ax25.sax25_ndigis; 124762306a36Sopenharmony_ci digi->lastrepeat = -1; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci while (ct < fsa->fsa_ax25.sax25_ndigis) { 125062306a36Sopenharmony_ci if ((fsa->fsa_digipeater[ct].ax25_call[6] & 125162306a36Sopenharmony_ci AX25_HBIT) && ax25->iamdigi) { 125262306a36Sopenharmony_ci digi->repeated[ct] = 1; 125362306a36Sopenharmony_ci digi->lastrepeat = ct; 125462306a36Sopenharmony_ci } else { 125562306a36Sopenharmony_ci digi->repeated[ct] = 0; 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci digi->calls[ct] = fsa->fsa_digipeater[ct]; 125862306a36Sopenharmony_ci ct++; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* 126362306a36Sopenharmony_ci * Must bind first - autobinding in this may or may not work. If 126462306a36Sopenharmony_ci * the socket is already bound, check to see if the device has 126562306a36Sopenharmony_ci * been filled in, error if it hasn't. 126662306a36Sopenharmony_ci */ 126762306a36Sopenharmony_ci if (sock_flag(sk, SOCK_ZAPPED)) { 126862306a36Sopenharmony_ci /* check if we can remove this feature. It is broken. */ 126962306a36Sopenharmony_ci printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@yaina.de\n", 127062306a36Sopenharmony_ci current->comm); 127162306a36Sopenharmony_ci if ((err = ax25_rt_autobind(ax25, &fsa->fsa_ax25.sax25_call)) < 0) { 127262306a36Sopenharmony_ci kfree(digi); 127362306a36Sopenharmony_ci goto out_release; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci ax25_fillin_cb(ax25, ax25->ax25_dev); 127762306a36Sopenharmony_ci ax25_cb_add(ax25); 127862306a36Sopenharmony_ci } else { 127962306a36Sopenharmony_ci if (ax25->ax25_dev == NULL) { 128062306a36Sopenharmony_ci kfree(digi); 128162306a36Sopenharmony_ci err = -EHOSTUNREACH; 128262306a36Sopenharmony_ci goto out_release; 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci if (sk->sk_type == SOCK_SEQPACKET && 128762306a36Sopenharmony_ci (ax25t=ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi, 128862306a36Sopenharmony_ci ax25->ax25_dev->dev))) { 128962306a36Sopenharmony_ci kfree(digi); 129062306a36Sopenharmony_ci err = -EADDRINUSE; /* Already such a connection */ 129162306a36Sopenharmony_ci ax25_cb_put(ax25t); 129262306a36Sopenharmony_ci goto out_release; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci ax25->dest_addr = fsa->fsa_ax25.sax25_call; 129662306a36Sopenharmony_ci ax25->digipeat = digi; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci /* First the easy one */ 129962306a36Sopenharmony_ci if (sk->sk_type != SOCK_SEQPACKET) { 130062306a36Sopenharmony_ci sock->state = SS_CONNECTED; 130162306a36Sopenharmony_ci sk->sk_state = TCP_ESTABLISHED; 130262306a36Sopenharmony_ci goto out_release; 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci /* Move to connecting socket, ax.25 lapb WAIT_UA.. */ 130662306a36Sopenharmony_ci sock->state = SS_CONNECTING; 130762306a36Sopenharmony_ci sk->sk_state = TCP_SYN_SENT; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { 131062306a36Sopenharmony_ci case AX25_PROTO_STD_SIMPLEX: 131162306a36Sopenharmony_ci case AX25_PROTO_STD_DUPLEX: 131262306a36Sopenharmony_ci ax25_std_establish_data_link(ax25); 131362306a36Sopenharmony_ci break; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci#ifdef CONFIG_AX25_DAMA_SLAVE 131662306a36Sopenharmony_ci case AX25_PROTO_DAMA_SLAVE: 131762306a36Sopenharmony_ci ax25->modulus = AX25_MODULUS; 131862306a36Sopenharmony_ci ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW]; 131962306a36Sopenharmony_ci if (ax25->ax25_dev->dama.slave) 132062306a36Sopenharmony_ci ax25_ds_establish_data_link(ax25); 132162306a36Sopenharmony_ci else 132262306a36Sopenharmony_ci ax25_std_establish_data_link(ax25); 132362306a36Sopenharmony_ci break; 132462306a36Sopenharmony_ci#endif 132562306a36Sopenharmony_ci } 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci ax25->state = AX25_STATE_1; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci ax25_start_heartbeat(ax25); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci /* Now the loop */ 133262306a36Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) { 133362306a36Sopenharmony_ci err = -EINPROGRESS; 133462306a36Sopenharmony_ci goto out_release; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (sk->sk_state == TCP_SYN_SENT) { 133862306a36Sopenharmony_ci DEFINE_WAIT(wait); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci for (;;) { 134162306a36Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, 134262306a36Sopenharmony_ci TASK_INTERRUPTIBLE); 134362306a36Sopenharmony_ci if (sk->sk_state != TCP_SYN_SENT) 134462306a36Sopenharmony_ci break; 134562306a36Sopenharmony_ci if (!signal_pending(current)) { 134662306a36Sopenharmony_ci release_sock(sk); 134762306a36Sopenharmony_ci schedule(); 134862306a36Sopenharmony_ci lock_sock(sk); 134962306a36Sopenharmony_ci continue; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci err = -ERESTARTSYS; 135262306a36Sopenharmony_ci break; 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci if (err) 135762306a36Sopenharmony_ci goto out_release; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) { 136162306a36Sopenharmony_ci /* Not in ABM, not in WAIT_UA -> failed */ 136262306a36Sopenharmony_ci sock->state = SS_UNCONNECTED; 136362306a36Sopenharmony_ci err = sock_error(sk); /* Always set at this point */ 136462306a36Sopenharmony_ci goto out_release; 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci sock->state = SS_CONNECTED; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci err = 0; 137062306a36Sopenharmony_ciout_release: 137162306a36Sopenharmony_ci release_sock(sk); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci return err; 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_cistatic int ax25_accept(struct socket *sock, struct socket *newsock, int flags, 137762306a36Sopenharmony_ci bool kern) 137862306a36Sopenharmony_ci{ 137962306a36Sopenharmony_ci struct sk_buff *skb; 138062306a36Sopenharmony_ci struct sock *newsk; 138162306a36Sopenharmony_ci DEFINE_WAIT(wait); 138262306a36Sopenharmony_ci struct sock *sk; 138362306a36Sopenharmony_ci int err = 0; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci if (sock->state != SS_UNCONNECTED) 138662306a36Sopenharmony_ci return -EINVAL; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci if ((sk = sock->sk) == NULL) 138962306a36Sopenharmony_ci return -EINVAL; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci lock_sock(sk); 139262306a36Sopenharmony_ci if (sk->sk_type != SOCK_SEQPACKET) { 139362306a36Sopenharmony_ci err = -EOPNOTSUPP; 139462306a36Sopenharmony_ci goto out; 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (sk->sk_state != TCP_LISTEN) { 139862306a36Sopenharmony_ci err = -EINVAL; 139962306a36Sopenharmony_ci goto out; 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci /* 140362306a36Sopenharmony_ci * The read queue this time is holding sockets ready to use 140462306a36Sopenharmony_ci * hooked into the SABM we saved 140562306a36Sopenharmony_ci */ 140662306a36Sopenharmony_ci for (;;) { 140762306a36Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 140862306a36Sopenharmony_ci skb = skb_dequeue(&sk->sk_receive_queue); 140962306a36Sopenharmony_ci if (skb) 141062306a36Sopenharmony_ci break; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci if (flags & O_NONBLOCK) { 141362306a36Sopenharmony_ci err = -EWOULDBLOCK; 141462306a36Sopenharmony_ci break; 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci if (!signal_pending(current)) { 141762306a36Sopenharmony_ci release_sock(sk); 141862306a36Sopenharmony_ci schedule(); 141962306a36Sopenharmony_ci lock_sock(sk); 142062306a36Sopenharmony_ci continue; 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci err = -ERESTARTSYS; 142362306a36Sopenharmony_ci break; 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci if (err) 142862306a36Sopenharmony_ci goto out; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci newsk = skb->sk; 143162306a36Sopenharmony_ci sock_graft(newsk, newsock); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci /* Now attach up the new socket */ 143462306a36Sopenharmony_ci kfree_skb(skb); 143562306a36Sopenharmony_ci sk_acceptq_removed(sk); 143662306a36Sopenharmony_ci newsock->state = SS_CONNECTED; 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ciout: 143962306a36Sopenharmony_ci release_sock(sk); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci return err; 144262306a36Sopenharmony_ci} 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_cistatic int ax25_getname(struct socket *sock, struct sockaddr *uaddr, 144562306a36Sopenharmony_ci int peer) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr; 144862306a36Sopenharmony_ci struct sock *sk = sock->sk; 144962306a36Sopenharmony_ci unsigned char ndigi, i; 145062306a36Sopenharmony_ci ax25_cb *ax25; 145162306a36Sopenharmony_ci int err = 0; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci memset(fsa, 0, sizeof(*fsa)); 145462306a36Sopenharmony_ci lock_sock(sk); 145562306a36Sopenharmony_ci ax25 = sk_to_ax25(sk); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci if (peer != 0) { 145862306a36Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) { 145962306a36Sopenharmony_ci err = -ENOTCONN; 146062306a36Sopenharmony_ci goto out; 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci fsa->fsa_ax25.sax25_family = AF_AX25; 146462306a36Sopenharmony_ci fsa->fsa_ax25.sax25_call = ax25->dest_addr; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci if (ax25->digipeat != NULL) { 146762306a36Sopenharmony_ci ndigi = ax25->digipeat->ndigi; 146862306a36Sopenharmony_ci fsa->fsa_ax25.sax25_ndigis = ndigi; 146962306a36Sopenharmony_ci for (i = 0; i < ndigi; i++) 147062306a36Sopenharmony_ci fsa->fsa_digipeater[i] = 147162306a36Sopenharmony_ci ax25->digipeat->calls[i]; 147262306a36Sopenharmony_ci } 147362306a36Sopenharmony_ci } else { 147462306a36Sopenharmony_ci fsa->fsa_ax25.sax25_family = AF_AX25; 147562306a36Sopenharmony_ci fsa->fsa_ax25.sax25_call = ax25->source_addr; 147662306a36Sopenharmony_ci fsa->fsa_ax25.sax25_ndigis = 1; 147762306a36Sopenharmony_ci if (ax25->ax25_dev != NULL) { 147862306a36Sopenharmony_ci memcpy(&fsa->fsa_digipeater[0], 147962306a36Sopenharmony_ci ax25->ax25_dev->dev->dev_addr, AX25_ADDR_LEN); 148062306a36Sopenharmony_ci } else { 148162306a36Sopenharmony_ci fsa->fsa_digipeater[0] = null_ax25_address; 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci err = sizeof (struct full_sockaddr_ax25); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ciout: 148762306a36Sopenharmony_ci release_sock(sk); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci return err; 149062306a36Sopenharmony_ci} 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_cistatic int ax25_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) 149362306a36Sopenharmony_ci{ 149462306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_ax25 *, usax, msg->msg_name); 149562306a36Sopenharmony_ci struct sock *sk = sock->sk; 149662306a36Sopenharmony_ci struct sockaddr_ax25 sax; 149762306a36Sopenharmony_ci struct sk_buff *skb; 149862306a36Sopenharmony_ci ax25_digi dtmp, *dp; 149962306a36Sopenharmony_ci ax25_cb *ax25; 150062306a36Sopenharmony_ci size_t size; 150162306a36Sopenharmony_ci int lv, err, addr_len = msg->msg_namelen; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) 150462306a36Sopenharmony_ci return -EINVAL; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci lock_sock(sk); 150762306a36Sopenharmony_ci ax25 = sk_to_ax25(sk); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci if (sock_flag(sk, SOCK_ZAPPED)) { 151062306a36Sopenharmony_ci err = -EADDRNOTAVAIL; 151162306a36Sopenharmony_ci goto out; 151262306a36Sopenharmony_ci } 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci if (sk->sk_shutdown & SEND_SHUTDOWN) { 151562306a36Sopenharmony_ci send_sig(SIGPIPE, current, 0); 151662306a36Sopenharmony_ci err = -EPIPE; 151762306a36Sopenharmony_ci goto out; 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci if (ax25->ax25_dev == NULL) { 152162306a36Sopenharmony_ci err = -ENETUNREACH; 152262306a36Sopenharmony_ci goto out; 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci if (len > ax25->ax25_dev->dev->mtu) { 152662306a36Sopenharmony_ci err = -EMSGSIZE; 152762306a36Sopenharmony_ci goto out; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci if (usax != NULL) { 153162306a36Sopenharmony_ci if (usax->sax25_family != AF_AX25) { 153262306a36Sopenharmony_ci err = -EINVAL; 153362306a36Sopenharmony_ci goto out; 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci if (addr_len == sizeof(struct sockaddr_ax25)) 153762306a36Sopenharmony_ci /* ax25_sendmsg(): uses obsolete socket structure */ 153862306a36Sopenharmony_ci ; 153962306a36Sopenharmony_ci else if (addr_len != sizeof(struct full_sockaddr_ax25)) 154062306a36Sopenharmony_ci /* support for old structure may go away some time 154162306a36Sopenharmony_ci * ax25_sendmsg(): uses old (6 digipeater) 154262306a36Sopenharmony_ci * socket structure. 154362306a36Sopenharmony_ci */ 154462306a36Sopenharmony_ci if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || 154562306a36Sopenharmony_ci (addr_len > sizeof(struct full_sockaddr_ax25))) { 154662306a36Sopenharmony_ci err = -EINVAL; 154762306a36Sopenharmony_ci goto out; 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (addr_len > sizeof(struct sockaddr_ax25) && usax->sax25_ndigis != 0) { 155262306a36Sopenharmony_ci int ct = 0; 155362306a36Sopenharmony_ci struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci /* Valid number of digipeaters ? */ 155662306a36Sopenharmony_ci if (usax->sax25_ndigis < 1 || 155762306a36Sopenharmony_ci usax->sax25_ndigis > AX25_MAX_DIGIS || 155862306a36Sopenharmony_ci addr_len < sizeof(struct sockaddr_ax25) + 155962306a36Sopenharmony_ci sizeof(ax25_address) * usax->sax25_ndigis) { 156062306a36Sopenharmony_ci err = -EINVAL; 156162306a36Sopenharmony_ci goto out; 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci dtmp.ndigi = usax->sax25_ndigis; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci while (ct < usax->sax25_ndigis) { 156762306a36Sopenharmony_ci dtmp.repeated[ct] = 0; 156862306a36Sopenharmony_ci dtmp.calls[ct] = fsa->fsa_digipeater[ct]; 156962306a36Sopenharmony_ci ct++; 157062306a36Sopenharmony_ci } 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci dtmp.lastrepeat = 0; 157362306a36Sopenharmony_ci } 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci sax = *usax; 157662306a36Sopenharmony_ci if (sk->sk_type == SOCK_SEQPACKET && 157762306a36Sopenharmony_ci ax25cmp(&ax25->dest_addr, &sax.sax25_call)) { 157862306a36Sopenharmony_ci err = -EISCONN; 157962306a36Sopenharmony_ci goto out; 158062306a36Sopenharmony_ci } 158162306a36Sopenharmony_ci if (usax->sax25_ndigis == 0) 158262306a36Sopenharmony_ci dp = NULL; 158362306a36Sopenharmony_ci else 158462306a36Sopenharmony_ci dp = &dtmp; 158562306a36Sopenharmony_ci } else { 158662306a36Sopenharmony_ci /* 158762306a36Sopenharmony_ci * FIXME: 1003.1g - if the socket is like this because 158862306a36Sopenharmony_ci * it has become closed (not started closed) and is VC 158962306a36Sopenharmony_ci * we ought to SIGPIPE, EPIPE 159062306a36Sopenharmony_ci */ 159162306a36Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) { 159262306a36Sopenharmony_ci err = -ENOTCONN; 159362306a36Sopenharmony_ci goto out; 159462306a36Sopenharmony_ci } 159562306a36Sopenharmony_ci sax.sax25_family = AF_AX25; 159662306a36Sopenharmony_ci sax.sax25_call = ax25->dest_addr; 159762306a36Sopenharmony_ci dp = ax25->digipeat; 159862306a36Sopenharmony_ci } 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci /* Build a packet */ 160162306a36Sopenharmony_ci /* Assume the worst case */ 160262306a36Sopenharmony_ci size = len + ax25->ax25_dev->dev->hard_header_len; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT, &err); 160562306a36Sopenharmony_ci if (skb == NULL) 160662306a36Sopenharmony_ci goto out; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci skb_reserve(skb, size - len); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci /* User data follows immediately after the AX.25 data */ 161162306a36Sopenharmony_ci if (memcpy_from_msg(skb_put(skb, len), msg, len)) { 161262306a36Sopenharmony_ci err = -EFAULT; 161362306a36Sopenharmony_ci kfree_skb(skb); 161462306a36Sopenharmony_ci goto out; 161562306a36Sopenharmony_ci } 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci skb_reset_network_header(skb); 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci /* Add the PID if one is not supplied by the user in the skb */ 162062306a36Sopenharmony_ci if (!ax25->pidincl) 162162306a36Sopenharmony_ci *(u8 *)skb_push(skb, 1) = sk->sk_protocol; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci if (sk->sk_type == SOCK_SEQPACKET) { 162462306a36Sopenharmony_ci /* Connected mode sockets go via the LAPB machine */ 162562306a36Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) { 162662306a36Sopenharmony_ci kfree_skb(skb); 162762306a36Sopenharmony_ci err = -ENOTCONN; 162862306a36Sopenharmony_ci goto out; 162962306a36Sopenharmony_ci } 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci /* Shove it onto the queue and kick */ 163262306a36Sopenharmony_ci ax25_output(ax25, ax25->paclen, skb); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci err = len; 163562306a36Sopenharmony_ci goto out; 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci skb_push(skb, 1 + ax25_addr_size(dp)); 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci /* Building AX.25 Header */ 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci /* Build an AX.25 header */ 164362306a36Sopenharmony_ci lv = ax25_addr_build(skb->data, &ax25->source_addr, &sax.sax25_call, 164462306a36Sopenharmony_ci dp, AX25_COMMAND, AX25_MODULUS); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci skb_set_transport_header(skb, lv); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci *skb_transport_header(skb) = AX25_UI; 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci /* Datagram frames go straight out of the door as UI */ 165162306a36Sopenharmony_ci ax25_queue_xmit(skb, ax25->ax25_dev->dev); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci err = len; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ciout: 165662306a36Sopenharmony_ci release_sock(sk); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci return err; 165962306a36Sopenharmony_ci} 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_cistatic int ax25_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, 166262306a36Sopenharmony_ci int flags) 166362306a36Sopenharmony_ci{ 166462306a36Sopenharmony_ci struct sock *sk = sock->sk; 166562306a36Sopenharmony_ci struct sk_buff *skb, *last; 166662306a36Sopenharmony_ci struct sk_buff_head *sk_queue; 166762306a36Sopenharmony_ci int copied; 166862306a36Sopenharmony_ci int err = 0; 166962306a36Sopenharmony_ci int off = 0; 167062306a36Sopenharmony_ci long timeo; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci lock_sock(sk); 167362306a36Sopenharmony_ci /* 167462306a36Sopenharmony_ci * This works for seqpacket too. The receiver has ordered the 167562306a36Sopenharmony_ci * queue for us! We do one quick check first though 167662306a36Sopenharmony_ci */ 167762306a36Sopenharmony_ci if (sk->sk_type == SOCK_SEQPACKET && sk->sk_state != TCP_ESTABLISHED) { 167862306a36Sopenharmony_ci err = -ENOTCONN; 167962306a36Sopenharmony_ci goto out; 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci /* We need support for non-blocking reads. */ 168362306a36Sopenharmony_ci sk_queue = &sk->sk_receive_queue; 168462306a36Sopenharmony_ci skb = __skb_try_recv_datagram(sk, sk_queue, flags, &off, &err, &last); 168562306a36Sopenharmony_ci /* If no packet is available, release_sock(sk) and try again. */ 168662306a36Sopenharmony_ci if (!skb) { 168762306a36Sopenharmony_ci if (err != -EAGAIN) 168862306a36Sopenharmony_ci goto out; 168962306a36Sopenharmony_ci release_sock(sk); 169062306a36Sopenharmony_ci timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); 169162306a36Sopenharmony_ci while (timeo && !__skb_wait_for_more_packets(sk, sk_queue, &err, 169262306a36Sopenharmony_ci &timeo, last)) { 169362306a36Sopenharmony_ci skb = __skb_try_recv_datagram(sk, sk_queue, flags, &off, 169462306a36Sopenharmony_ci &err, &last); 169562306a36Sopenharmony_ci if (skb) 169662306a36Sopenharmony_ci break; 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci if (err != -EAGAIN) 169962306a36Sopenharmony_ci goto done; 170062306a36Sopenharmony_ci } 170162306a36Sopenharmony_ci if (!skb) 170262306a36Sopenharmony_ci goto done; 170362306a36Sopenharmony_ci lock_sock(sk); 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci if (!sk_to_ax25(sk)->pidincl) 170762306a36Sopenharmony_ci skb_pull(skb, 1); /* Remove PID */ 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci skb_reset_transport_header(skb); 171062306a36Sopenharmony_ci copied = skb->len; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci if (copied > size) { 171362306a36Sopenharmony_ci copied = size; 171462306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 171562306a36Sopenharmony_ci } 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci skb_copy_datagram_msg(skb, 0, msg, copied); 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci if (msg->msg_name) { 172062306a36Sopenharmony_ci ax25_digi digi; 172162306a36Sopenharmony_ci ax25_address src; 172262306a36Sopenharmony_ci const unsigned char *mac = skb_mac_header(skb); 172362306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_ax25 *, sax, msg->msg_name); 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci memset(sax, 0, sizeof(struct full_sockaddr_ax25)); 172662306a36Sopenharmony_ci ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL, 172762306a36Sopenharmony_ci &digi, NULL, NULL); 172862306a36Sopenharmony_ci sax->sax25_family = AF_AX25; 172962306a36Sopenharmony_ci /* We set this correctly, even though we may not let the 173062306a36Sopenharmony_ci application know the digi calls further down (because it 173162306a36Sopenharmony_ci did NOT ask to know them). This could get political... **/ 173262306a36Sopenharmony_ci sax->sax25_ndigis = digi.ndigi; 173362306a36Sopenharmony_ci sax->sax25_call = src; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci if (sax->sax25_ndigis != 0) { 173662306a36Sopenharmony_ci int ct; 173762306a36Sopenharmony_ci struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)sax; 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci for (ct = 0; ct < digi.ndigi; ct++) 174062306a36Sopenharmony_ci fsa->fsa_digipeater[ct] = digi.calls[ct]; 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci msg->msg_namelen = sizeof(struct full_sockaddr_ax25); 174362306a36Sopenharmony_ci } 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci skb_free_datagram(sk, skb); 174662306a36Sopenharmony_ci err = copied; 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ciout: 174962306a36Sopenharmony_ci release_sock(sk); 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_cidone: 175262306a36Sopenharmony_ci return err; 175362306a36Sopenharmony_ci} 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_cistatic int ax25_shutdown(struct socket *sk, int how) 175662306a36Sopenharmony_ci{ 175762306a36Sopenharmony_ci /* FIXME - generate DM and RNR states */ 175862306a36Sopenharmony_ci return -EOPNOTSUPP; 175962306a36Sopenharmony_ci} 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_cistatic int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 176262306a36Sopenharmony_ci{ 176362306a36Sopenharmony_ci struct sock *sk = sock->sk; 176462306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 176562306a36Sopenharmony_ci int res = 0; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci lock_sock(sk); 176862306a36Sopenharmony_ci switch (cmd) { 176962306a36Sopenharmony_ci case TIOCOUTQ: { 177062306a36Sopenharmony_ci long amount; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); 177362306a36Sopenharmony_ci if (amount < 0) 177462306a36Sopenharmony_ci amount = 0; 177562306a36Sopenharmony_ci res = put_user(amount, (int __user *)argp); 177662306a36Sopenharmony_ci break; 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci case TIOCINQ: { 178062306a36Sopenharmony_ci struct sk_buff *skb; 178162306a36Sopenharmony_ci long amount = 0L; 178262306a36Sopenharmony_ci /* These two are safe on a single CPU system as only user tasks fiddle here */ 178362306a36Sopenharmony_ci if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) 178462306a36Sopenharmony_ci amount = skb->len; 178562306a36Sopenharmony_ci res = put_user(amount, (int __user *) argp); 178662306a36Sopenharmony_ci break; 178762306a36Sopenharmony_ci } 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */ 179062306a36Sopenharmony_ci case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */ 179162306a36Sopenharmony_ci case SIOCAX25GETUID: { 179262306a36Sopenharmony_ci struct sockaddr_ax25 sax25; 179362306a36Sopenharmony_ci if (copy_from_user(&sax25, argp, sizeof(sax25))) { 179462306a36Sopenharmony_ci res = -EFAULT; 179562306a36Sopenharmony_ci break; 179662306a36Sopenharmony_ci } 179762306a36Sopenharmony_ci res = ax25_uid_ioctl(cmd, &sax25); 179862306a36Sopenharmony_ci break; 179962306a36Sopenharmony_ci } 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci case SIOCAX25NOUID: { /* Set the default policy (default/bar) */ 180262306a36Sopenharmony_ci long amount; 180362306a36Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) { 180462306a36Sopenharmony_ci res = -EPERM; 180562306a36Sopenharmony_ci break; 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci if (get_user(amount, (long __user *)argp)) { 180862306a36Sopenharmony_ci res = -EFAULT; 180962306a36Sopenharmony_ci break; 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci if (amount < 0 || amount > AX25_NOUID_BLOCK) { 181262306a36Sopenharmony_ci res = -EINVAL; 181362306a36Sopenharmony_ci break; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci ax25_uid_policy = amount; 181662306a36Sopenharmony_ci res = 0; 181762306a36Sopenharmony_ci break; 181862306a36Sopenharmony_ci } 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci case SIOCADDRT: 182162306a36Sopenharmony_ci case SIOCDELRT: 182262306a36Sopenharmony_ci case SIOCAX25OPTRT: 182362306a36Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) { 182462306a36Sopenharmony_ci res = -EPERM; 182562306a36Sopenharmony_ci break; 182662306a36Sopenharmony_ci } 182762306a36Sopenharmony_ci res = ax25_rt_ioctl(cmd, argp); 182862306a36Sopenharmony_ci break; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci case SIOCAX25CTLCON: 183162306a36Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) { 183262306a36Sopenharmony_ci res = -EPERM; 183362306a36Sopenharmony_ci break; 183462306a36Sopenharmony_ci } 183562306a36Sopenharmony_ci res = ax25_ctl_ioctl(cmd, argp); 183662306a36Sopenharmony_ci break; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci case SIOCAX25GETINFO: 183962306a36Sopenharmony_ci case SIOCAX25GETINFOOLD: { 184062306a36Sopenharmony_ci ax25_cb *ax25 = sk_to_ax25(sk); 184162306a36Sopenharmony_ci struct ax25_info_struct ax25_info; 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci ax25_info.t1 = ax25->t1 / HZ; 184462306a36Sopenharmony_ci ax25_info.t2 = ax25->t2 / HZ; 184562306a36Sopenharmony_ci ax25_info.t3 = ax25->t3 / HZ; 184662306a36Sopenharmony_ci ax25_info.idle = ax25->idle / (60 * HZ); 184762306a36Sopenharmony_ci ax25_info.n2 = ax25->n2; 184862306a36Sopenharmony_ci ax25_info.t1timer = ax25_display_timer(&ax25->t1timer) / HZ; 184962306a36Sopenharmony_ci ax25_info.t2timer = ax25_display_timer(&ax25->t2timer) / HZ; 185062306a36Sopenharmony_ci ax25_info.t3timer = ax25_display_timer(&ax25->t3timer) / HZ; 185162306a36Sopenharmony_ci ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ); 185262306a36Sopenharmony_ci ax25_info.n2count = ax25->n2count; 185362306a36Sopenharmony_ci ax25_info.state = ax25->state; 185462306a36Sopenharmony_ci ax25_info.rcv_q = sk_rmem_alloc_get(sk); 185562306a36Sopenharmony_ci ax25_info.snd_q = sk_wmem_alloc_get(sk); 185662306a36Sopenharmony_ci ax25_info.vs = ax25->vs; 185762306a36Sopenharmony_ci ax25_info.vr = ax25->vr; 185862306a36Sopenharmony_ci ax25_info.va = ax25->va; 185962306a36Sopenharmony_ci ax25_info.vs_max = ax25->vs; /* reserved */ 186062306a36Sopenharmony_ci ax25_info.paclen = ax25->paclen; 186162306a36Sopenharmony_ci ax25_info.window = ax25->window; 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci /* old structure? */ 186462306a36Sopenharmony_ci if (cmd == SIOCAX25GETINFOOLD) { 186562306a36Sopenharmony_ci static int warned = 0; 186662306a36Sopenharmony_ci if (!warned) { 186762306a36Sopenharmony_ci printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n", 186862306a36Sopenharmony_ci current->comm); 186962306a36Sopenharmony_ci warned=1; 187062306a36Sopenharmony_ci } 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct_deprecated))) { 187362306a36Sopenharmony_ci res = -EFAULT; 187462306a36Sopenharmony_ci break; 187562306a36Sopenharmony_ci } 187662306a36Sopenharmony_ci } else { 187762306a36Sopenharmony_ci if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct))) { 187862306a36Sopenharmony_ci res = -EINVAL; 187962306a36Sopenharmony_ci break; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci } 188262306a36Sopenharmony_ci res = 0; 188362306a36Sopenharmony_ci break; 188462306a36Sopenharmony_ci } 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci case SIOCAX25ADDFWD: 188762306a36Sopenharmony_ci case SIOCAX25DELFWD: { 188862306a36Sopenharmony_ci struct ax25_fwd_struct ax25_fwd; 188962306a36Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) { 189062306a36Sopenharmony_ci res = -EPERM; 189162306a36Sopenharmony_ci break; 189262306a36Sopenharmony_ci } 189362306a36Sopenharmony_ci if (copy_from_user(&ax25_fwd, argp, sizeof(ax25_fwd))) { 189462306a36Sopenharmony_ci res = -EFAULT; 189562306a36Sopenharmony_ci break; 189662306a36Sopenharmony_ci } 189762306a36Sopenharmony_ci res = ax25_fwd_ioctl(cmd, &ax25_fwd); 189862306a36Sopenharmony_ci break; 189962306a36Sopenharmony_ci } 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci case SIOCGIFADDR: 190262306a36Sopenharmony_ci case SIOCSIFADDR: 190362306a36Sopenharmony_ci case SIOCGIFDSTADDR: 190462306a36Sopenharmony_ci case SIOCSIFDSTADDR: 190562306a36Sopenharmony_ci case SIOCGIFBRDADDR: 190662306a36Sopenharmony_ci case SIOCSIFBRDADDR: 190762306a36Sopenharmony_ci case SIOCGIFNETMASK: 190862306a36Sopenharmony_ci case SIOCSIFNETMASK: 190962306a36Sopenharmony_ci case SIOCGIFMETRIC: 191062306a36Sopenharmony_ci case SIOCSIFMETRIC: 191162306a36Sopenharmony_ci res = -EINVAL; 191262306a36Sopenharmony_ci break; 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci default: 191562306a36Sopenharmony_ci res = -ENOIOCTLCMD; 191662306a36Sopenharmony_ci break; 191762306a36Sopenharmony_ci } 191862306a36Sopenharmony_ci release_sock(sk); 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci return res; 192162306a36Sopenharmony_ci} 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_cistatic void *ax25_info_start(struct seq_file *seq, loff_t *pos) 192662306a36Sopenharmony_ci __acquires(ax25_list_lock) 192762306a36Sopenharmony_ci{ 192862306a36Sopenharmony_ci spin_lock_bh(&ax25_list_lock); 192962306a36Sopenharmony_ci return seq_hlist_start(&ax25_list, *pos); 193062306a36Sopenharmony_ci} 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_cistatic void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos) 193362306a36Sopenharmony_ci{ 193462306a36Sopenharmony_ci return seq_hlist_next(v, &ax25_list, pos); 193562306a36Sopenharmony_ci} 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_cistatic void ax25_info_stop(struct seq_file *seq, void *v) 193862306a36Sopenharmony_ci __releases(ax25_list_lock) 193962306a36Sopenharmony_ci{ 194062306a36Sopenharmony_ci spin_unlock_bh(&ax25_list_lock); 194162306a36Sopenharmony_ci} 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_cistatic int ax25_info_show(struct seq_file *seq, void *v) 194462306a36Sopenharmony_ci{ 194562306a36Sopenharmony_ci ax25_cb *ax25 = hlist_entry(v, struct ax25_cb, ax25_node); 194662306a36Sopenharmony_ci char buf[11]; 194762306a36Sopenharmony_ci int k; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci /* 195162306a36Sopenharmony_ci * New format: 195262306a36Sopenharmony_ci * 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 195362306a36Sopenharmony_ci */ 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci seq_printf(seq, "%p %s %s%s ", 195662306a36Sopenharmony_ci ax25, 195762306a36Sopenharmony_ci ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name, 195862306a36Sopenharmony_ci ax2asc(buf, &ax25->source_addr), 195962306a36Sopenharmony_ci ax25->iamdigi? "*":""); 196062306a36Sopenharmony_ci seq_printf(seq, "%s", ax2asc(buf, &ax25->dest_addr)); 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { 196362306a36Sopenharmony_ci seq_printf(seq, ",%s%s", 196462306a36Sopenharmony_ci ax2asc(buf, &ax25->digipeat->calls[k]), 196562306a36Sopenharmony_ci ax25->digipeat->repeated[k]? "*":""); 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci seq_printf(seq, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d", 196962306a36Sopenharmony_ci ax25->state, 197062306a36Sopenharmony_ci ax25->vs, ax25->vr, ax25->va, 197162306a36Sopenharmony_ci ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ, 197262306a36Sopenharmony_ci ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ, 197362306a36Sopenharmony_ci ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ, 197462306a36Sopenharmony_ci ax25_display_timer(&ax25->idletimer) / (60 * HZ), 197562306a36Sopenharmony_ci ax25->idle / (60 * HZ), 197662306a36Sopenharmony_ci ax25->n2count, ax25->n2, 197762306a36Sopenharmony_ci ax25->rtt / HZ, 197862306a36Sopenharmony_ci ax25->window, 197962306a36Sopenharmony_ci ax25->paclen); 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci if (ax25->sk != NULL) { 198262306a36Sopenharmony_ci seq_printf(seq, " %d %d %lu\n", 198362306a36Sopenharmony_ci sk_wmem_alloc_get(ax25->sk), 198462306a36Sopenharmony_ci sk_rmem_alloc_get(ax25->sk), 198562306a36Sopenharmony_ci sock_i_ino(ax25->sk)); 198662306a36Sopenharmony_ci } else { 198762306a36Sopenharmony_ci seq_puts(seq, " * * *\n"); 198862306a36Sopenharmony_ci } 198962306a36Sopenharmony_ci return 0; 199062306a36Sopenharmony_ci} 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_cistatic const struct seq_operations ax25_info_seqops = { 199362306a36Sopenharmony_ci .start = ax25_info_start, 199462306a36Sopenharmony_ci .next = ax25_info_next, 199562306a36Sopenharmony_ci .stop = ax25_info_stop, 199662306a36Sopenharmony_ci .show = ax25_info_show, 199762306a36Sopenharmony_ci}; 199862306a36Sopenharmony_ci#endif 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_cistatic const struct net_proto_family ax25_family_ops = { 200162306a36Sopenharmony_ci .family = PF_AX25, 200262306a36Sopenharmony_ci .create = ax25_create, 200362306a36Sopenharmony_ci .owner = THIS_MODULE, 200462306a36Sopenharmony_ci}; 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_cistatic const struct proto_ops ax25_proto_ops = { 200762306a36Sopenharmony_ci .family = PF_AX25, 200862306a36Sopenharmony_ci .owner = THIS_MODULE, 200962306a36Sopenharmony_ci .release = ax25_release, 201062306a36Sopenharmony_ci .bind = ax25_bind, 201162306a36Sopenharmony_ci .connect = ax25_connect, 201262306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 201362306a36Sopenharmony_ci .accept = ax25_accept, 201462306a36Sopenharmony_ci .getname = ax25_getname, 201562306a36Sopenharmony_ci .poll = datagram_poll, 201662306a36Sopenharmony_ci .ioctl = ax25_ioctl, 201762306a36Sopenharmony_ci .gettstamp = sock_gettstamp, 201862306a36Sopenharmony_ci .listen = ax25_listen, 201962306a36Sopenharmony_ci .shutdown = ax25_shutdown, 202062306a36Sopenharmony_ci .setsockopt = ax25_setsockopt, 202162306a36Sopenharmony_ci .getsockopt = ax25_getsockopt, 202262306a36Sopenharmony_ci .sendmsg = ax25_sendmsg, 202362306a36Sopenharmony_ci .recvmsg = ax25_recvmsg, 202462306a36Sopenharmony_ci .mmap = sock_no_mmap, 202562306a36Sopenharmony_ci}; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci/* 202862306a36Sopenharmony_ci * Called by socket.c on kernel start up 202962306a36Sopenharmony_ci */ 203062306a36Sopenharmony_cistatic struct packet_type ax25_packet_type __read_mostly = { 203162306a36Sopenharmony_ci .type = cpu_to_be16(ETH_P_AX25), 203262306a36Sopenharmony_ci .func = ax25_kiss_rcv, 203362306a36Sopenharmony_ci}; 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_cistatic struct notifier_block ax25_dev_notifier = { 203662306a36Sopenharmony_ci .notifier_call = ax25_device_event, 203762306a36Sopenharmony_ci}; 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_cistatic int __init ax25_init(void) 204062306a36Sopenharmony_ci{ 204162306a36Sopenharmony_ci int rc = proto_register(&ax25_proto, 0); 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci if (rc != 0) 204462306a36Sopenharmony_ci goto out; 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci sock_register(&ax25_family_ops); 204762306a36Sopenharmony_ci dev_add_pack(&ax25_packet_type); 204862306a36Sopenharmony_ci register_netdevice_notifier(&ax25_dev_notifier); 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci proc_create_seq("ax25_route", 0444, init_net.proc_net, &ax25_rt_seqops); 205162306a36Sopenharmony_ci proc_create_seq("ax25", 0444, init_net.proc_net, &ax25_info_seqops); 205262306a36Sopenharmony_ci proc_create_seq("ax25_calls", 0444, init_net.proc_net, 205362306a36Sopenharmony_ci &ax25_uid_seqops); 205462306a36Sopenharmony_ciout: 205562306a36Sopenharmony_ci return rc; 205662306a36Sopenharmony_ci} 205762306a36Sopenharmony_cimodule_init(ax25_init); 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ciMODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>"); 206162306a36Sopenharmony_ciMODULE_DESCRIPTION("The amateur radio AX.25 link layer protocol"); 206262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 206362306a36Sopenharmony_ciMODULE_ALIAS_NETPROTO(PF_AX25); 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_cistatic void __exit ax25_exit(void) 206662306a36Sopenharmony_ci{ 206762306a36Sopenharmony_ci remove_proc_entry("ax25_route", init_net.proc_net); 206862306a36Sopenharmony_ci remove_proc_entry("ax25", init_net.proc_net); 206962306a36Sopenharmony_ci remove_proc_entry("ax25_calls", init_net.proc_net); 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci unregister_netdevice_notifier(&ax25_dev_notifier); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci dev_remove_pack(&ax25_packet_type); 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci sock_unregister(PF_AX25); 207662306a36Sopenharmony_ci proto_unregister(&ax25_proto); 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci ax25_rt_free(); 207962306a36Sopenharmony_ci ax25_uid_free(); 208062306a36Sopenharmony_ci ax25_dev_free(); 208162306a36Sopenharmony_ci} 208262306a36Sopenharmony_cimodule_exit(ax25_exit); 2083