From e5067d7cd967cb17067de24a162306b79f432b20 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 24 Jun 2015 04:23:46 +0200 Subject: Import newax25-2.4.3.patch.1.bz2 And cleanup the *.orig and *.rej files and whitespace errors that are part of the original patch. Signed-off-by: Ralf Baechle --- net/ax25/af_ax25.c | 1740 ++++++++++++++++++++-------------------------------- 1 file changed, 658 insertions(+), 1082 deletions(-) (limited to 'net/ax25/af_ax25.c') diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 4a2684ebe..6fa817d65 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1,107 +1,22 @@ /* - * AX.25 release 038 + * af_ax25.c: Network subsystem interface and NEW-AX.25 main functions * - * This code REQUIRES 2.1.15 or higher/ NET3.038 + * Authors: Jens David (DG1KJD), Matthias Welwarsky (DG2FEF), + * Jonathan (G4KLX), Alan Cox (GW4PTS) * - * This module: - * This module is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. + * Comment: SOCK_DGRAM support is missing and should be implemented ASAP. + * There is currently no clean way for unproto operation. Most + * application use AF_PACKET, SOCK_RAW which is seriously broken + * because it skips the DDI arbiter etc. etc. * - * History - * AX.25 006 Alan(GW4PTS) Nearly died of shock - it's working 8-) - * AX.25 007 Alan(GW4PTS) Removed the silliest bugs - * AX.25 008 Alan(GW4PTS) Cleaned up, fixed a few state machine problems, added callbacks - * AX.25 009 Alan(GW4PTS) Emergency patch kit to fix memory corruption - * AX.25 010 Alan(GW4PTS) Added RAW sockets/Digipeat. - * AX.25 011 Alan(GW4PTS) RAW socket and datagram fixes (thanks) - Raw sendto now gets PID right - * datagram sendto uses correct target address. - * AX.25 012 Alan(GW4PTS) Correct incoming connection handling, send DM to failed connects. - * Use skb->data not skb+1. Support sk->priority correctly. - * Correct receive on SOCK_DGRAM. - * AX.25 013 Alan(GW4PTS) Send DM to all unknown frames, missing initialiser fixed - * Leave spare SSID bits set (DAMA etc) - thanks for bug report, - * removed device registration (it's not used or needed). Clean up for - * gcc 2.5.8. PID to AX25_P_ - * AX.25 014 Alan(GW4PTS) Cleanup and NET3 merge - * AX.25 015 Alan(GW4PTS) Internal test version. - * AX.25 016 Alan(GW4PTS) Semi Internal version for PI card - * work. - * AX.25 017 Alan(GW4PTS) Fixed some small bugs reported by - * G4KLX - * AX.25 018 Alan(GW4PTS) Fixed a small error in SOCK_DGRAM - * AX.25 019 Alan(GW4PTS) Clean ups for the non INET kernel and device ioctls in AX.25 - * AX.25 020 Jonathan(G4KLX) /proc support and other changes. - * AX.25 021 Alan(GW4PTS) Added AX25_T1, AX25_N2, AX25_T3 as requested. - * AX.25 022 Jonathan(G4KLX) More work on the ax25 auto router and /proc improved (again)! - * Alan(GW4PTS) Added TIOCINQ/OUTQ - * AX.25 023 Alan(GW4PTS) Fixed shutdown bug - * AX.25 023 Alan(GW4PTS) Linus changed timers - * AX.25 024 Alan(GW4PTS) Small bug fixes - * AX.25 025 Alan(GW4PTS) More fixes, Linux 1.1.51 compatibility stuff, timers again! - * AX.25 026 Alan(GW4PTS) Small state fix. - * AX.25 027 Alan(GW4PTS) Socket close crash fixes. - * AX.25 028 Alan(GW4PTS) Callsign control including settings per uid. - * Small bug fixes. - * Protocol set by sockets only. - * Small changes to allow for start of NET/ROM layer. - * AX.25 028a Jonathan(G4KLX) Changes to state machine. - * AX.25 028b Jonathan(G4KLX) Extracted ax25 control block - * from sock structure. - * AX.25 029 Alan(GW4PTS) Combined 028b and some KA9Q code - * Jonathan(G4KLX) and removed all the old Berkeley, added IP mode registration. - * Darryl(G7LED) stuff. Cross-port digipeating. Minor fixes and enhancements. - * Alan(GW4PTS) Missed suser() on axassociate checks - * AX.25 030 Alan(GW4PTS) Added variable length headers. - * Jonathan(G4KLX) Added BPQ Ethernet interface. - * Steven(GW7RRM) Added digi-peating control ioctl. - * Added extended AX.25 support. - * Added AX.25 frame segmentation. - * Darryl(G7LED) Changed connect(), recvfrom(), sendto() sockaddr/addrlen to - * fall inline with bind() and new policy. - * Moved digipeating ctl to new ax25_dev structs. - * Fixed ax25_release(), set TCP_CLOSE, wakeup app - * context, THEN make the sock dead. - * Alan(GW4PTS) Cleaned up for single recvmsg methods. - * Alan(GW4PTS) Fixed not clearing error on connect failure. - * AX.25 031 Jonathan(G4KLX) Added binding to any device. - * Joerg(DL1BKE) Added DAMA support, fixed (?) digipeating, fixed buffer locking - * for "virtual connect" mode... Result: Probably the - * "Most Buggiest Code You've Ever Seen" (TM) - * HaJo(DD8NE) Implementation of a T5 (idle) timer - * Joerg(DL1BKE) Renamed T5 to IDLE and changed behaviour: - * the timer gets reloaded on every received or transmitted - * I frame for IP or NETROM. The idle timer is not active - * on "vanilla AX.25" connections. Furthermore added PACLEN - * to provide AX.25-layer based fragmentation (like WAMPES) - * AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout error. - * ax25_send_frame() limits the number of enqueued - * datagrams per socket. - * AX.25 033 Jonathan(G4KLX) Removed auto-router. - * Hans(PE1AYX) Converted to Module. - * Joerg(DL1BKE) Moved BPQ Ethernet to separate driver. - * AX.25 034 Jonathan(G4KLX) 2.1 changes - * Alan(GW4PTS) Small POSIXisations - * AX.25 035 Alan(GW4PTS) Started fixing to the new - * format. - * Hans(PE1AYX) Fixed interface to IP layer. - * Alan(GW4PTS) Added asynchronous support. - * Frederic(F1OAT) Support for pseudo-digipeating. - * Jonathan(G4KLX) Support for packet forwarding. - * AX.25 036 Jonathan(G4KLX) Major restructuring. - * Joerg(DL1BKE) Fixed DAMA Slave. - * Jonathan(G4KLX) Fix wildcard listen parameter setting. - * AX.25 037 Jonathan(G4KLX) New timer architecture. - * AX.25 038 Matthias(DG2FEF) Small fixes to the syscall interface to make kernel - * independent of AX25_MAX_DIGIS used by applications. - * Tomi(OH2BNS) Fixed ax25_getname(). - * Joerg(DL1BKE) Starting to phase out the support for full_sockaddr_ax25 - * with only 6 digipeaters and sockaddr_ax25 in ax25_bind(), - * ax25_connect() and ax25_sendmsg() - * Joerg(DL1BKE) Added support for SO_BINDTODEVICE - * Arnaldo C. Melo s/suser/capable(CAP_NET_ADMIN)/, some more cleanups - * Michal Ostrowski Module initialization cleanup. + * Changelog: + * 2001-02-06 Joerg Reuter DL1BKE + * port to kernel 2.4.1 + * + * License: This module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. */ #include @@ -111,518 +26,327 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include +#include #include -#include -#include -#include +#include #include #include /* For TIOCINQ/OUTQ */ -#include #include #include #include #include -#include -#include #include -#include -#include - - - -ax25_cb *volatile ax25_list; +#include +#include -static struct proto_ops ax25_proto_ops; +#include +#include +#include +#include + +#include "af_ax25.h" +#include "ax25_vj.h" +#include "ax25_ddi.h" +#include "ax25_route.h" +#include "ax25_core.h" +#include "ax25_ctl.h" +#include "ax25_in.h" +#include "ax25_subr.h" +#include "ax25_netlink.h" +#include "ax25_timer.h" /* - * Free an allocated ax25 control block. This is done to centralise - * the MOD count code. + * ------------------------------------------------------------------------ + * declaration of static functions + * ------------------------------------------------------------------------ */ -void ax25_free_cb(ax25_cb *ax25) -{ - if (ax25->digipeat != NULL) { - kfree(ax25->digipeat); - ax25->digipeat = NULL; - } - - kfree(ax25); - - MOD_DEC_USE_COUNT; -} - -static void ax25_free_sock(struct sock *sk) -{ - ax25_free_cb(sk->protinfo.ax25); -} +static int ax25_device_event(struct notifier_block* ,unsigned long, void*); +static int ax25_setsockopt(struct socket*, int, int, char*, int); +static int ax25_getsockopt(struct socket*, int, int, char*, int*); +static int ax25_listen(struct socket*, int); +static int ax25_shutdown(struct socket*, int); +static int ax25_create(struct socket*, int); +static int ax25_release(struct socket *); +static int ax25_bind(struct socket*, struct sockaddr*, int); +static int ax25_connect(struct socket*, struct sockaddr*, int, int); +static int ax25_accept(struct socket*, struct socket*, int); +static int ax25_getname(struct socket*, struct sockaddr*, int*, int); +static int ax25_sendmsg(struct socket*, struct msghdr*, int, struct scm_cookie*); +static int ax25_recvmsg(struct socket*, struct msghdr*, int, int, struct scm_cookie*); +static int ax25_ioctl(struct socket*, unsigned int, unsigned long); +static int ax25_print_list(char*, off_t*, off_t, int, off_t*, ax25_cb*, char*); +static int ax25_get_info(char*, char **, off_t, int); +static int ax25_gifconf(struct net_device *dev, char *buf, int len); + +/* in ax25_ipax.c */ +int ipax_init(void); +int ipax_cleanup(void); /* - * Socket removal during an interrupt is now safe. + * ------------------------------------------------------------------------ + * static variables and structures + * ------------------------------------------------------------------------ */ -static void ax25_remove_socket(ax25_cb *ax25) -{ - ax25_cb *s; - unsigned long flags; - - save_flags(flags); cli(); - - if ((s = ax25_list) == ax25) { - ax25_list = s->next; - restore_flags(flags); - return; - } - - while (s != NULL && s->next != NULL) { - if (s->next == ax25) { - s->next = ax25->next; - restore_flags(flags); - return; - } - - s = s->next; - } - - restore_flags(flags); -} /* - * Kill all bound sockets on a dropped device. + * table of exportes symbols */ -static void ax25_kill_by_device(struct net_device *dev) -{ - ax25_dev *ax25_dev; - ax25_cb *s; - if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) - return; +EXPORT_SYMBOL(ax25_find_match_for_uid); +EXPORT_SYMBOL(ax25_find_cb); +EXPORT_SYMBOL(ax25_linkfail_register); +EXPORT_SYMBOL(ax25_linkfail_release); +EXPORT_SYMBOL(ax25_listen_register); +EXPORT_SYMBOL(ax25_listen_release); +EXPORT_SYMBOL(ax25_protocol_register); +EXPORT_SYMBOL(ax25_protocol_release); +EXPORT_SYMBOL(ax25_send_frame); +EXPORT_SYMBOL(ax25_uid_policy); +EXPORT_SYMBOL(ax25cmp); +EXPORT_SYMBOL(ax2asc); +EXPORT_SYMBOL(asc2ax); +EXPORT_SYMBOL(null_ax25_address); - for (s = ax25_list; s != NULL; s = s->next) { - if (s->ax25_dev == ax25_dev) { - s->ax25_dev = NULL; - ax25_disconnect(s, ENETUNREACH); - } - } -} +/* for debugging */ +EXPORT_SYMBOL(ax25_kill_by_device); /* - * Handle device status changes. + * This list contains all sockets that are not bound to + * a specific device. */ -static int ax25_device_event(struct notifier_block *this,unsigned long event, void *ptr) -{ - struct net_device *dev = (struct net_device *)ptr; - - /* Reject non AX.25 devices */ - if (dev->type != ARPHRD_AX25) - return NOTIFY_DONE; - - switch (event) { - case NETDEV_UP: - ax25_dev_device_up(dev); - break; - case NETDEV_DOWN: - ax25_kill_by_device(dev); - ax25_rt_device_down(dev); - ax25_dev_device_down(dev); - break; - default: - break; - } - - return NOTIFY_DONE; -} +ax25_cb *ax25_list = NULL; /* - * Add a socket to the bound sockets list. + * Protocol family registration data */ -void ax25_insert_socket(ax25_cb *ax25) +static struct net_proto_family ax25_family_ops = { - unsigned long flags; - - save_flags(flags); - cli(); - - ax25->next = ax25_list; - ax25_list = ax25; - - restore_flags(flags); -} + family: PF_AX25, + create: ax25_create, +}; /* - * Find a socket that wants to accept the SABM we have just - * received. + * Protocol operations for AF_AX25 */ -struct sock *ax25_find_listener(ax25_address *addr, int digi, struct net_device *dev, int type) -{ - unsigned long flags; - ax25_cb *s; - - save_flags(flags); - cli(); +static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = { + family: PF_AX25, - for (s = ax25_list; s != NULL; s = s->next) { - if ((s->iamdigi && !digi) || (!s->iamdigi && digi)) - continue; - if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == type && s->sk->state == TCP_LISTEN) { - /* If device is null we match any device */ - if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) { - restore_flags(flags); - return s->sk; - } - } - } + release: ax25_release, + bind: ax25_bind, + connect: ax25_connect, + socketpair: sock_no_socketpair, + accept: ax25_accept, + getname: ax25_getname, + poll: datagram_poll, + ioctl: ax25_ioctl, + listen: ax25_listen, + shutdown: ax25_shutdown, + setsockopt: ax25_setsockopt, + getsockopt: ax25_getsockopt, + sendmsg: ax25_sendmsg, + recvmsg: ax25_recvmsg, + mmap: sock_no_mmap +}; - restore_flags(flags); - return NULL; -} +SOCKOPS_WRAP(ax25_proto, PF_AX25); /* - * Find an AX.25 socket given both ends. + * Device up/down notifier block */ -struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, int type) -{ - ax25_cb *s; - unsigned long flags; - - save_flags(flags); - cli(); - - for (s = ax25_list; s != NULL; s = s->next) { - if (s->sk != NULL && ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->sk->type == type) { - restore_flags(flags); - return s->sk; - } - } - - restore_flags(flags); +static struct notifier_block ax25_dev_notifier = { + ax25_device_event, + 0 +}; - return NULL; -} +/* + * ------------------------------------------------------------------------ + * Interface implementation + * All public functions of this module are defined here + * ------------------------------------------------------------------------ + */ /* - * Find an AX.25 control block given both ends. It will only pick up - * floating AX.25 control blocks or non Raw socket bound control blocks. + * ------------------------------------------------------------------------ + * Init functions. called by the kernel on startup + * ------------------------------------------------------------------------ */ -ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi *digi, struct net_device *dev) +void __init ax25_proto_init(struct net_proto *pro) { - ax25_cb *s; - unsigned long flags; + struct net_device *dev; - save_flags(flags); - cli(); + sock_register(&ax25_family_ops); + ax25_packet_type.type = htons(ETH_P_AX25); + dev_add_pack(&ax25_packet_type); + register_gifconf(PF_AX25, ax25_gifconf); + register_netdevice_notifier(&ax25_dev_notifier); + ax25_register_sysctl(); + ax25_ddi_init(); + ax25_netlink_init(); - for (s = ax25_list; s != NULL; s = s->next) { - if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET) - continue; - if (s->ax25_dev == NULL) - continue; - if (ax25cmp(&s->source_addr, src_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->ax25_dev->dev == dev) { - if (digi != NULL && digi->ndigi != 0) { - if (s->digipeat == NULL) - continue; - if (ax25digicmp(s->digipeat, digi) != 0) - continue; - } else { - if (s->digipeat != NULL && s->digipeat->ndigi != 0) - continue; - } - restore_flags(flags); - return s; + proc_net_create("ax25_route", 0, ax25_rt_get_info); + proc_net_create("ax25", 0, ax25_get_info); + proc_net_create("ax25_calls", 0, ax25_cs_get_info); + proc_net_create("ax25_ports", 0, ax25_dev_get_info); + printk(KERN_INFO "NET4: AX.25 for Linux 2.4-NET4 by DG2FEF\n"); + +#ifdef CONFIG_INET + ipax_init(); +#endif + for (dev=dev_base; dev!=NULL; dev=dev->next) { + if (dev->type == ARPHRD_AX25 && AX25_PTR(dev)) { + register_ax25device(dev); + if (netif_running(dev)) ax25_dev_device_up(dev); } } - - restore_flags(flags); - - return NULL; } -/* - * Look for any matching address - RAW sockets can bind to arbitrary names - */ -struct sock *ax25_addr_match(ax25_address *addr) +void __exit ax25_proto_remove(void) { - unsigned long flags; - ax25_cb *s; + int i; + struct net_device *dev; - save_flags(flags); - cli(); + proc_net_remove("ax25_route"); + proc_net_remove("ax25"); + proc_net_remove("ax25_calls"); + proc_net_remove("ax25_ports"); - for (s = ax25_list; s != NULL; s = s->next) { - if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == SOCK_RAW) { - restore_flags(flags); - return s->sk; + for (i=0; itype == SOCK_RAW && - sk->protocol == proto && - atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) { - if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL) - return; + ax25_rt_free(); +#ifdef CONFIG_INET + ipax_cleanup(); +#endif + ax25_netlink_cleanup(); + ax25_unregister_sysctl(); - if (sock_queue_rcv_skb(sk, copy) != 0) - kfree_skb(copy); - } + unregister_netdevice_notifier(&ax25_dev_notifier); + register_gifconf(PF_AX25, NULL); + dev_remove_pack(&ax25_packet_type); + sock_unregister(AF_AX25); - sk = sk->next; - } } /* - * Deferred destroy. + * ------------------------------------------------------------------------ + * module registration/unregistration + * ------------------------------------------------------------------------ */ -void ax25_destroy_socket(ax25_cb *); -/* - * Handler for deferred kills. - */ -static void ax25_destroy_timer(unsigned long data) -{ - ax25_destroy_socket((ax25_cb *)data); -} -/* - * This is called from user mode and the timers. Thus it protects itself against - * interrupt users but doesn't worry about being called during work. - * Once it is removed from the queue no interrupt or bottom half will - * touch it and we are (fairly 8-) ) safe. - */ -void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer */ +int __init ax25_init_module(void) { - struct sk_buff *skb; - unsigned long flags; - - save_flags(flags); cli(); + ax25_proto_init(NULL); + return 0; +} - ax25_stop_heartbeat(ax25); - ax25_stop_t1timer(ax25); - ax25_stop_t2timer(ax25); - ax25_stop_t3timer(ax25); - ax25_stop_idletimer(ax25); +MODULE_AUTHOR("Matthias Welwarsky, dg2fef@afthd.tu-darmstadt.de, dg2fef@db0ais.ampr.org"); +MODULE_DESCRIPTION("Packet Radio AX.25 Protocol stack"); +module_init(ax25_init_module); +module_exit(ax25_proto_remove); - ax25_remove_socket(ax25); - ax25_clear_queues(ax25); /* Flush the queues */ - if (ax25->sk != NULL) { - while ((skb = skb_dequeue(&ax25->sk->receive_queue)) != NULL) { - if (skb->sk != ax25->sk) { /* A pending connection */ - skb->sk->dead = 1; /* Queue the unaccepted socket for death */ - ax25_start_heartbeat(skb->sk->protinfo.ax25); - skb->sk->protinfo.ax25->state = AX25_STATE_0; - } +/* ---------------------------------------------------------------------*/ +/* + * Find the AX.25 device that matches the hardware address supplied. + */ - kfree_skb(skb); - } - } +struct net_device *ax25rtr_get_dev(ax25_address *addr) +{ + struct net_device *dev = NULL; + int i; - if (ax25->sk != NULL) { - if (atomic_read(&ax25->sk->wmem_alloc) != 0 || - atomic_read(&ax25->sk->rmem_alloc) != 0) { - /* Defer: outstanding buffers */ - init_timer(&ax25->timer); - ax25->timer.expires = jiffies + 10 * HZ; - ax25->timer.function = ax25_destroy_timer; - ax25->timer.data = (unsigned long)ax25; - add_timer(&ax25->timer); - } else { - sk_free(ax25->sk); - } - } else { - ax25_free_cb(ax25); + read_lock(&ax25_dev_lock); + for (i = 0; i < AX25_MAX_DEVICES; i++) { + dev = ax25_devices[i]; + if (dev != NULL && !ax25cmp(addr, (ax25_address *)dev->dev_addr)) + break; } + read_unlock(&ax25_dev_lock); - restore_flags(flags); + return dev; } +/* ---------------------------------------------------------------------*/ /* - * dl1bke 960311: set parameters for existing AX.25 connections, - * includes a KILL command to abort any connection. - * VERY useful for debugging ;-) + * Kill all bound sockets on a dropped device. */ -static int ax25_ctl_ioctl(const unsigned int cmd, void *arg) +void ax25_kill_by_device(struct net_device *dev) { - struct ax25_ctl_struct ax25_ctl; - ax25_digi digi; - ax25_dev *ax25_dev; - ax25_cb *ax25; - unsigned int k; - - if (copy_from_user(&ax25_ctl, arg, sizeof(ax25_ctl))) - return -EFAULT; - - if ((ax25_dev = ax25_addr_ax25dev(&ax25_ctl.port_addr)) == NULL) - return -ENODEV; - - if (ax25_ctl.digi_count > AX25_MAX_DIGIS) - return -EINVAL; - - digi.ndigi = ax25_ctl.digi_count; - for (k = 0; k < digi.ndigi; k++) - digi.calls[k] = ax25_ctl.digi_addr[k]; - - if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, &digi, ax25_dev->dev)) == NULL) - return -ENOTCONN; - - switch (ax25_ctl.cmd) { - case AX25_KILL: - ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); -#ifdef CONFIG_AX25_DAMA_SLAVE - if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE) - ax25_dama_off(ax25); -#endif - ax25_disconnect(ax25, ENETRESET); - break; + ax25_cb *s; + unsigned long flags; - case AX25_WINDOW: - if (ax25->modulus == AX25_MODULUS) { - if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7) - return -EINVAL; - } else { - if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63) - return -EINVAL; - } - ax25->window = ax25_ctl.arg; - break; - - case AX25_T1: - if (ax25_ctl.arg < 1) - return -EINVAL; - ax25->rtt = (ax25_ctl.arg * HZ) / 2; - ax25->t1 = ax25_ctl.arg * HZ; - break; - - case AX25_T2: - if (ax25_ctl.arg < 1) - return -EINVAL; - ax25->t2 = ax25_ctl.arg * HZ; - break; - - case AX25_N2: - if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31) - return -EINVAL; - ax25->n2count = 0; - ax25->n2 = ax25_ctl.arg; - break; - - case AX25_T3: - if (ax25_ctl.arg < 0) - return -EINVAL; - ax25->t3 = ax25_ctl.arg * HZ; - break; - - case AX25_IDLE: - if (ax25_ctl.arg < 0) - return -EINVAL; - ax25->idle = ax25_ctl.arg * 60 * HZ; - break; - - case AX25_PACLEN: - if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535) - return -EINVAL; - ax25->paclen = ax25_ctl.arg; - break; - - default: - return -EINVAL; - } - - return 0; + printk(KERN_WARNING "ax25_kill_by_device(%s)\n", dev->name); + save_flags(flags); + cli(); + for (s = ax25_dev_list(dev); s != NULL; s = ax25_dev_list(dev)) { + /* + * list structure is being modified by ax25_remove_cb, + * so we can not walk along ax25->next path + */ + if (s->peer && s->peer->device != s->device) + ax25_destroy_cb(s->peer); + if (s->sk) { + ax25_remove_cb(s); + ax25_disconnect(s, ENETUNREACH); + ax25_close_socket(s->sk, ENETUNREACH); + } else + ax25_destroy_cb(s); + } + restore_flags(flags); } /* - * Fill in a created AX.25 created control block with the default - * values for a particular device. + * ------------------------------------------------------------------------ + * End of public area, all private functions of this module are defined + * here. + * ------------------------------------------------------------------------ */ -void ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev) -{ - ax25->ax25_dev = ax25_dev; - - if (ax25->ax25_dev != NULL) { - ax25->rtt = ax25_dev->values[AX25_VALUES_T1] / 2; - ax25->t1 = ax25_dev->values[AX25_VALUES_T1]; - ax25->t2 = ax25_dev->values[AX25_VALUES_T2]; - ax25->t3 = ax25_dev->values[AX25_VALUES_T3]; - ax25->n2 = ax25_dev->values[AX25_VALUES_N2]; - ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN]; - ax25->idle = ax25_dev->values[AX25_VALUES_IDLE]; - ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF]; - - if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) { - ax25->modulus = AX25_EMODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW]; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = ax25_dev->values[AX25_VALUES_WINDOW]; - } - } else { - ax25->rtt = AX25_DEF_T1 / 2; - ax25->t1 = AX25_DEF_T1; - ax25->t2 = AX25_DEF_T2; - ax25->t3 = AX25_DEF_T3; - ax25->n2 = AX25_DEF_N2; - ax25->paclen = AX25_DEF_PACLEN; - ax25->idle = AX25_DEF_IDLE; - ax25->backoff = AX25_DEF_BACKOFF; - - if (AX25_DEF_AXDEFMODE) { - ax25->modulus = AX25_EMODULUS; - ax25->window = AX25_DEF_EWINDOW; - } else { - ax25->modulus = AX25_MODULUS; - ax25->window = AX25_DEF_WINDOW; - } - } -} +/* ---------------------------------------------------------------------*/ /* - * Create an empty AX.25 control block. + * Handle device status changes. */ -ax25_cb *ax25_create_cb(void) +static int ax25_device_event(struct notifier_block *this,unsigned long event, void *ptr) { - ax25_cb *ax25; - - if ((ax25 = kmalloc(sizeof(*ax25), GFP_ATOMIC)) == NULL) - return NULL; - - MOD_INC_USE_COUNT; - - memset(ax25, 0x00, sizeof(*ax25)); - - skb_queue_head_init(&ax25->write_queue); - skb_queue_head_init(&ax25->frag_queue); - skb_queue_head_init(&ax25->ack_queue); - skb_queue_head_init(&ax25->reseq_queue); - - init_timer(&ax25->timer); - init_timer(&ax25->t1timer); - init_timer(&ax25->t2timer); - init_timer(&ax25->t3timer); - init_timer(&ax25->idletimer); - - ax25_fillin_cb(ax25, NULL); + struct net_device *dev = (struct net_device *)ptr; - ax25->state = AX25_STATE_0; + /* Reject non AX.25 devices */ + if (dev->type != ARPHRD_AX25 || !AX25_PTR(dev)) + return NOTIFY_DONE; - return ax25; + switch (event) { + case NETDEV_UP: + ax25_dev_device_up(dev); + break; + case NETDEV_DOWN: + ax25_dev_device_down(dev); + break; + case NETDEV_REGISTER: + register_ax25device(dev); + break; + case NETDEV_UNREGISTER: + unregister_ax25device(dev); + break; + default: + break; + } + return NOTIFY_DONE; } + +/* ---------------------------------------------------------------------*/ /* * Handling for system calls applied via the various interfaces to an * AX25 socket object @@ -646,7 +370,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op switch (optname) { case AX25_WINDOW: - if (sk->protinfo.ax25->modulus == AX25_MODULUS) { + if (sk->protinfo.ax25->seqmask == AX25_SEQMASK) { if (opt < 1 || opt > 7) return -EINVAL; } else { @@ -659,14 +383,14 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op case AX25_T1: if (opt < 1) return -EINVAL; - sk->protinfo.ax25->rtt = (opt * HZ) / 2; - sk->protinfo.ax25->t1 = opt * HZ; + sk->protinfo.ax25->t1 = opt; + sk->protinfo.ax25->rtt = (opt * AX25_TICS) / 4; return 0; case AX25_T2: - if (opt < 1) + if (opt < 0) return -EINVAL; - sk->protinfo.ax25->t2 = opt * HZ; + sk->protinfo.ax25->t2 = opt; return 0; case AX25_N2: @@ -678,13 +402,13 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op case AX25_T3: if (opt < 1) return -EINVAL; - sk->protinfo.ax25->t3 = opt * HZ; + sk->protinfo.ax25->t3 = opt * AX25_SLOWHZ; return 0; case AX25_IDLE: if (opt < 0) return -EINVAL; - sk->protinfo.ax25->idle = opt * 60 * HZ; + sk->protinfo.ax25->idle = opt * AX25_SLOWHZ; return 0; case AX25_BACKOFF: @@ -694,7 +418,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op return 0; case AX25_EXTSEQ: - sk->protinfo.ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS; + sk->protinfo.ax25->seqmask = opt ? AX25_ESEQMASK : AX25_SEQMASK; return 0; case AX25_PIDINCL: @@ -712,19 +436,18 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op return 0; case SO_BINDTODEVICE: - if (optlen > IFNAMSIZ) optlen=IFNAMSIZ; + if (optlen > IFNAMSIZ) optlen = IFNAMSIZ; if (copy_from_user(devname, optval, optlen)) return -EFAULT; dev = dev_get_by_name(devname); if (dev == NULL) return -ENODEV; - if (sk->type == SOCK_SEQPACKET && + if (sk->type == SOCK_SEQPACKET && (sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN)) return -EADDRNOTAVAIL; - - sk->protinfo.ax25->ax25_dev = ax25_dev_ax25dev(dev); - ax25_fillin_cb(sk->protinfo.ax25, sk->protinfo.ax25->ax25_dev); + + ax25_fillin_cb(sk->protinfo.ax25, dev); return 0; default: @@ -732,10 +455,12 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op } } +/* ---------------------------------------------------------------------*/ + static int ax25_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) { struct sock *sk = sock->sk; - struct ax25_dev *ax25_dev; + struct net_device *dev; char devname[IFNAMSIZ]; void *valptr; int val = 0; @@ -759,11 +484,11 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op break; case AX25_T1: - val = sk->protinfo.ax25->t1 / HZ; + val = sk->protinfo.ax25->t1; break; case AX25_T2: - val = sk->protinfo.ax25->t2 / HZ; + val = sk->protinfo.ax25->t2; break; case AX25_N2: @@ -771,11 +496,11 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op break; case AX25_T3: - val = sk->protinfo.ax25->t3 / HZ; + val = sk->protinfo.ax25->t3 / AX25_SLOWHZ; break; case AX25_IDLE: - val = sk->protinfo.ax25->idle / (60 * HZ); + val = sk->protinfo.ax25->idle / AX25_SLOWHZ; break; case AX25_BACKOFF: @@ -783,7 +508,7 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op break; case AX25_EXTSEQ: - val = (sk->protinfo.ax25->modulus == AX25_EMODULUS); + val = (sk->protinfo.ax25->seqmask == AX25_ESEQMASK); break; case AX25_PIDINCL: @@ -799,11 +524,11 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op break; case SO_BINDTODEVICE: - ax25_dev = sk->protinfo.ax25->ax25_dev; + dev = sk->protinfo.ax25->device; - if (ax25_dev != NULL && ax25_dev->dev != NULL) { - strncpy(devname, ax25_dev->dev->name, IFNAMSIZ); - length = min(strlen(ax25_dev->dev->name)+1, maxlen); + if (dev != NULL) { + strncpy(devname, dev->name, IFNAMSIZ); + length = min(strlen(dev->name)+1, maxlen); devname[length-1] = '\0'; } else { *devname = '\0'; @@ -820,68 +545,84 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op if (put_user(length, optlen)) return -EFAULT; - return copy_to_user(optval, valptr, length) ? -EFAULT : 0; + if (copy_to_user(optval, valptr, length)) + return -EFAULT; + + return 0; } +/* ---------------------------------------------------------------------*/ + static int ax25_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; - if (sk->type == SOCK_SEQPACKET && sk->state != TCP_LISTEN) { + if (sk->type != SOCK_SEQPACKET) + return -EOPNOTSUPP; + + if (sk->state != TCP_LISTEN) { + /* + * POSIX VIOLATION: according to listen(2) the call can + * never return EADDRINUSE. bind(2) should have done this. + * However, things are different with AX.25. You are + * _required_ to bind() before connect() to set the + * source callsign of the outgoing connection. But as you + * may open multiple connections at one time with the + * same source callsign, you cannot perform this check + * within bind(). And as I like to have descriptive errors, + * EADDRINUSE is perfect to be returned here. + */ + if (ax25_find_listener(&sk->protinfo.ax25->addr.src, sk->protinfo.ax25->iamdigi, sk->protinfo.ax25->device)) + return -EADDRINUSE; + + ax25_insert_cb(sk->protinfo.ax25); sk->max_ack_backlog = backlog; sk->state = TCP_LISTEN; return 0; } - return -EOPNOTSUPP; + return -EINVAL; } -int ax25_create(struct socket *sock, int protocol) +/* ---------------------------------------------------------------------*/ + +static int ax25_create(struct socket *sock, int protocol) { struct sock *sk; ax25_cb *ax25; switch (sock->type) { - case SOCK_DGRAM: - if (protocol == 0 || protocol == PF_AX25) - protocol = AX25_P_TEXT; + case SOCK_DGRAM: + if (protocol == 0 || protocol == PF_AX25) + protocol = AX25_P_TEXT; + break; + case SOCK_SEQPACKET: + switch (protocol) { + case 0: + case PF_AX25: /* For CLX */ + protocol = AX25_P_TEXT; break; - case SOCK_SEQPACKET: - switch (protocol) { - case 0: - case PF_AX25: /* For CLX */ - protocol = AX25_P_TEXT; - break; - case AX25_P_SEGMENT: + case AX25_P_SEGMENT: #ifdef CONFIG_INET - case AX25_P_ARP: - case AX25_P_IP: + case AX25_P_ARP: #endif #ifdef CONFIG_NETROM - case AX25_P_NETROM: + case AX25_P_NETROM: #endif #ifdef CONFIG_ROSE - case AX25_P_ROSE: -#endif - return -ESOCKTNOSUPPORT; -#ifdef CONFIG_NETROM_MODULE - case AX25_P_NETROM: - if (ax25_protocol_is_registered(AX25_P_NETROM)) - return -ESOCKTNOSUPPORT; + case AX25_P_ROSE: #endif -#ifdef CONFIG_ROSE_MODULE - case AX25_P_ROSE: - if (ax25_protocol_is_registered(AX25_P_ROSE)) - return -ESOCKTNOSUPPORT; -#endif - default: - break; - } - break; - case SOCK_RAW: - break; - default: return -ESOCKTNOSUPPORT; + + default: + if (ax25_protocol_is_registered(protocol)) + return -ESOCKTNOSUPPORT; + } + break; + case SOCK_RAW: + break; + default: + return -ESOCKTNOSUPPORT; } if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, 1)) == NULL) @@ -904,226 +645,162 @@ int ax25_create(struct socket *sock, int protocol) return 0; } -struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) +static int ax25_release(struct socket *sock) { - struct sock *sk; + struct sock *sk = sock->sk; ax25_cb *ax25; - if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, 1)) == NULL) - return NULL; + if (sk == NULL) + return 0; - if ((ax25 = ax25_create_cb()) == NULL) { - sk_free(sk); - return NULL; - } + ax25 = sk->protinfo.ax25; - switch (osk->type) { - case SOCK_DGRAM: - break; - case SOCK_SEQPACKET: - break; - default: - sk_free(sk); - ax25_free_cb(ax25); - return NULL; - } + sk->state = TCP_CLOSE; + sk->shutdown = SHUTDOWN_MASK; + /* + * don't wake me, I'm dying: this one has cost me nerves a bit. + * Seems that we should not attempt to wake an application + * that is currently exiting, which is exactly what state_change() + * does. It results in calling __wake_up() with invalid arguments + */ + if (!(current->flags & PF_EXITING)) + sk->state_change(sk); + sk->dead = 1; - sock_init_data(NULL, sk); + if (sk->type == SOCK_STREAM || sk->type == SOCK_SEQPACKET) { + switch (ax25->state) { + default: + ax25_remove_cb(ax25); + break; - sk->destruct = ax25_free_sock; - sk->type = osk->type; - sk->socket = osk->socket; - sk->priority = osk->priority; - sk->protocol = osk->protocol; - sk->rcvbuf = osk->rcvbuf; - sk->sndbuf = osk->sndbuf; - sk->debug = osk->debug; - sk->state = TCP_ESTABLISHED; - sk->sleep = osk->sleep; - sk->zapped = osk->zapped; - - ax25->modulus = osk->protinfo.ax25->modulus; - ax25->backoff = osk->protinfo.ax25->backoff; - ax25->pidincl = osk->protinfo.ax25->pidincl; - ax25->iamdigi = osk->protinfo.ax25->iamdigi; - ax25->rtt = osk->protinfo.ax25->rtt; - ax25->t1 = osk->protinfo.ax25->t1; - ax25->t2 = osk->protinfo.ax25->t2; - ax25->t3 = osk->protinfo.ax25->t3; - ax25->n2 = osk->protinfo.ax25->n2; - ax25->idle = osk->protinfo.ax25->idle; - ax25->paclen = osk->protinfo.ax25->paclen; - ax25->window = osk->protinfo.ax25->window; - - ax25->ax25_dev = ax25_dev; - ax25->source_addr = osk->protinfo.ax25->source_addr; - - if (osk->protinfo.ax25->digipeat != NULL) { - if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - sk_free(sk); - return NULL; + case AX25_STATE_3: /* connected */ + case AX25_STATE_4: /* timer recovery */ + ax25_set_cond(ax25, AX25_COND_RELEASE); + break; } - - memcpy(ax25->digipeat, osk->protinfo.ax25->digipeat, sizeof(ax25_digi)); } - sk->protinfo.ax25 = ax25; - ax25->sk = sk; - - return sk; -} - -static int ax25_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - - if (sk == NULL) return 0; - - if (sk->type == SOCK_SEQPACKET) { - switch (sk->protinfo.ax25->state) { - case AX25_STATE_0: - ax25_disconnect(sk->protinfo.ax25, 0); - ax25_destroy_socket(sk->protinfo.ax25); - break; - - case AX25_STATE_1: - case AX25_STATE_2: - ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25_disconnect(sk->protinfo.ax25, 0); - ax25_destroy_socket(sk->protinfo.ax25); - break; - - case AX25_STATE_3: - case AX25_STATE_4: - ax25_clear_queues(sk->protinfo.ax25); - sk->protinfo.ax25->n2count = 0; - switch (sk->protinfo.ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); - ax25_stop_t2timer(sk->protinfo.ax25); - ax25_stop_t3timer(sk->protinfo.ax25); - ax25_stop_idletimer(sk->protinfo.ax25); - break; -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - ax25_stop_t3timer(sk->protinfo.ax25); - ax25_stop_idletimer(sk->protinfo.ax25); - break; -#endif - } - ax25_calculate_t1(sk->protinfo.ax25); - ax25_start_t1timer(sk->protinfo.ax25); - sk->protinfo.ax25->state = AX25_STATE_2; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; - sk->destroy = 1; - break; - - default: - break; - } + sk->protinfo.ax25 = NULL; + if (ax25->inserted && ax25->device != NULL) { + ax25->killtimer = 0; + ax25->sk = NULL; } else { - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - sk->dead = 1; - ax25_destroy_socket(sk->protinfo.ax25); + ax25_destroy_cb(ax25); } - - sock->sk = NULL; - sk->socket = NULL; /* Not used, but we should do this */ - + ax25_destroy_socket(sk); return 0; } +/* ---------------------------------------------------------------------*/ /* - * We support a funny extension here so you can (as root) give any callsign - * digipeated via a local address as source. This hack is obsolete now - * that we've implemented support for SO_BINDTODEVICE. It is however small - * and trivially backward compatible. + * Former semantics: + * + * - struct sockaddr_ax25 contains the interface callsign, outgoing + * user connects either get the interface callsign or the one + * provided by the uid/callsign translation table for the source + * address + * + * - struct full_sockaddr_ax25 provides the interface callsign as + * the first digipeater, fsa.fsa_ax25call provides the source + * address for the connection. + * + * New semantics: + * + * We now have SO_BINDTODEVICE, ax25_bind (should) only set the + * source address. Thus we'll allow the "bind to device callsign + * provided with the digipeater field" hack only for backward + * compatibility. + * + * NB: I don't follow Matthias' and Jens' patch here as I do + * plan to allow multiple callsigns for one uid (including + * multiple SSIDs) and assigning user callsigns per interface. */ + static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sock *sk = sock->sk; struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; - ax25_address *call; - ax25_dev *ax25_dev = NULL; + struct net_device *dev; + ax25_address *call = NULL; + /* already bound */ if (sk->zapped == 0) return -EINVAL; - if (addr_len != sizeof(struct sockaddr_ax25) && - addr_len != sizeof(struct full_sockaddr_ax25)) { - /* support for old structure may go away some time */ - if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || - (addr_len > sizeof(struct full_sockaddr_ax25))) - return -EINVAL; - - printk(KERN_WARNING "ax25_bind(): %s uses old (6 digipeater) socket structure.\n", - current->comm); - } - - if (addr->fsa_ax25.sax25_family != AF_AX25) + if (addr_len != sizeof(struct sockaddr_ax25) && + addr_len != sizeof(struct full_sockaddr_ax25)) return -EINVAL; - call = ax25_findbyuid(current->euid); - if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN)) - return -EACCES; - - if (call == NULL) - sk->protinfo.ax25->source_addr = addr->fsa_ax25.sax25_call; - else - sk->protinfo.ax25->source_addr = *call; + /* wrong family */ + if (addr->fsax25_family != AF_AX25) + return -EINVAL; /* - * User already set interface with SO_BINDTODEVICE + * User did not set interface with SO_BINDTODEVICE + * thus we'll use the compatibility code */ - if (sk->protinfo.ax25->ax25_dev != NULL) - goto done; + dev = sk->protinfo.ax25->device; + if (dev == NULL) { + /* Try to find the interface... */ + if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsax25_ndigis == 1) { + /* device callsign provided... */ + if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 && + (dev = ax25rtr_get_dev(&addr->fsa_digipeater[0])) == NULL) + return -EADDRNOTAVAIL; + } else { + /* addr->fsax25_call is device callsign */ + if ((dev = ax25rtr_get_dev(&addr->fsax25_call)) == NULL) + return -EADDRNOTAVAIL; + } + + ax25_fillin_cb(sk->protinfo.ax25, dev); + } - if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) { - if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 && - (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) - return -EADDRNOTAVAIL; - } else { - if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) - return -EADDRNOTAVAIL; + /* root can do whatever (s)he likes, but anyone else... */ + if (!capable(CAP_NET_BIND_SERVICE)) + { + call = ax25_find_match_for_uid(current->euid, &addr->fsax25_call, dev->name); + if (call == NULL && ax25_uid_policy) + return -EACCES; } - if (ax25_dev != NULL) - ax25_fillin_cb(sk->protinfo.ax25, ax25_dev); + if (call == NULL) call = &addr->fsax25_call; -done: - ax25_insert_socket(sk->protinfo.ax25); + sk->protinfo.ax25->addr.src = *call; + sk->protinfo.ax25->addr.dcount = 0; + sk->protinfo.ax25->addr.lastrepeat = -1; + +// ax25_insert_socket(sk->protinfo.ax25); /* FIXME: gone with Matthias' patch, intentionally? */ sk->zapped = 0; return 0; } -/* - * FIXME: nonblock behaviour looks like it may have a bug. - */ -static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) +/* ---------------------------------------------------------------------*/ + +static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, + int addr_len, int flags) { struct sock *sk = sock->sk; struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr; - ax25_digi *digi = NULL; + ax25_addr_t *addr; + ax25_address *dest; int ct = 0, err; /* deal with restarts */ if (sock->state == SS_CONNECTING) { switch (sk->state) { case TCP_SYN_SENT: /* still trying */ - return -EINPROGRESS; + if (!(flags & O_NONBLOCK)) + goto wait_for_con; + return -EALREADY; case TCP_ESTABLISHED: /* connection established */ sock->state = SS_CONNECTED; return 0; case TCP_CLOSE: /* connection refused */ + case TCP_CLOSE_WAIT: sock->state = SS_UNCONNECTED; return -ECONNREFUSED; } @@ -1139,118 +816,77 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le * some sanity checks. code further down depends on this */ - if (addr_len == sizeof(struct sockaddr_ax25)) { - /* support for this will go away in early 2.5.x */ + if (addr_len == sizeof(struct sockaddr_ax25)) printk(KERN_WARNING "ax25_connect(): %s uses obsolete socket structure\n", current->comm); - } - else if (addr_len != sizeof(struct full_sockaddr_ax25)) { - /* support for old structure may go away some time */ - if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || - (addr_len > sizeof(struct full_sockaddr_ax25))) - return -EINVAL; - - printk(KERN_WARNING "ax25_connect(): %s uses old (6 digipeater) socket structure.\n", - current->comm); - } - - if (fsa->fsa_ax25.sax25_family != AF_AX25) + else if (addr_len != sizeof(struct full_sockaddr_ax25)) return -EINVAL; - if (sk->protinfo.ax25->digipeat != NULL) { - kfree(sk->protinfo.ax25->digipeat); - sk->protinfo.ax25->digipeat = NULL; - } - /* * Handle digi-peaters to be used. */ - if (addr_len > sizeof(struct sockaddr_ax25) && fsa->fsa_ax25.sax25_ndigis != 0) { + SOCK_DEBUG(sk, "ax25_connect: ndigi=%d\n", fsa->fsax25_ndigis); + + addr = &sk->protinfo.ax25->addr; + addr->dcount = 0; + addr->lastrepeat = -1; + if (addr_len > sizeof(struct sockaddr_ax25) && fsa->fsax25_ndigis != 0) { /* Valid number of digipeaters ? */ - if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) + if (fsa->fsax25_ndigis < 0 || fsa->fsax25_ndigis > AX25_MAX_DIGIS) return -EINVAL; - if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) - return -ENOBUFS; + addr->dcount = fsa->fsax25_ndigis; - digi->ndigi = fsa->fsa_ax25.sax25_ndigis; - digi->lastrepeat = -1; - - while (ct < fsa->fsa_ax25.sax25_ndigis) { - if ((fsa->fsa_digipeater[ct].ax25_call[6] & AX25_HBIT) && sk->protinfo.ax25->iamdigi) { - digi->repeated[ct] = 1; - digi->lastrepeat = ct; - } else { - digi->repeated[ct] = 0; - } - digi->calls[ct] = fsa->fsa_digipeater[ct]; + while (ct < fsa->fsax25_ndigis) { + if ((fsa->fsa_digipeater[ct].ax25_call[6] & AX25_HBIT) && sk->protinfo.ax25->iamdigi) + addr->lastrepeat = ct; + addr->digipeater[ct] = fsa->fsa_digipeater[ct]; ct++; } + + /* where to go next? either to next digipeater in path ...*/ + dest = &addr->digipeater[addr->lastrepeat+1]; + } else { + /* ... or directly to the destination */ + dest = &fsa->fsax25_call; } - /* - * Must bind first - autobinding in this may or may not work. If - * the socket is already bound, check to see if the device has - * been filled in, error if it hasn't. - */ - if (sk->zapped) { - /* check if we can remove this feature. It is broken. */ - printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@yaina.de\n", - current->comm); - if ((err = ax25_rt_autobind(sk->protinfo.ax25, &fsa->fsa_ax25.sax25_call)) < 0) + if (sk->protinfo.ax25->device == NULL) { + if ((err = ax25_rt_fillin_dev(sk->protinfo.ax25, dest)) < 0) return err; - ax25_fillin_cb(sk->protinfo.ax25, sk->protinfo.ax25->ax25_dev); - ax25_insert_socket(sk->protinfo.ax25); - } else { - if (sk->protinfo.ax25->ax25_dev == NULL) - return -EHOSTUNREACH; + SOCK_DEBUG(sk, "ax25_connect: device filled in\n"); } + addr->dest = fsa->fsax25_call; - if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi, sk->protinfo.ax25->ax25_dev->dev) != NULL) { - if (digi != NULL) kfree(digi); - return -EADDRINUSE; /* Already such a connection */ + if (sk->type == SOCK_SEQPACKET) { + ax25_cb* ax25 = ax25_find_cb(addr, sk->protinfo.ax25->device); + if (ax25) { + if (ax25->state != AX25_STATE_0) + return -EADDRINUSE; /* Already such a connection */ + ax25_destroy_cb(ax25); + } } - sk->protinfo.ax25->dest_addr = fsa->fsa_ax25.sax25_call; - sk->protinfo.ax25->digipeat = digi; + ax25_insert_cb(sk->protinfo.ax25); /* First the easy one */ - if (sk->type != SOCK_SEQPACKET) { + if (sk->type != SOCK_SEQPACKET && sk->type != SOCK_STREAM) { sock->state = SS_CONNECTED; sk->state = TCP_ESTABLISHED; return 0; } /* Move to connecting socket, ax.25 lapb WAIT_UA.. */ - sock->state = SS_CONNECTING; - sk->state = TCP_SYN_SENT; - - switch (sk->protinfo.ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { - case AX25_PROTO_STD_SIMPLEX: - case AX25_PROTO_STD_DUPLEX: - ax25_std_establish_data_link(sk->protinfo.ax25); - break; - -#ifdef CONFIG_AX25_DAMA_SLAVE - case AX25_PROTO_DAMA_SLAVE: - sk->protinfo.ax25->modulus = AX25_MODULUS; - sk->protinfo.ax25->window = sk->protinfo.ax25->ax25_dev->values[AX25_VALUES_WINDOW]; - if (sk->protinfo.ax25->ax25_dev->dama.slave) - ax25_ds_establish_data_link(sk->protinfo.ax25); - else - ax25_std_establish_data_link(sk->protinfo.ax25); - break; -#endif - } - - sk->protinfo.ax25->state = AX25_STATE_1; - - ax25_start_heartbeat(sk->protinfo.ax25); + sock->state = SS_CONNECTING; + sk->state = TCP_SYN_SENT; + /* Start going SABM SABM until a UA or a give up and DM */ + ax25_establish_data_link(sk->protinfo.ax25); /* Now the loop */ if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) return -EINPROGRESS; + wait_for_con: cli(); /* To avoid races on the sleep */ /* A DM or timeout will go to closed, a UA will go to ABM */ @@ -1270,12 +906,11 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le } sock->state = SS_CONNECTED; - sti(); - return 0; } +/* ---------------------------------------------------------------------*/ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) { @@ -1310,12 +945,14 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) } } while (skb == NULL); - newsk = skb->sk; - newsk->pair = NULL; + newsk = skb->sk; + newsk->pair = NULL; newsk->socket = newsock; newsk->sleep = &newsock->wait; /* Now attach up the new socket */ + skb->sk = NULL; + skb->destructor = NULL; kfree_skb(skb); sk->ack_backlog--; newsock->sk = newsk; @@ -1324,132 +961,108 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) return 0; } +/* ---------------------------------------------------------------------*/ + static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { + struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr; struct sock *sk = sock->sk; - struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr; - unsigned char ndigi, i; + unsigned char dcount; - if (peer != 0) { + if (peer) { if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; - fsa->fsa_ax25.sax25_family = AF_AX25; - fsa->fsa_ax25.sax25_call = sk->protinfo.ax25->dest_addr; - fsa->fsa_ax25.sax25_ndigis = 0; - - if (sk->protinfo.ax25->digipeat != NULL) { - ndigi = sk->protinfo.ax25->digipeat->ndigi; - fsa->fsa_ax25.sax25_ndigis = ndigi; - for (i = 0; i < ndigi; i++) - fsa->fsa_digipeater[i] = sk->protinfo.ax25->digipeat->calls[i]; - } + sax->fsax25_family = AF_AX25; + sax->fsax25_call = sk->protinfo.ax25->addr.dest; + dcount = sax->fsax25_ndigis = sk->protinfo.ax25->addr.dcount; + memcpy(sax->fsa_digipeater, sk->protinfo.ax25->addr.digipeater, dcount * AX25_ADDR_LEN); } else { - fsa->fsa_ax25.sax25_family = AF_AX25; - fsa->fsa_ax25.sax25_call = sk->protinfo.ax25->source_addr; - fsa->fsa_ax25.sax25_ndigis = 1; - if (sk->protinfo.ax25->ax25_dev != NULL) { - memcpy(&fsa->fsa_digipeater[0], sk->protinfo.ax25->ax25_dev->dev->dev_addr, AX25_ADDR_LEN); + sax->fsax25_family = AF_AX25; + sax->fsax25_call = sk->protinfo.ax25->addr.src; + + if (sk->protinfo.ax25->device != NULL) { + sax->fsax25_ndigis = 1; + memcpy(&sax->fsa_digipeater[0], sk->protinfo.ax25->device->dev_addr, AX25_ADDR_LEN); } else { - fsa->fsa_digipeater[0] = null_ax25_address; + sax->fsax25_ndigis = 0; } } *uaddr_len = sizeof (struct full_sockaddr_ax25); return 0; } +/* ---------------------------------------------------------------------*/ + static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) { struct sock *sk = sock->sk; struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name; int err; - struct sockaddr_ax25 sax; struct sk_buff *skb; unsigned char *asmptr; int size; - ax25_digi *dp; - ax25_digi dtmp; int lv; int addr_len = msg->msg_namelen; + ax25_addr_t addr; if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) return -EINVAL; + /* socket must be bound to a name */ if (sk->zapped) return -EADDRNOTAVAIL; + /* socket ist shut down */ if (sk->shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); return -EPIPE; } - if (sk->protinfo.ax25->ax25_dev == NULL) + if (sk->protinfo.ax25->device == NULL) return -ENETUNREACH; - if (usax != NULL) { + if (addr_len != 0) { if (usax->sax25_family != AF_AX25) return -EINVAL; + if (sk->type == SOCK_SEQPACKET) + return -EISCONN; - if (addr_len == sizeof(struct sockaddr_ax25)) { + if (addr_len != sizeof(struct sockaddr_ax25)) { printk(KERN_WARNING "ax25_sendmsg(): %s uses obsolete socket structure\n", current->comm); - } - else if (addr_len != sizeof(struct full_sockaddr_ax25)) { - /* support for old structure may go away some time */ - if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || - (addr_len > sizeof(struct full_sockaddr_ax25))) - return -EINVAL; - - printk(KERN_WARNING "ax25_sendmsg(): %s uses old (6 digipeater) socket structure.\n", - current->comm); - } + } else if (addr_len != sizeof(struct full_sockaddr_ax25)) + return -EINVAL; if (addr_len > sizeof(struct sockaddr_ax25) && usax->sax25_ndigis != 0) { - int ct = 0; struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax; + int ct; /* Valid number of digipeaters ? */ - if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS) + if (usax->sax25_ndigis < 0 || usax->sax25_ndigis > AX25_MAX_DIGIS) return -EINVAL; - dtmp.ndigi = usax->sax25_ndigis; - - while (ct < usax->sax25_ndigis) { - dtmp.repeated[ct] = 0; - dtmp.calls[ct] = fsa->fsa_digipeater[ct]; - ct++; - } - - dtmp.lastrepeat = 0; + for (ct = 0; ct < usax->sax25_ndigis; ct++) + addr.digipeater[ct] = fsa->fsa_digipeater[ct]; + addr.lastrepeat = -1; } - - sax = *usax; - if (sk->type == SOCK_SEQPACKET && ax25cmp(&sk->protinfo.ax25->dest_addr, &sax.sax25_call) != 0) - return -EISCONN; - if (usax->sax25_ndigis == 0) - dp = NULL; - else - dp = &dtmp; + addr.dcount = usax->sax25_ndigis; + addr.dest = usax->sax25_call; } else { - /* - * FIXME: 1003.1g - if the socket is like this because - * it has become closed (not started closed) and is VC - * we ought to SIGPIPE, EPIPE - */ - if (sk->state != TCP_ESTABLISHED) + if (sk->state != TCP_ESTABLISHED) { + if (sk->dead) { + send_sig(SIGPIPE, current, 0); + return -EPIPE; + } return -ENOTCONN; - sax.sax25_family = AF_AX25; - sax.sax25_call = sk->protinfo.ax25->dest_addr; - dp = sk->protinfo.ax25->digipeat; + } + addr = sk->protinfo.ax25->addr; } - SOCK_DEBUG(sk, "AX.25: sendto: Addresses built.\n"); - - /* Build a packet */ - SOCK_DEBUG(sk, "AX.25: sendto: building packet.\n"); + SOCK_DEBUG(sk, "AX.25: sendto: Addresses built, building packet.\n"); /* Assume the worst case */ - size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN; + size = len + 3 + ax25_sizeof_addr(&addr) + AX25_BPQ_HEADER_LEN; if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; @@ -1463,10 +1076,8 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct skb->nh.raw = skb->data; /* Add the PID if one is not supplied by the user in the skb */ - if (!sk->protinfo.ax25->pidincl) { - asmptr = skb_push(skb, 1); - *asmptr = sk->protocol; - } + if (!sk->protinfo.ax25->pidincl) + *skb_push(skb, 1) = sk->protocol; SOCK_DEBUG(sk, "AX.25: Transmitting buffer\n"); @@ -1476,44 +1087,38 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct kfree_skb(skb); return -ENOTCONN; } - ax25_output(sk->protinfo.ax25, sk->protinfo.ax25->paclen, skb); /* Shove it onto the queue and kick */ - return len; - } else { - asmptr = skb_push(skb, 1 + ax25_addr_size(dp)); - - SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp); - - if (dp != NULL) - SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi); - - /* Build an AX.25 header */ - asmptr += (lv = ax25_addr_build(asmptr, &sk->protinfo.ax25->source_addr, &sax.sax25_call, dp, AX25_COMMAND, AX25_MODULUS)); + } - SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv); + addr.src = sk->protinfo.ax25->addr.src; + asmptr = skb_push(skb, ax25_sizeof_addr(&addr)+1); - skb->h.raw = asmptr; + SOCK_DEBUG(sk, "Num digipeaters=%d\n", addr.dcount); - SOCK_DEBUG(sk, "base=%p pos=%p\n", skb->data, asmptr); + /* Build an AX.25 header */ + lv = ax25_build_addr(asmptr, &addr, AX25_COMMAND, AX25_SEQMASK); + asmptr += lv; - *asmptr = AX25_UI; + SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv); + SOCK_DEBUG(sk, "base=%p pos=%p\n", skb->data, asmptr); - /* Datagram frames go straight out of the door as UI */ - skb->dev = sk->protinfo.ax25->ax25_dev->dev; + *asmptr = AX25_UI; - ax25_queue_xmit(skb); + /* Datagram frames go straight out of the door as UI */ + ax25_send_unproto(skb, sk->protinfo.ax25->device); - return len; - } + return len; } +/* ---------------------------------------------------------------------*/ + static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) { struct sock *sk = sock->sk; int copied; struct sk_buff *skb; - int er; + int err; /* * This works for seqpacket too. The receiver has ordered the @@ -1523,8 +1128,8 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f return -ENOTCONN; /* Now we can treat all alike */ - if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) - return er; + if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &err)) == NULL) + return err; if (!sk->protinfo.ax25->pidincl) skb_pull(skb, 1); /* Remove PID */ @@ -1540,25 +1145,19 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (msg->msg_namelen != 0) { - struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name; - ax25_digi digi; - ax25_address dest; + struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)msg->msg_name; + ax25_pktinfo pkt; - ax25_addr_parse(skb->mac.raw+1, skb->data-skb->mac.raw-1, NULL, &dest, &digi, NULL, NULL); + ax25_parse_addr(skb->mac.raw, skb->data-skb->mac.raw, &pkt); - sax->sax25_family = AF_AX25; - /* We set this correctly, even though we may not let the - application know the digi calls further down (because it - did NOT ask to know them). This could get political... **/ - sax->sax25_ndigis = digi.ndigi; - sax->sax25_call = dest; + sax->fsax25_family = AF_AX25; + sax->fsax25_ndigis = pkt.addr.dcount; + sax->fsax25_call = pkt.addr.dest; - if (sax->sax25_ndigis != 0) { + if (sax->fsax25_ndigis != 0) { int ct; - struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)sax; - - for (ct = 0; ct < digi.ndigi; ct++) - fsa->fsa_digipeater[ct] = digi.calls[ct]; + for (ct = 0; ct < pkt.addr.dcount; ct++) + sax->fsa_digipeater[ct] = pkt.addr.digipeater[ct]; } msg->msg_namelen = sizeof(struct full_sockaddr_ax25); } @@ -1568,12 +1167,31 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f return copied; } -static int ax25_shutdown(struct socket *sk, int how) +/* ---------------------------------------------------------------------*/ + +static int ax25_shutdown(struct socket *sock, int how) { - /* FIXME - generate DM and RNR states */ - return -EOPNOTSUPP; + switch (how) { + case 0: + sock->sk->shutdown = RCV_SHUTDOWN; + break; + + case 1: + sock->sk->shutdown = SEND_SHUTDOWN; + break; + + case 2: + sock->sk->shutdown = SHUTDOWN_MASK; + break; + + default: + return -EINVAL; + } + return 0; } +/* ---------------------------------------------------------------------*/ + static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; @@ -1584,7 +1202,9 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; - return put_user(amount, (int *)arg); + if (put_user(amount, (int *)arg)) + return -EFAULT; + return 0; } case TIOCINQ: { @@ -1593,15 +1213,19 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->receive_queue)) != NULL) amount = skb->len; - return put_user(amount, (int *)arg); + if (put_user(amount, (int *)arg)) + return -EFAULT; + return 0; } case SIOCGSTAMP: if (sk != NULL) { if (sk->stamp.tv_sec == 0) return -ENOENT; - return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; - } + if (copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) + return -EFAULT; + return 0; + } return -EINVAL; case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */ @@ -1637,29 +1261,31 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) return -EPERM; return ax25_ctl_ioctl(cmd, (void *)arg); - case SIOCAX25GETINFO: + case SIOCAX25GETINFO: case SIOCAX25GETINFOOLD: { struct ax25_info_struct ax25_info; - ax25_info.t1 = sk->protinfo.ax25->t1 / HZ; - ax25_info.t2 = sk->protinfo.ax25->t2 / HZ; - ax25_info.t3 = sk->protinfo.ax25->t3 / HZ; - ax25_info.idle = sk->protinfo.ax25->idle / (60 * HZ); + read_lock(&sk->protinfo.ax25->timer_lock); + ax25_info.t1 = sk->protinfo.ax25->t1; + ax25_info.t2 = sk->protinfo.ax25->t2; + ax25_info.t3 = sk->protinfo.ax25->t3 / AX25_SLOWHZ; + ax25_info.idle = sk->protinfo.ax25->idle / AX25_SLOWHZ; ax25_info.n2 = sk->protinfo.ax25->n2; - ax25_info.t1timer = ax25_display_timer(&sk->protinfo.ax25->t1timer) / HZ; - ax25_info.t2timer = ax25_display_timer(&sk->protinfo.ax25->t2timer) / HZ; - ax25_info.t3timer = ax25_display_timer(&sk->protinfo.ax25->t3timer) / HZ; - ax25_info.idletimer = ax25_display_timer(&sk->protinfo.ax25->idletimer) / (60 * HZ); + ax25_info.t1timer = sk->protinfo.ax25->wrt_timer; + ax25_info.t3timer = sk->protinfo.ax25->wrt_timer / AX25_SLOWHZ; + ax25_info.t2timer = sk->protinfo.ax25->ack_timer; + ax25_info.idletimer = sk->protinfo.ax25->idletimer / AX25_SLOWHZ; ax25_info.n2count = sk->protinfo.ax25->n2count; ax25_info.state = sk->protinfo.ax25->state; ax25_info.rcv_q = atomic_read(&sk->rmem_alloc); ax25_info.snd_q = atomic_read(&sk->wmem_alloc); ax25_info.vs = sk->protinfo.ax25->vs; - ax25_info.vr = sk->protinfo.ax25->vr; - ax25_info.va = sk->protinfo.ax25->va; - ax25_info.vs_max = sk->protinfo.ax25->vs; /* reserved */ + ax25_info.vr = sk->protinfo.ax25->vr; + ax25_info.va = sk->protinfo.ax25->va; + ax25_info.vs_max = sk->protinfo.ax25->vs_max; ax25_info.paclen = sk->protinfo.ax25->paclen; ax25_info.window = sk->protinfo.ax25->window; + read_unlock(&sk->protinfo.ax25->timer_lock); /* old structure? */ if (cmd == SIOCAX25GETINFOOLD) { @@ -1670,12 +1296,14 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) warned=1; } - if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated))) + if (copy_to_user((void *) arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated))) return -EFAULT; } else { - if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct))) + if (copy_to_user((void *) arg, &ax25_info, sizeof(struct ax25_info_struct))) return -EINVAL; - } + } + + return 0; } @@ -1709,48 +1337,47 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) return 0; } -static int ax25_get_info(char *buffer, char **start, off_t offset, int length) -{ - ax25_cb *ax25; - int k; - int len = 0; - off_t pos = 0; - off_t begin = 0; +/* ---------------------------------------------------------------------*/ - cli(); +static int ax25_print_list(char *buffer, off_t *begin, off_t offset, int length, off_t *pos, ax25_cb *ax25, char *devname) { + int len = 0; /* * New format: * 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 */ - - for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) { + + for ( ; ax25 != NULL; ax25 = ax25->next) { + int k; + len += sprintf(buffer+len, "%8.8lx %s %s%s ", - (long) ax25, - ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name, - ax2asc(&ax25->source_addr), - ax25->iamdigi? "*":""); - - len += sprintf(buffer+len, "%s", ax2asc(&ax25->dest_addr)); - - for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { + (long) ax25, + devname, + ax2asc(&ax25->addr.src), + ax25->iamdigi? "*":""); + + len += sprintf(buffer+len, "%s", ax2asc(&ax25->addr.dest)); + + for (k=0; k < ax25->addr.dcount; k++) { len += sprintf(buffer+len, ",%s%s", - ax2asc(&ax25->digipeat->calls[k]), - ax25->digipeat->repeated[k]? "*":""); + ax2asc(&ax25->addr.digipeater[k]), + ax25->addr.lastrepeat == k ? "*":""); } - - len += sprintf(buffer+len, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d", + + read_lock(&ax25->timer_lock); + len += sprintf(buffer+len, " %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", ax25->state, ax25->vs, ax25->vr, ax25->va, - ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ, - ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ, - ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ, - ax25_display_timer(&ax25->idletimer) / (60 * HZ), - ax25->idle / (60 * HZ), + ax25->wrt_timer , ax25->t1, + ax25->ack_timer , ax25->t2, + ax25->t3 , ax25->t3, + ax25->idletimer / AX25_SLOWHZ, + ax25->idle / AX25_SLOWHZ, ax25->n2count, ax25->n2, - ax25->rtt / HZ, + ax25->rtt / AX25_TICS, ax25->window, ax25->paclen); + read_unlock(&ax25->timer_lock); if (ax25->sk != NULL) { len += sprintf(buffer + len, " %d %d %ld\n", @@ -1761,121 +1388,70 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length) len += sprintf(buffer + len, " * * *\n"); } - pos = begin + len; + *pos = *begin + len; - if (pos < offset) { - len = 0; - begin = pos; + if (*pos < offset) { + len = 0; + *begin = *pos; } - if (pos > offset + length) + if (*pos > offset + length) break; } - sti(); - - *start = buffer + (offset - begin); - len -= (offset - begin); - - if (len > length) len = length; - - return(len); + return len; } -static struct net_proto_family ax25_family_ops = { - family: PF_AX25, - create: ax25_create, -}; -static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = { - family: PF_AX25, +/* ---------------------------------------------------------------------*/ - release: ax25_release, - bind: ax25_bind, - connect: ax25_connect, - socketpair: sock_no_socketpair, - accept: ax25_accept, - getname: ax25_getname, - poll: datagram_poll, - ioctl: ax25_ioctl, - listen: ax25_listen, - shutdown: ax25_shutdown, - setsockopt: ax25_setsockopt, - getsockopt: ax25_getsockopt, - sendmsg: ax25_sendmsg, - recvmsg: ax25_recvmsg, - mmap: sock_no_mmap, -}; +static int ax25_get_info(char *buffer, char **start, off_t offset, int length) +{ + struct net_device *dev; + int len = 0; + off_t begin = 0; + off_t pos = begin; + int i; -#include -SOCKOPS_WRAP(ax25_proto, PF_AX25); + read_lock(&ax25_dev_lock); -/* - * Called by socket.c on kernel start up - */ -static struct packet_type ax25_packet_type = { - type: __constant_htons(ETH_P_AX25), - func: ax25_kiss_rcv, -}; + len += ax25_print_list(buffer + len, &begin, offset, length, &pos, ax25_list, "*"); -static struct notifier_block ax25_dev_notifier = { - notifier_call: ax25_device_event, -}; + for (i = 0; i < AX25_MAX_DEVICES; i++) { + dev = ax25_devices[i]; + if (!dev || !(dev->flags & IFF_UP)) + continue; -EXPORT_SYMBOL(ax25_encapsulate); -EXPORT_SYMBOL(ax25_rebuild_header); -EXPORT_SYMBOL(ax25_findbyuid); -EXPORT_SYMBOL(ax25_find_cb); -EXPORT_SYMBOL(ax25_linkfail_register); -EXPORT_SYMBOL(ax25_linkfail_release); -EXPORT_SYMBOL(ax25_listen_register); -EXPORT_SYMBOL(ax25_listen_release); -EXPORT_SYMBOL(ax25_protocol_register); -EXPORT_SYMBOL(ax25_protocol_release); -EXPORT_SYMBOL(ax25_send_frame); -EXPORT_SYMBOL(ax25_uid_policy); -EXPORT_SYMBOL(ax25cmp); -EXPORT_SYMBOL(ax2asc); -EXPORT_SYMBOL(asc2ax); -EXPORT_SYMBOL(null_ax25_address); -EXPORT_SYMBOL(ax25_display_timer); + len += ax25_print_list(buffer + len, &begin, offset, length, &pos, ax25_dev_list(dev), dev->name); + } -static const char banner[] __initdata = KERN_INFO "NET4: G4KLX/GW4PTS AX.25 for Linux. Version 0.37 for Linux NET4.0\n"; + read_unlock(&ax25_dev_lock); -static int __init ax25_init(void) -{ - sock_register(&ax25_family_ops); - dev_add_pack(&ax25_packet_type); - register_netdevice_notifier(&ax25_dev_notifier); - ax25_register_sysctl(); + *start = buffer + (offset - begin); + len -= (offset - begin); - proc_net_create("ax25_route", 0, ax25_rt_get_info); - proc_net_create("ax25", 0, ax25_get_info); - proc_net_create("ax25_calls", 0, ax25_uid_get_info); + if (len > length) len = length; - printk(banner); - return 0; + return len; } -module_init(ax25_init); - -MODULE_AUTHOR("Jonathan Naylor G4KLX "); -MODULE_DESCRIPTION("The amateur radio AX.25 link layer protocol"); +/* ---------------------------------------------------------------------*/ -static void __exit ax25_exit(void) +static int ax25_gifconf(struct net_device *dev, char *buf, int len) { - proc_net_remove("ax25_route"); - proc_net_remove("ax25"); - proc_net_remove("ax25_calls"); - ax25_rt_free(); - ax25_uid_free(); - ax25_dev_free(); + struct ifreq ifr; + int done=0; - ax25_unregister_sysctl(); - unregister_netdevice_notifier(&ax25_dev_notifier); - - dev_remove_pack(&ax25_packet_type); - - sock_unregister(PF_AX25); + if (!buf) { + done += sizeof(ifr); + return done; + } + if (len < (int) sizeof(ifr)) return done; + memset(&ifr, 0, sizeof(struct ifreq)); + strcpy(ifr.ifr_name, dev->name); + (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = AF_AX25; + if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) return -EFAULT; + done += sizeof(struct ifreq); + return done; } -module_exit(ax25_exit); + -- cgit v1.2.3