📄 af_ax25.c
字号:
/* * AX.25 release 038 * * This code REQUIRES 2.1.15 or higher/ NET3.038 * * 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. * * 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. * Jeroen(PE1RXQ) Use sock_orphan() on release. */#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/sockios.h>#include <linux/net.h>#include <net/ax25.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/skbuff.h>#include <net/sock.h>#include <asm/uaccess.h>#include <asm/system.h>#include <linux/fcntl.h>#include <linux/termios.h> /* For TIOCINQ/OUTQ */#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/notifier.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/netfilter.h>#include <linux/sysctl.h>#include <linux/init.h>#include <net/ip.h>#include <net/arp.h>ax25_cb *volatile ax25_list;static struct proto_ops ax25_proto_ops;/* * Free an allocated ax25 control block. This is done to centralise * the MOD count code. */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);}/* * Socket removal during an interrupt is now safe. */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. */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; for (s = ax25_list; s != NULL; s = s->next) { if (s->ax25_dev == ax25_dev) { s->ax25_dev = NULL; ax25_disconnect(s, ENETUNREACH); } }}/* * Handle device status changes. */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;}/* * Add a socket to the bound sockets list. */void ax25_insert_socket(ax25_cb *ax25){ unsigned long flags; save_flags(flags); cli(); ax25->next = ax25_list; ax25_list = ax25; restore_flags(flags);}/* * Find a socket that wants to accept the SABM we have just * received. */struct sock *ax25_find_listener(ax25_address *addr, int digi, struct net_device *dev, int type){ unsigned long flags; ax25_cb *s; save_flags(flags); cli(); 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; } } } restore_flags(flags); return NULL;}/* * Find an AX.25 socket given both ends. */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); return NULL;}/* * Find an AX.25 control block given both ends. It will only pick up * floating AX.25 control blocks or non Raw socket bound control blocks. */ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi *digi, struct net_device *dev){ ax25_cb *s; unsigned long flags; save_flags(flags); cli(); 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; } } 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){ unsigned long flags; ax25_cb *s; save_flags(flags); cli(); 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; } } restore_flags(flags); return NULL;}void ax25_send_to_raw(struct sock *sk, struct sk_buff *skb, int proto){ struct sk_buff *copy; while (sk != NULL) { if (sk->type == SOCK_RAW && sk->protocol == proto && atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) { if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL) return; if (sock_queue_rcv_skb(sk, copy) != 0) kfree_skb(copy); } sk = sk->next; }}/* * Deferred destroy. */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 */{ struct sk_buff *skb; unsigned long flags; save_flags(flags); cli(); ax25_stop_heartbeat(ax25); ax25_stop_t1timer(ax25); ax25_stop_t2timer(ax25); ax25_stop_t3timer(ax25); ax25_stop_idletimer(ax25); 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; } kfree_skb(skb); } } 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); } restore_flags(flags);}/* * dl1bke 960311: set parameters for existing AX.25 connections, * includes a KILL command to abort any connection. * VERY useful for debugging ;-) */static int ax25_ctl_ioctl(const unsigned int cmd, void *arg){ 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -