11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 31da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 41da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 51da177e4SLinus Torvalds * (at your option) any later version. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds #include <linux/errno.h> 101da177e4SLinus Torvalds #include <linux/types.h> 111da177e4SLinus Torvalds #include <linux/socket.h> 121da177e4SLinus Torvalds #include <linux/in.h> 131da177e4SLinus Torvalds #include <linux/kernel.h> 1470868eacSRalf Baechle #include <linux/module.h> 151da177e4SLinus Torvalds #include <linux/sched.h> 161da177e4SLinus Torvalds #include <linux/spinlock.h> 171da177e4SLinus Torvalds #include <linux/timer.h> 181da177e4SLinus Torvalds #include <linux/string.h> 191da177e4SLinus Torvalds #include <linux/sockios.h> 201da177e4SLinus Torvalds #include <linux/net.h> 211da177e4SLinus Torvalds #include <net/ax25.h> 221da177e4SLinus Torvalds #include <linux/inet.h> 231da177e4SLinus Torvalds #include <linux/netdevice.h> 241da177e4SLinus Torvalds #include <linux/skbuff.h> 251da177e4SLinus Torvalds #include <net/sock.h> 261da177e4SLinus Torvalds #include <asm/uaccess.h> 271da177e4SLinus Torvalds #include <asm/system.h> 281da177e4SLinus Torvalds #include <linux/fcntl.h> 291da177e4SLinus Torvalds #include <linux/mm.h> 301da177e4SLinus Torvalds #include <linux/interrupt.h> 311da177e4SLinus Torvalds 328d5cf596SRalf Baechle static struct ax25_protocol *protocol_list; 331da177e4SLinus Torvalds static DEFINE_RWLOCK(protocol_list_lock); 341da177e4SLinus Torvalds 35*a4282717SRalf Baechle static HLIST_HEAD(ax25_linkfail_list); 361da177e4SLinus Torvalds static DEFINE_SPINLOCK(linkfail_lock); 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds static struct listen_struct { 391da177e4SLinus Torvalds struct listen_struct *next; 401da177e4SLinus Torvalds ax25_address callsign; 411da177e4SLinus Torvalds struct net_device *dev; 421da177e4SLinus Torvalds } *listen_list = NULL; 431da177e4SLinus Torvalds static DEFINE_SPINLOCK(listen_lock); 441da177e4SLinus Torvalds 458d5cf596SRalf Baechle /* 468d5cf596SRalf Baechle * Do not register the internal protocols AX25_P_TEXT, AX25_P_SEGMENT, 478d5cf596SRalf Baechle * AX25_P_IP or AX25_P_ARP ... 488d5cf596SRalf Baechle */ 498d5cf596SRalf Baechle void ax25_register_pid(struct ax25_protocol *ap) 501da177e4SLinus Torvalds { 5195ff9f4dSRalf Baechle write_lock_bh(&protocol_list_lock); 528d5cf596SRalf Baechle ap->next = protocol_list; 538d5cf596SRalf Baechle protocol_list = ap; 5495ff9f4dSRalf Baechle write_unlock_bh(&protocol_list_lock); 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds 578d5cf596SRalf Baechle EXPORT_SYMBOL_GPL(ax25_register_pid); 5870868eacSRalf Baechle 591da177e4SLinus Torvalds void ax25_protocol_release(unsigned int pid) 601da177e4SLinus Torvalds { 618d5cf596SRalf Baechle struct ax25_protocol *s, *protocol; 621da177e4SLinus Torvalds 6395ff9f4dSRalf Baechle write_lock_bh(&protocol_list_lock); 641da177e4SLinus Torvalds protocol = protocol_list; 651da177e4SLinus Torvalds if (protocol == NULL) { 6695ff9f4dSRalf Baechle write_unlock_bh(&protocol_list_lock); 671da177e4SLinus Torvalds return; 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds if (protocol->pid == pid) { 711da177e4SLinus Torvalds protocol_list = protocol->next; 7295ff9f4dSRalf Baechle write_unlock_bh(&protocol_list_lock); 731da177e4SLinus Torvalds kfree(protocol); 741da177e4SLinus Torvalds return; 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds while (protocol != NULL && protocol->next != NULL) { 781da177e4SLinus Torvalds if (protocol->next->pid == pid) { 791da177e4SLinus Torvalds s = protocol->next; 801da177e4SLinus Torvalds protocol->next = protocol->next->next; 8195ff9f4dSRalf Baechle write_unlock_bh(&protocol_list_lock); 821da177e4SLinus Torvalds kfree(s); 831da177e4SLinus Torvalds return; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds protocol = protocol->next; 871da177e4SLinus Torvalds } 8895ff9f4dSRalf Baechle write_unlock_bh(&protocol_list_lock); 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 9170868eacSRalf Baechle EXPORT_SYMBOL(ax25_protocol_release); 9270868eacSRalf Baechle 93*a4282717SRalf Baechle void ax25_linkfail_register(struct ax25_linkfail *lf) 941da177e4SLinus Torvalds { 951da177e4SLinus Torvalds spin_lock_bh(&linkfail_lock); 96*a4282717SRalf Baechle hlist_add_head(&lf->lf_node, &ax25_linkfail_list); 971da177e4SLinus Torvalds spin_unlock_bh(&linkfail_lock); 981da177e4SLinus Torvalds } 991da177e4SLinus Torvalds 10070868eacSRalf Baechle EXPORT_SYMBOL(ax25_linkfail_register); 10170868eacSRalf Baechle 102*a4282717SRalf Baechle void ax25_linkfail_release(struct ax25_linkfail *lf) 1031da177e4SLinus Torvalds { 1041da177e4SLinus Torvalds spin_lock_bh(&linkfail_lock); 105*a4282717SRalf Baechle hlist_del_init(&lf->lf_node); 1061da177e4SLinus Torvalds spin_unlock_bh(&linkfail_lock); 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 10970868eacSRalf Baechle EXPORT_SYMBOL(ax25_linkfail_release); 11070868eacSRalf Baechle 1111da177e4SLinus Torvalds int ax25_listen_register(ax25_address *callsign, struct net_device *dev) 1121da177e4SLinus Torvalds { 1131da177e4SLinus Torvalds struct listen_struct *listen; 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds if (ax25_listen_mine(callsign, dev)) 1161da177e4SLinus Torvalds return 0; 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds if ((listen = kmalloc(sizeof(*listen), GFP_ATOMIC)) == NULL) 11981dcd169SRalf Baechle return -ENOMEM; 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds listen->callsign = *callsign; 1221da177e4SLinus Torvalds listen->dev = dev; 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds spin_lock_bh(&listen_lock); 1251da177e4SLinus Torvalds listen->next = listen_list; 1261da177e4SLinus Torvalds listen_list = listen; 1271da177e4SLinus Torvalds spin_unlock_bh(&listen_lock); 1281da177e4SLinus Torvalds 12981dcd169SRalf Baechle return 0; 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds 13270868eacSRalf Baechle EXPORT_SYMBOL(ax25_listen_register); 13370868eacSRalf Baechle 1341da177e4SLinus Torvalds void ax25_listen_release(ax25_address *callsign, struct net_device *dev) 1351da177e4SLinus Torvalds { 1361da177e4SLinus Torvalds struct listen_struct *s, *listen; 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds spin_lock_bh(&listen_lock); 1391da177e4SLinus Torvalds listen = listen_list; 1401da177e4SLinus Torvalds if (listen == NULL) { 1411da177e4SLinus Torvalds spin_unlock_bh(&listen_lock); 1421da177e4SLinus Torvalds return; 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) { 1461da177e4SLinus Torvalds listen_list = listen->next; 1471da177e4SLinus Torvalds spin_unlock_bh(&listen_lock); 1481da177e4SLinus Torvalds kfree(listen); 1491da177e4SLinus Torvalds return; 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds while (listen != NULL && listen->next != NULL) { 1531da177e4SLinus Torvalds if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) { 1541da177e4SLinus Torvalds s = listen->next; 1551da177e4SLinus Torvalds listen->next = listen->next->next; 1561da177e4SLinus Torvalds spin_unlock_bh(&listen_lock); 1571da177e4SLinus Torvalds kfree(s); 1581da177e4SLinus Torvalds return; 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds listen = listen->next; 1621da177e4SLinus Torvalds } 1631da177e4SLinus Torvalds spin_unlock_bh(&listen_lock); 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds 16670868eacSRalf Baechle EXPORT_SYMBOL(ax25_listen_release); 16770868eacSRalf Baechle 1681da177e4SLinus Torvalds int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *) 1691da177e4SLinus Torvalds { 1701da177e4SLinus Torvalds int (*res)(struct sk_buff *, ax25_cb *) = NULL; 1718d5cf596SRalf Baechle struct ax25_protocol *protocol; 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds read_lock(&protocol_list_lock); 1741da177e4SLinus Torvalds for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) 1751da177e4SLinus Torvalds if (protocol->pid == pid) { 1761da177e4SLinus Torvalds res = protocol->func; 1771da177e4SLinus Torvalds break; 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds read_unlock(&protocol_list_lock); 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds return res; 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds int ax25_listen_mine(ax25_address *callsign, struct net_device *dev) 1851da177e4SLinus Torvalds { 1861da177e4SLinus Torvalds struct listen_struct *listen; 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds spin_lock_bh(&listen_lock); 1891da177e4SLinus Torvalds for (listen = listen_list; listen != NULL; listen = listen->next) 19081dcd169SRalf Baechle if (ax25cmp(&listen->callsign, callsign) == 0 && 19181dcd169SRalf Baechle (listen->dev == dev || listen->dev == NULL)) { 1921da177e4SLinus Torvalds spin_unlock_bh(&listen_lock); 1931da177e4SLinus Torvalds return 1; 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds spin_unlock_bh(&listen_lock); 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds return 0; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds void ax25_link_failed(ax25_cb *ax25, int reason) 2011da177e4SLinus Torvalds { 202*a4282717SRalf Baechle struct ax25_linkfail *lf; 203*a4282717SRalf Baechle struct hlist_node *node; 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds spin_lock_bh(&linkfail_lock); 206*a4282717SRalf Baechle hlist_for_each_entry(lf, node, &ax25_linkfail_list, lf_node) 207*a4282717SRalf Baechle lf->func(ax25, reason); 2081da177e4SLinus Torvalds spin_unlock_bh(&linkfail_lock); 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds int ax25_protocol_is_registered(unsigned int pid) 2121da177e4SLinus Torvalds { 2138d5cf596SRalf Baechle struct ax25_protocol *protocol; 2141da177e4SLinus Torvalds int res = 0; 2151da177e4SLinus Torvalds 21695ff9f4dSRalf Baechle read_lock_bh(&protocol_list_lock); 2171da177e4SLinus Torvalds for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) 2181da177e4SLinus Torvalds if (protocol->pid == pid) { 2191da177e4SLinus Torvalds res = 1; 2201da177e4SLinus Torvalds break; 2211da177e4SLinus Torvalds } 22295ff9f4dSRalf Baechle read_unlock_bh(&protocol_list_lock); 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds return res; 2251da177e4SLinus Torvalds } 226