11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Implements an IPX socket layer. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This code is derived from work by 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ross Biro : Writing the original IP stack 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fred Van Kempen : Tidying up the TCP/IP 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Many thanks go to Keith Baker, Institute For Industrial Information 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Technology Ltd, Swansea University for allowing me to work on this 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in my own time even though it was in some ways related to commercial 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * work I am currently employed to do there. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All the material in this file is subject to the Gnu license version 2. 14981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki * Neither Alan Cox nor the Swansea University Computer Society admit 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * liability nor provide warranty for any of this software. This material 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is provided as is and at no charge. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Portions Copyright (c) 2000-2003 Conectiva, Inc. <acme@conectiva.com.br> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Neither Arnaldo Carvalho de Melo nor Conectiva, Inc. admit liability nor 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * provide warranty for any of this software. This material is provided 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "AS-IS" and at no charge. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Portions Copyright (c) 1995 Caldera, Inc. <greg@caldera.com> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Neither Greg Page nor Caldera, Inc. admit liability nor provide 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * warranty for any of this software. This material is provided 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "AS-IS" and at no charge. 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See net/ipx/ChangeLog. 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 314fc268d24ceb9f4150777c1b5b2b8e6214e56b2bRandy Dunlap#include <linux/capability.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_ether.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ipx.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/net.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/uio.h> 435a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/socket.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sockios.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/termios.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/ipx.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/p8022.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/psnap.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sock.h> 557780d8ae4ae1960ef7c0570de0a1ecd7b60c8152Rashika Kheria#include <net/datalink.h> 56c752f0739f09b803aed191c4765a3b6650a08653Arnaldo Carvalho de Melo#include <net/tcp_states.h> 57535d3ae9c808e6a5248f0524dbc7a9e997cf3288Rashika Kheria#include <net/net_namespace.h> 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Configuration Variables */ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char ipxcfg_max_hops = 16; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char ipxcfg_auto_select_primary; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char ipxcfg_auto_create_interfaces; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sysctl_ipx_pprop_broadcasting = 1; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Global Variables */ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct datalink_proto *p8022_datalink; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct datalink_proto *pEII_datalink; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct datalink_proto *p8023_datalink; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct datalink_proto *pSNAP_datalink; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7390ddc4f0470427df306f308ad03db6b6b21644b8Eric Dumazetstatic const struct proto_ops ipx_dgram_ops; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsLIST_HEAD(ipx_interfaces); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsDEFINE_SPINLOCK(ipx_interfaces_lock); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ipx_interface *ipx_primary_net; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ipx_interface *ipx_internal_net; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ipx_interface *ipx_interfaces_head(void) 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *rc = NULL; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!list_empty(&ipx_interfaces)) 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = list_entry(ipx_interfaces.next, 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface, node); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ipxcfg_set_auto_select(char val) 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxcfg_auto_select_primary = val; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (val && !ipx_primary_net) 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_primary_net = ipx_interfaces_head(); 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipxcfg_get_config_data(struct ipx_config_data __user *arg) 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_config_data vals; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vals.ipxcfg_auto_create_interfaces = ipxcfg_auto_create_interfaces; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vals.ipxcfg_auto_select_primary = ipxcfg_auto_select_primary; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return copy_to_user(arg, &vals, sizeof(vals)) ? -EFAULT : 0; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: Sockets may not be removed _during_ an interrupt or inet_bh 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handler using this technique. They can be added although we do not 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * use this facility. 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ipx_remove_socket(struct sock *sk) 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Determine interface with which socket is associated */ 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *intrfc = ipx_sk(sk)->intrfc; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!intrfc) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_hold(intrfc); 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&intrfc->if_sklist_lock); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk_del_node_init(sk); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&intrfc->if_sklist_lock); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(intrfc); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ipx_destroy_socket(struct sock *sk) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_remove_socket(sk); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_purge(&sk->sk_receive_queue); 135c2b42336f4a733020360157ba629d37f1410923aPavel Emelyanov sk_refcnt_debug_dec(sk); 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 138981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki/* 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The following code is used to support IPX Interfaces (IPXITF). An 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IPX interface is defined by a physical device and a frame type. 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ipxitf_clear_primary_net has to be called with ipx_interfaces_lock held */ 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ipxitf_clear_primary_net(void) 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_primary_net = NULL; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipxcfg_auto_select_primary) 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_primary_net = ipx_interfaces_head(); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev, 1534833ed094097323f5f219820f6ebdc8dd66f501fAl Viro __be16 datalink) 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *i; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(i, &ipx_interfaces, node) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i->if_dev == dev && i->if_dlink_type == datalink) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = NULL; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ipx_interface *ipxitf_find_using_phys(struct net_device *dev, 1664833ed094097323f5f219820f6ebdc8dd66f501fAl Viro __be16 datalink) 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *i; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&ipx_interfaces_lock); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = __ipxitf_find_using_phys(dev, datalink); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_hold(i); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&ipx_interfaces_lock); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1784833ed094097323f5f219820f6ebdc8dd66f501fAl Virostruct ipx_interface *ipxitf_find_using_net(__be32 net) 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *i; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&ipx_interfaces_lock); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (net) { 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(i, &ipx_interfaces, node) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i->if_netnum == net) 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto hold; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = NULL; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto unlock; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = ipx_primary_net; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i) 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshold: 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_hold(i); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunlock: 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&ipx_interfaces_lock); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Sockets are bound to a particular IPX interface. */ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ipxitf_insert_socket(struct ipx_interface *intrfc, struct sock *sk) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_hold(intrfc); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&intrfc->if_sklist_lock); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_sk(sk)->intrfc = intrfc; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk_add_node(sk, &intrfc->if_sklist); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&intrfc->if_sklist_lock); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(intrfc); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* caller must hold intrfc->if_sklist_lock */ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sock *__ipxitf_find_socket(struct ipx_interface *intrfc, 2134833ed094097323f5f219820f6ebdc8dd66f501fAl Viro __be16 port) 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *s; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 217b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin sk_for_each(s, &intrfc->if_sklist) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipx_sk(s)->port == port) 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto found; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s = NULL; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfound: 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return s; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* caller must hold a reference to intrfc */ 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sock *ipxitf_find_socket(struct ipx_interface *intrfc, 2274833ed094097323f5f219820f6ebdc8dd66f501fAl Viro __be16 port) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *s; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&intrfc->if_sklist_lock); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s = __ipxitf_find_socket(intrfc, port); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s) 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock_hold(s); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&intrfc->if_sklist_lock); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return s; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IPX_INTERN 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc, 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *ipx_node, 2434833ed094097323f5f219820f6ebdc8dd66f501fAl Viro __be16 port) 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *s; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_hold(intrfc); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&intrfc->if_sklist_lock); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 250b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin sk_for_each(s, &intrfc->if_sklist) { 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_sock *ipxs = ipx_sk(s); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipxs->port == port && 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !memcmp(ipx_node, ipxs->node, IPX_NODE_LEN)) 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto found; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s = NULL; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfound: 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&intrfc->if_sklist_lock); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(intrfc); 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return s; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __ipxitf_down(struct ipx_interface *intrfc) 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *s; 268b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin struct hlist_node *t; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Delete all routes associated with this interface */ 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxrtr_del_routes(intrfc); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&intrfc->if_sklist_lock); 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* error sockets */ 275b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin sk_for_each_safe(s, t, &intrfc->if_sklist) { 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_sock *ipxs = ipx_sk(s); 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->sk_err = ENOLINK; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->sk_error_report(s); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxs->intrfc = NULL; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxs->port = 0; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock_set_flag(s, SOCK_ZAPPED); /* Indicates it is no longer bound */ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk_del_node_init(s); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_HLIST_HEAD(&intrfc->if_sklist); 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&intrfc->if_sklist_lock); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* remove this interface from list */ 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&intrfc->node); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* remove this interface from *special* networks */ 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intrfc == ipx_primary_net) 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_clear_primary_net(); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intrfc == ipx_internal_net) 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_internal_net = NULL; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intrfc->if_dev) 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(intrfc->if_dev); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(intrfc); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid ipxitf_down(struct ipx_interface *intrfc) 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&ipx_interfaces_lock); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ipxitf_down(intrfc); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&ipx_interfaces_lock); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __inline__ void __ipxitf_put(struct ipx_interface *intrfc) 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atomic_dec_and_test(&intrfc->refcnt)) 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ipxitf_down(intrfc); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipxitf_device_event(struct notifier_block *notifier, 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long event, void *ptr) 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 318351638e7deeed2ec8ce451b53d33921b3da68f83Jiri Pirko struct net_device *dev = netdev_notifier_info_to_dev(ptr); 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *i, *tmp; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321721499e8931c5732202481ae24f2dfbf9910f129YOSHIFUJI Hideaki if (!net_eq(dev_net(dev), &init_net)) 322e9dc86534051b78e41e5b746cccc291b57a3a311Eric W. Biederman return NOTIFY_DONE; 323e9dc86534051b78e41e5b746cccc291b57a3a311Eric W. Biederman 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (event != NETDEV_DOWN && event != NETDEV_UP) 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&ipx_interfaces_lock); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry_safe(i, tmp, &ipx_interfaces, node) 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i->if_dev == dev) { 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (event == NETDEV_UP) 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_hold(i); 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ipxitf_put(i); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&ipx_interfaces_lock); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NOTIFY_DONE; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __exit void ipxitf_cleanup(void) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *i, *tmp; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&ipx_interfaces_lock); 346981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki list_for_each_entry_safe(i, tmp, &ipx_interfaces, node) 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ipxitf_put(i); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&ipx_interfaces_lock); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ipxitf_def_skb_handler(struct sock *sock, struct sk_buff *skb) 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sock_queue_rcv_skb(sock, skb) < 0) 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On input skb->sk is NULL. Nobody is charged for the memory. 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* caller must hold a reference to intrfc */ 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IPX_INTERN 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipxitf_demux_socket(struct ipx_interface *intrfc, 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb, int copy) 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipxhdr *ipx = ipx_hdr(skb); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int is_broadcast = !memcmp(ipx->ipx_dest.node, ipx_broadcast_node, 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_NODE_LEN); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *s; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&intrfc->if_sklist_lock); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 375b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin sk_for_each(s, &intrfc->if_sklist) { 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_sock *ipxs = ipx_sk(s); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipxs->port == ipx->ipx_dest.sock && 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (is_broadcast || !memcmp(ipx->ipx_dest.node, 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxs->node, IPX_NODE_LEN))) { 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We found a socket to which to send */ 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb1; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy) { 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb1 = skb_clone(skb, GFP_ATOMIC); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOMEM; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb1) 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb1 = skb; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copy = 1; /* skb may only be used once */ 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_def_skb_handler(s, skb1); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* On an external interface, one socket can listen */ 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intrfc != ipx_internal_net) 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* skb was solely for us, and we did not make a copy, so free it. */ 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!copy) 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&intrfc->if_sklist_lock); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sock *ncp_connection_hack(struct ipx_interface *intrfc, 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipxhdr *ipx) 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The packet's target is a NCP connection handler. We want to hand it 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the correct socket directly within the kernel, so that the 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mars_nwe packet distribution process does not have to do it. Here we 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * only care about NCP and BURST packets. 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You might call this a hack, but believe me, you do not want a 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complete NCP layer in the kernel, and this is VERY fast as well. */ 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk = NULL; 422981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki int connection = 0; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *ncphdr = (u8 *)(ipx + 1); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 425981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki if (*ncphdr == 0x22 && *(ncphdr + 1) == 0x22) /* NCP request */ 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds connection = (((int) *(ncphdr + 5)) << 8) | (int) *(ncphdr + 3); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (*ncphdr == 0x77 && *(ncphdr + 1) == 0x77) /* BURST packet */ 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds connection = (((int) *(ncphdr + 9)) << 8) | (int) *(ncphdr + 8); 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (connection) { 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now we have to look for a special NCP connection handling 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * socket. Only these sockets have ipx_ncp_conn != 0, set by 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SIOCIPXNCPCONN. */ 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&intrfc->if_sklist_lock); 435b67bfe0d42cac56c512dd5da4b1b347a23f4b70aSasha Levin sk_for_each(sk, &intrfc->if_sklist) 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipx_sk(sk)->ipx_ncp_conn == connection) { 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock_hold(sk); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto found; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk = NULL; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found: 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&intrfc->if_sklist_lock); 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sk; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipxitf_demux_socket(struct ipx_interface *intrfc, 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb, int copy) 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipxhdr *ipx = ipx_hdr(skb); 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sock1 = NULL, *sock2 = NULL; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb1 = NULL, *skb2 = NULL; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intrfc == ipx_primary_net && ntohs(ipx->ipx_dest.sock) == 0x451) 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock1 = ncp_connection_hack(intrfc, ipx); 457981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki if (!sock1) 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No special socket found, forward the packet the normal way */ 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock1 = ipxitf_find_socket(intrfc, ipx->ipx_dest.sock); 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to check if there is a primary net and if 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this is addressed to one of the *SPECIAL* sockets because 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * these need to be propagated to the primary net. 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The *SPECIAL* socket list contains: 0x452(SAP), 0x453(RIP) and 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0x456(Diagnostic). 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipx_primary_net && intrfc != ipx_primary_net) { 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const int dsock = ntohs(ipx->ipx_dest.sock); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dsock == 0x452 || dsock == 0x453 || dsock == 0x456) 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The appropriate thing to do here is to dup the 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packet and route to the primary net interface via 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ipxitf_send; however, we'll cheat and just demux it 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * here. */ 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock2 = ipxitf_find_socket(ipx_primary_net, 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx->ipx_dest.sock); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If there is nothing to do return. The kfree will cancel any charging. 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sock1 && !sock2) { 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!copy) 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This next segment of code is a little awkward, but it sets it up 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so that the appropriate number of copies of the SKB are made and 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that skb1 and skb2 point to it (them) so that it (they) can be 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * demuxed to sock1 and/or sock2. If we are unable to make enough 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * copies, we do as much as is possible. 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy) 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb1 = skb_clone(skb, GFP_ATOMIC); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb1 = skb; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOMEM; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb1) 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_put; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Do we need 2 SKBs? */ 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sock1 && sock2) 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb2 = skb_clone(skb1, GFP_ATOMIC); 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb2 = skb1; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sock1) 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_def_skb_handler(sock1, skb1); 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb2) 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_put; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sock2) 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_def_skb_handler(sock2, skb2); 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_put: 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sock1) 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock_put(sock1); 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sock2) 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock_put(sock2); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_IPX_INTERN */ 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sk_buff *ipxitf_adjust_skbuff(struct ipx_interface *intrfc, 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb) 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb2; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int in_offset = (unsigned char *)ipx_hdr(skb) - skb->head; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int out_offset = intrfc->if_ipx_offset; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Hopefully, most cases */ 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (in_offset >= out_offset) 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Need new SKB */ 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = skb->len + out_offset; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb2 = alloc_skb(len, GFP_ATOMIC); 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb2) { 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(skb2, out_offset); 5517e28ecc282574a7d72ace365fc9bc86e27ba880fArnaldo Carvalho de Melo skb_reset_network_header(skb2); 552badff6d01a8589a1c828b0bf118903ca38627f4eArnaldo Carvalho de Melo skb_reset_transport_header(skb2); 5537e28ecc282574a7d72ace365fc9bc86e27ba880fArnaldo Carvalho de Melo skb_put(skb2, skb->len); 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(ipx_hdr(skb2), ipx_hdr(skb), skb->len); 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb2->cb, skb->cb, sizeof(skb->cb)); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb2; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* caller must hold a reference to intrfc and the skb has to be unshared */ 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb, char *node) 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipxhdr *ipx = ipx_hdr(skb); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = intrfc->if_dev; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct datalink_proto *dl = intrfc->if_dlink; 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char dest_node[IPX_NODE_LEN]; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int send_to_wire = 1; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int addr_len; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx->ipx_tctrl = IPX_SKB_CB(skb)->ipx_tctrl; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx->ipx_dest.net = IPX_SKB_CB(skb)->ipx_dest_net; 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx->ipx_source.net = IPX_SKB_CB(skb)->ipx_source_net; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* see if we need to include the netnum in the route list */ 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IPX_SKB_CB(skb)->last_hop.index >= 0) { 5774833ed094097323f5f219820f6ebdc8dd66f501fAl Viro __be32 *last_hop = (__be32 *)(((u8 *) skb->data) + 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct ipxhdr) + 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_SKB_CB(skb)->last_hop.index * 5804833ed094097323f5f219820f6ebdc8dd66f501fAl Viro sizeof(__be32)); 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *last_hop = IPX_SKB_CB(skb)->last_hop.netnum; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_SKB_CB(skb)->last_hop.index = -1; 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 584981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki 585981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki /* 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to know how many skbuffs it will take to send out this 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packet to avoid unnecessary copies. 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 589981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki 590981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki if (!dl || !dev || dev->flags & IFF_LOOPBACK) 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_to_wire = 0; /* No non looped */ 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 594981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki * See if this should be demuxed to sockets on this interface 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We want to ensure the original was eaten or that we only use 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * up clones. 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 599981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipx->ipx_dest.net == intrfc->if_netnum) { 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To our own node, loop and free the original. 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The internal net will receive on all node address. 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intrfc == ipx_internal_net || 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !memcmp(intrfc->if_node, node, IPX_NODE_LEN)) { 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't charge sender */ 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_orphan(skb); 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Will charge receiver */ 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ipxitf_demux_socket(intrfc, skb, 0); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Broadcast, loop and possibly keep to send on. */ 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!memcmp(ipx_broadcast_node, node, IPX_NODE_LEN)) { 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!send_to_wire) 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_orphan(skb); 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_demux_socket(intrfc, skb, send_to_wire); 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!send_to_wire) 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the originating net is not equal to our net; this is routed 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We are still charging the sender. Which is right - the driver 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * free will handle this fairly. 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipx->ipx_source.net != intrfc->if_netnum) { 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unshare the buffer before modifying the count in 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * case it's a flood or tcpdump 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = skb_unshare(skb, GFP_ATOMIC); 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb) 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++ipx->ipx_tctrl > ipxcfg_max_hops) 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_to_wire = 0; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!send_to_wire) { 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Determine the appropriate hardware address */ 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr_len = dev->addr_len; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!memcmp(ipx_broadcast_node, node, IPX_NODE_LEN)) 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dest_node, dev->broadcast, addr_len); 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dest_node, &(node[IPX_NODE_LEN-addr_len]), addr_len); 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Make any compensation for differing physical/data link size */ 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = ipxitf_adjust_skbuff(intrfc, skb); 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb) 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set up data link and physical headers */ 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->dev = dev; 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = htons(ETH_P_IPX); 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Send it out */ 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dl->request(dl, skb, dest_node); 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipxitf_add_local_route(struct ipx_interface *intrfc) 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ipxrtr_add_route(intrfc->if_netnum, intrfc, NULL); 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ipxitf_discover_netnum(struct ipx_interface *intrfc, 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb); 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb); 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipxitf_rcv(struct ipx_interface *intrfc, struct sk_buff *skb) 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipxhdr *ipx = ipx_hdr(skb); 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_hold(intrfc); 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* See if we should update our network number */ 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!intrfc->if_netnum) /* net number of intrfc not known yet */ 686981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki ipxitf_discover_netnum(intrfc, skb); 687981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_SKB_CB(skb)->last_hop.index = -1; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipx->ipx_type == IPX_TYPE_PPROP) { 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxitf_pprop(intrfc, skb); 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free_skb; 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* local processing follows */ 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!IPX_SKB_CB(skb)->ipx_dest_net) 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_SKB_CB(skb)->ipx_dest_net = intrfc->if_netnum; 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!IPX_SKB_CB(skb)->ipx_source_net) 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_SKB_CB(skb)->ipx_source_net = intrfc->if_netnum; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* it doesn't make sense to route a pprop packet, there's no meaning 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the ipx_dest_net for such packets */ 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipx->ipx_type != IPX_TYPE_PPROP && 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc->if_netnum != IPX_SKB_CB(skb)->ipx_dest_net) { 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We only route point-to-point packets. */ 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb->pkt_type == PACKET_HOST) { 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = skb_unshare(skb, GFP_ATOMIC); 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb) 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxrtr_route_skb(skb); 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_intrfc; 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free_skb; 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* see if we should keep it */ 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!memcmp(ipx_broadcast_node, ipx->ipx_dest.node, IPX_NODE_LEN) || 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !memcmp(intrfc->if_node, ipx->ipx_dest.node, IPX_NODE_LEN)) { 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxitf_demux_socket(intrfc, skb, 0); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_intrfc; 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we couldn't pawn it off so unload it */ 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_free_skb: 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_intrfc: 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(intrfc); 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ipxitf_discover_netnum(struct ipx_interface *intrfc, 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb) 733981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki{ 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct ipx_cb *cb = IPX_SKB_CB(skb); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* see if this is an intra packet: source_net == dest_net */ 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cb->ipx_source_net == cb->ipx_dest_net && cb->ipx_source_net) { 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *i = 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_find_using_net(cb->ipx_source_net); 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NB: NetWare servers lie about their hop count so we 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dropped the test based on it. This is the best way 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to determine this is a 0 hop count packet. */ 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!i) { 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc->if_netnum = cb->ipx_source_net; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_add_local_route(intrfc); 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "IPX: Network number collision " 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%lx\n %s %s and %s %s\n", 7494833ed094097323f5f219820f6ebdc8dd66f501fAl Viro (unsigned long) ntohl(cb->ipx_source_net), 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_device_name(i), 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_frame_name(i->if_dlink_type), 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_device_name(intrfc), 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_frame_name(intrfc->if_dlink_type)); 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(i); 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ipxitf_pprop - Process packet propagation IPX packet type 0x14, used for 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NetBIOS broadcasts 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @intrfc: IPX interface receiving this packet 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @skb: Received packet 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Checks if packet is valid: if its more than %IPX_MAX_PPROP_HOPS hops or if it 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is smaller than a IPX header + the room for %IPX_MAX_PPROP_HOPS hops we drop 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it, not even processing it locally, if it has exact %IPX_MAX_PPROP_HOPS we 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * don't broadcast it, but process it locally. See chapter 5 of Novell's "IPX 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * RIP and SAP Router Specification", Part Number 107-000029-001. 770981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki * 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it is valid, check if we have pprop broadcasting enabled by the user, 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if not, just return zero for local processing. 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it is enabled check the packet and don't broadcast it if we have already 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * seen this packet. 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Broadcast: send it to the interfaces that aren't on the packet visited nets 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * array, just after the IPX header. 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns -EINVAL for invalid packets, so that the calling function drops 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the packet without local processing. 0 if packet is to be locally processed. 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb) 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipxhdr *ipx = ipx_hdr(skb); 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, rc = -EINVAL; 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *ifcs; 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *c; 7894833ed094097323f5f219820f6ebdc8dd66f501fAl Viro __be32 *l; 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Illegal packet - too many hops or too short */ 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We decide to throw it away: no broadcasting, no local processing. 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NetBIOS unaware implementations route them as normal packets - 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tctrl <= 15, any data payload... */ 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IPX_SKB_CB(skb)->ipx_tctrl > IPX_MAX_PPROP_HOPS || 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ntohs(ipx->ipx_pktsize) < sizeof(struct ipxhdr) + 797981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki IPX_MAX_PPROP_HOPS * sizeof(u32)) 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* are we broadcasting this damn thing? */ 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sysctl_ipx_pprop_broadcasting) 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We do broadcast packet on the IPX_MAX_PPROP_HOPS hop, but we 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * process it locally. All previous hops broadcasted it, and process it 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * locally. */ 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IPX_SKB_CB(skb)->ipx_tctrl == IPX_MAX_PPROP_HOPS) 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 808981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c = ((u8 *) ipx) + sizeof(struct ipxhdr); 8104833ed094097323f5f219820f6ebdc8dd66f501fAl Viro l = (__be32 *) c; 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't broadcast packet if already seen this net */ 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++) 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*l++ == intrfc->if_netnum) 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* < IPX_MAX_PPROP_HOPS hops && input interface not in list. Save the 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * position where we will insert recvd netnum into list, later on, 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in ipxitf_send */ 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_SKB_CB(skb)->last_hop.index = i; 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_SKB_CB(skb)->last_hop.netnum = intrfc->if_netnum; 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* xmit on all other interfaces... */ 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&ipx_interfaces_lock); 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(ifcs, &ipx_interfaces, node) { 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Except unconfigured interfaces */ 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ifcs->if_netnum) 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 828981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* That aren't in the list */ 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ifcs == intrfc) 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 8324833ed094097323f5f219820f6ebdc8dd66f501fAl Viro l = (__be32 *) c; 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* don't consider the last entry in the packet list, 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it is our netnum, and it is not there yet */ 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++) 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ifcs->if_netnum == *l++) 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == IPX_SKB_CB(skb)->ipx_tctrl) { 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *s = skb_copy(skb, GFP_ATOMIC); 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s) { 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_SKB_CB(s)->ipx_dest_net = ifcs->if_netnum; 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxrtr_route_skb(s); 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&ipx_interfaces_lock); 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ipxitf_insert(struct ipx_interface *intrfc) 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&ipx_interfaces_lock); 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&intrfc->node, &ipx_interfaces); 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&ipx_interfaces_lock); 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipxcfg_auto_select_primary && !ipx_primary_net) 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_primary_net = intrfc; 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8624833ed094097323f5f219820f6ebdc8dd66f501fAl Virostatic struct ipx_interface *ipxitf_alloc(struct net_device *dev, __be32 netnum, 8634833ed094097323f5f219820f6ebdc8dd66f501fAl Viro __be16 dlink_type, 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct datalink_proto *dlink, 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char internal, 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ipx_offset) 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *intrfc = kmalloc(sizeof(*intrfc), GFP_ATOMIC); 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intrfc) { 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc->if_dev = dev; 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc->if_netnum = netnum; 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc->if_dlink_type = dlink_type; 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc->if_dlink = dlink; 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc->if_internal = internal; 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc->if_ipx_offset = ipx_offset; 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET; 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_HLIST_HEAD(&intrfc->if_sklist); 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&intrfc->refcnt, 1); 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&intrfc->if_sklist_lock); 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return intrfc; 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipxitf_create_internal(struct ipx_interface_definition *idef) 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *intrfc; 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -EEXIST; 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Only one primary network allowed */ 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipx_primary_net) 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Must have a valid network number */ 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EADDRNOTAVAIL; 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!idef->ipx_network) 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc = ipxitf_find_using_net(idef->ipx_network); 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EADDRINUSE; 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intrfc) { 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(intrfc); 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc = ipxitf_alloc(NULL, idef->ipx_network, 0, NULL, 1, 0); 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EAGAIN; 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!intrfc) 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy((char *)&(intrfc->if_node), idef->ipx_node, IPX_NODE_LEN); 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_internal_net = ipx_primary_net = intrfc; 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_hold(intrfc); 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_insert(intrfc); 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxitf_add_local_route(intrfc); 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(intrfc); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9204ac396c0467993853d3d58c0975151515700c07bAlexey Dobriyanstatic __be16 ipx_map_frame_type(unsigned char type) 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9224ac396c0467993853d3d58c0975151515700c07bAlexey Dobriyan __be16 rc = 0; 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (type) { 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPX_FRAME_ETHERII: rc = htons(ETH_P_IPX); break; 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPX_FRAME_8022: rc = htons(ETH_P_802_2); break; 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPX_FRAME_SNAP: rc = htons(ETH_P_SNAP); break; 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPX_FRAME_8023: rc = htons(ETH_P_802_3); break; 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipxitf_create(struct ipx_interface_definition *idef) 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 9374833ed094097323f5f219820f6ebdc8dd66f501fAl Viro __be16 dlink_type = 0; 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct datalink_proto *datalink = NULL; 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *intrfc; 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idef->ipx_special == IPX_INTERNAL) { 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxitf_create_internal(idef); 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EEXIST; 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idef->ipx_special == IPX_PRIMARY && ipx_primary_net) 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc = ipxitf_find_using_net(idef->ipx_network); 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EADDRINUSE; 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idef->ipx_network && intrfc) { 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(intrfc); 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intrfc) 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(intrfc); 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman dev = dev_get_by_name(&init_net, idef->ipx_device); 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENODEV; 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (idef->ipx_dlink_type) { 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPX_FRAME_8022: 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dlink_type = htons(ETH_P_802_2); 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds datalink = p8022_datalink; 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPX_FRAME_ETHERII: 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->type != ARPHRD_IEEE802) { 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dlink_type = htons(ETH_P_IPX); 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds datalink = pEII_datalink; 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 976211ed865108e24697b44bee5daac502ee6bdd4a4Paul Gortmaker } 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* fall through */ 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPX_FRAME_SNAP: 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dlink_type = htons(ETH_P_SNAP); 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds datalink = pSNAP_datalink; 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPX_FRAME_8023: 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dlink_type = htons(ETH_P_802_3); 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds datalink = p8023_datalink; 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPX_FRAME_NONE: 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EPROTONOSUPPORT; 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_dev; 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENETDOWN; 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(dev->flags & IFF_UP)) 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_dev; 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check addresses are suitable */ 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->addr_len > IPX_NODE_LEN) 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_dev; 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc = ipxitf_find_using_phys(dev, dlink_type); 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!intrfc) { 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Ok now create */ 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc = ipxitf_alloc(dev, idef->ipx_network, dlink_type, 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds datalink, 0, dev->hard_header_len + 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds datalink->header_length); 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EAGAIN; 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!intrfc) 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_dev; 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Setup primary if necessary */ 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idef->ipx_special == IPX_PRIMARY) 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_primary_net = intrfc; 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!memcmp(idef->ipx_node, "\000\000\000\000\000\000", 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_NODE_LEN)) { 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(intrfc->if_node, 0, IPX_NODE_LEN); 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(intrfc->if_node + IPX_NODE_LEN - dev->addr_len, 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->dev_addr, dev->addr_len); 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(intrfc->if_node, idef->ipx_node, IPX_NODE_LEN); 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_hold(intrfc); 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_insert(intrfc); 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If the network number is known, add a route */ 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!intrfc->if_netnum) 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_intrfc; 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxitf_add_local_route(intrfc); 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_intrfc: 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(intrfc); 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_dev: 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(dev); 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipxitf_delete(struct ipx_interface_definition *idef) 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = NULL; 10434833ed094097323f5f219820f6ebdc8dd66f501fAl Viro __be16 dlink_type = 0; 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *intrfc; 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&ipx_interfaces_lock); 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idef->ipx_special == IPX_INTERNAL) { 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipx_internal_net) { 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ipxitf_put(ipx_internal_net); 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOENT; 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dlink_type = ipx_map_frame_type(idef->ipx_dlink_type); 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EPROTONOSUPPORT; 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dlink_type) 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1062881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman dev = __dev_get_by_name(&init_net, idef->ipx_device); 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENODEV; 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc = __ipxitf_find_using_phys(dev, dlink_type); 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!intrfc) 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ipxitf_put(intrfc); 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&ipx_interfaces_lock); 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ipx_interface *ipxitf_auto_create(struct net_device *dev, 10804833ed094097323f5f219820f6ebdc8dd66f501fAl Viro __be16 dlink_type) 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *intrfc = NULL; 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct datalink_proto *datalink; 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check addresses are suitable */ 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->addr_len > IPX_NODE_LEN) 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10924833ed094097323f5f219820f6ebdc8dd66f501fAl Viro switch (ntohs(dlink_type)) { 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ETH_P_IPX: datalink = pEII_datalink; break; 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ETH_P_802_2: datalink = p8022_datalink; break; 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ETH_P_SNAP: datalink = pSNAP_datalink; break; 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ETH_P_802_3: datalink = p8023_datalink; break; 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: goto out; 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc = ipxitf_alloc(dev, 0, dlink_type, datalink, 0, 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->hard_header_len + datalink->header_length); 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intrfc) { 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(intrfc->if_node, 0, IPX_NODE_LEN); 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy((char *)&(intrfc->if_node[IPX_NODE_LEN-dev->addr_len]), 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->dev_addr, dev->addr_len); 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&intrfc->if_sklist_lock); 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_set(&intrfc->refcnt, 1); 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_insert(intrfc); 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_hold(dev); 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return intrfc; 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipxitf_ioctl(unsigned int cmd, void __user *arg) 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -EINVAL; 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ifreq ifr; 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int val; 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCSIFADDR: { 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr_ipx *sipx; 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface_definition f; 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EFAULT; 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&ifr, arg, sizeof(ifr))) 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx = (struct sockaddr_ipx *)&ifr.ifr_addr; 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sipx->sipx_family != AF_IPX) 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f.ipx_network = sipx->sipx_network; 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(f.ipx_device, ifr.ifr_name, 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(f.ipx_device)); 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(f.ipx_node, sipx->sipx_node, IPX_NODE_LEN); 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f.ipx_dlink_type = sipx->sipx_type; 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f.ipx_special = sipx->sipx_special; 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sipx->sipx_action == IPX_DLTITF) 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxitf_delete(&f); 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxitf_create(&f); 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCGIFADDR: { 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr_ipx *sipx; 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *ipxif; 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EFAULT; 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&ifr, arg, sizeof(ifr))) 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx = (struct sockaddr_ipx *)&ifr.ifr_addr; 1157881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman dev = __dev_get_by_name(&init_net, ifr.ifr_name); 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENODEV; 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxif = ipxitf_find_using_phys(dev, 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_map_frame_type(sipx->sipx_type)); 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EADDRNOTAVAIL; 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ipxif) 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx->sipx_family = AF_IPX; 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx->sipx_network = ipxif->if_netnum; 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(sipx->sipx_node, ipxif->if_node, 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(sipx->sipx_node)); 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EFAULT; 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(arg, &ifr, sizeof(ifr))) 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(ipxif); 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1178981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki case SIOCAIPXITFCRT: 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EFAULT; 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_user(val, (unsigned char __user *) arg)) 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxcfg_auto_create_interfaces = val; 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1185981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki case SIOCAIPXPRISLT: 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EFAULT; 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_user(val, (unsigned char __user *) arg)) 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxcfg_set_auto_select(val); 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Checksum routine for IPX 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1200981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize */ 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This functions should *not* mess with packet contents */ 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 120402e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro__be16 ipx_cksum(struct ipxhdr *packet, int length) 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1206981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki /* 1207981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki * NOTE: sum is a net byte order quantity, which optimizes the 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * loop. This only works on big and little endian machines. (I 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * don't know of a machine that isn't.) 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 121102e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro /* handle the first 3 words separately; checksum should be skipped 121202e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro * and ipx_tctrl masked out */ 121302e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro __u16 *p = (__u16 *)packet; 121402e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro __u32 sum = p[1] + (p[2] & (__force u16)htons(0x00ff)); 121502e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro __u32 i = (length >> 1) - 3; /* Number of remaining complete words */ 121602e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro 121702e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro /* Loop through them */ 121802e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro p += 3; 121902e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro while (i--) 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sum += *p++; 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Add on the last part word if it exists */ 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (packet->ipx_pktsize & htons(1)) 122402e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro sum += (__force u16)htons(0xff00) & *p; 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Do final fixup */ 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sum = (sum & 0xffff) + (sum >> 16); 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* It's a pity there's no concept of carry in C */ 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sum >= 0x10000) 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sum++; 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 123302e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro /* 123402e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro * Leave 0 alone; we don't want 0xffff here. Note that we can't get 123502e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro * here with 0x10000, so this check is the same as ((__u16)sum) 123602e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro */ 123702e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro if (sum) 123802e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro sum = ~sum; 123902e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro 124002e60370d4dac83f22d5ae75d5512bcb9a3f24b7Al Viro return (__force __be16)sum; 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12434833ed094097323f5f219820f6ebdc8dd66f501fAl Viroconst char *ipx_frame_name(__be16 frame) 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char* rc = "None"; 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ntohs(frame)) { 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ETH_P_IPX: rc = "EtherII"; break; 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ETH_P_802_2: rc = "802.2"; break; 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ETH_P_SNAP: rc = "SNAP"; break; 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ETH_P_802_3: rc = "802.3"; break; 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsconst char *ipx_device_name(struct ipx_interface *intrfc) 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return intrfc->if_internal ? "Internal" : 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc->if_dev ? intrfc->if_dev->name : "Unknown"; 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Handling for system calls applied via the various interfaces to an IPX 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * socket object. */ 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipx_setsockopt(struct socket *sock, int level, int optname, 1267b7058842c940ad2c08dd829b21e5c92ebe3b8758David S. Miller char __user *optval, unsigned int optlen) 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk = sock->sk; 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int opt; 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -EINVAL; 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1273b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann lock_sock(sk); 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (optlen != sizeof(int)) 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EFAULT; 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_user(opt, (unsigned int __user *)optval)) 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOPROTOOPT; 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(level == SOL_IPX && optname == IPX_TYPE)) 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_sk(sk)->type = opt; 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1288b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann release_sock(sk); 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipx_getsockopt(struct socket *sock, int level, int optname, 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char __user *optval, int __user *optlen) 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk = sock->sk; 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int val = 0; 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len; 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -ENOPROTOOPT; 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1300b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann lock_sock(sk); 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(level == SOL_IPX && optname == IPX_TYPE)) 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = ipx_sk(sk)->type; 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EFAULT; 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_user(len, optlen)) 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = min_t(unsigned int, len, sizeof(int)); 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(len < 0) 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1314981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EFAULT; 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user(len, optlen) || copy_to_user(optval, &val, len)) 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1321b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann release_sock(sk); 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct proto ipx_proto = { 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "IPX", 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .obj_size = sizeof(struct ipx_sock), 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13313f378b684453f2a028eda463ce383370545d9cc9Eric Parisstatic int ipx_create(struct net *net, struct socket *sock, int protocol, 13323f378b684453f2a028eda463ce383370545d9cc9Eric Paris int kern) 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -ESOCKTNOSUPPORT; 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk; 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 133709ad9bc752519cc167d0a573e1acf69b5c707c67Octavian Purdila if (!net_eq(net, &init_net)) 13381b8d7ae42d02e483ad94035cca851e4f7fbecb40Eric W. Biederman return -EAFNOSUPPORT; 13391b8d7ae42d02e483ad94035cca851e4f7fbecb40Eric W. Biederman 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SPX support is not anymore in the kernel sources. If you want to 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ressurrect it, completing it and making it understand shared skbs, 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be fully multithreaded, etc, grab the sources in an early 2.5 kernel 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tree. 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sock->type != SOCK_DGRAM) 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1349981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki rc = -ENOMEM; 13506257ff2177ff02d7f260a7a501876aa41cb9a9f6Pavel Emelyanov sk = sk_alloc(net, PF_IPX, GFP_KERNEL, &ipx_proto); 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sk) 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1353c2b42336f4a733020360157ba629d37f1410923aPavel Emelyanov 1354c2b42336f4a733020360157ba629d37f1410923aPavel Emelyanov sk_refcnt_debug_inc(sk); 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock_init_data(sock, sk); 135628448b80456feafe07e2d05b6363b00f61f6171eTom Herbert sk->sk_no_check_tx = 1; /* Checksum off by default */ 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock->ops = &ipx_dgram_ops; 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipx_release(struct socket *sock) 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk = sock->sk; 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sk) 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1370b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann lock_sock(sk); 13718815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca sk->sk_shutdown = SHUTDOWN_MASK; 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sock_flag(sk, SOCK_DEAD)) 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk->sk_state_change(sk); 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock_set_flag(sk, SOCK_DEAD); 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock->sk = NULL; 1377c2b42336f4a733020360157ba629d37f1410923aPavel Emelyanov sk_refcnt_debug_release(sk); 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_destroy_socket(sk); 1379b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann release_sock(sk); 1380674f2115995b7b588cbf3540c9f9b2448a8c7ea8Eric Dumazet sock_put(sk); 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* caller must hold a reference to intrfc */ 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13874833ed094097323f5f219820f6ebdc8dd66f501fAl Virostatic __be16 ipx_first_free_socketnum(struct ipx_interface *intrfc) 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short socketNum = intrfc->if_sknum; 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&intrfc->if_sklist_lock); 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (socketNum < IPX_MIN_EPHEMERAL_SOCKET) 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socketNum = IPX_MIN_EPHEMERAL_SOCKET; 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13964833ed094097323f5f219820f6ebdc8dd66f501fAl Viro while (__ipxitf_find_socket(intrfc, htons(socketNum))) 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (socketNum > IPX_MAX_EPHEMERAL_SOCKET) 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socketNum = IPX_MIN_EPHEMERAL_SOCKET; 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socketNum++; 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&intrfc->if_sklist_lock); 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc->if_sknum = socketNum; 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14054833ed094097323f5f219820f6ebdc8dd66f501fAl Viro return htons(socketNum); 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 140883927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmannstatic int __ipx_bind(struct socket *sock, 140983927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmann struct sockaddr *uaddr, int addr_len) 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk = sock->sk; 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_sock *ipxs = ipx_sk(sk); 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *intrfc; 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr_ipx *addr = (struct sockaddr_ipx *)uaddr; 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -EINVAL; 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sock_flag(sk, SOCK_ZAPPED) || addr_len != sizeof(struct sockaddr_ipx)) 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc = ipxitf_find_using_net(addr->sipx_network); 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EADDRNOTAVAIL; 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!intrfc) 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!addr->sipx_port) { 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr->sipx_port = ipx_first_free_socketnum(intrfc); 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!addr->sipx_port) 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_put; 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* protect IPX system stuff like routing/sap */ 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EACCES; 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ntohs(addr->sipx_port) < IPX_MIN_EPHEMERAL_SOCKET && 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !capable(CAP_NET_ADMIN)) 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_put; 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxs->port = addr->sipx_port; 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IPX_INTERN 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intrfc == ipx_internal_net) { 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The source address is to be set explicitly if the 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * socket is to be bound on the internal network. If a 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * node number 0 was specified, the default is used. 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!memcmp(addr->sipx_node, ipx_broadcast_node, IPX_NODE_LEN)) 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_put; 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!memcmp(addr->sipx_node, ipx_this_node, IPX_NODE_LEN)) 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(ipxs->node, intrfc->if_node, IPX_NODE_LEN); 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(ipxs->node, addr->sipx_node, IPX_NODE_LEN); 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EADDRINUSE; 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipxitf_find_internal_socket(intrfc, ipxs->node, 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxs->port)) { 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SOCK_DEBUG(sk, 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "IPX: bind failed because port %X in use.\n", 14604833ed094097323f5f219820f6ebdc8dd66f501fAl Viro ntohs(addr->sipx_port)); 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_put; 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Source addresses are easy. It must be our 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * network:node pair for an interface routed to IPX 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with the ipx routing ioctl() 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(ipxs->node, intrfc->if_node, IPX_NODE_LEN); 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EADDRINUSE; 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipxitf_find_socket(intrfc, addr->sipx_port)) { 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SOCK_DEBUG(sk, 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "IPX: bind failed because port %X in use.\n", 14754833ed094097323f5f219820f6ebdc8dd66f501fAl Viro ntohs(addr->sipx_port)); 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_put; 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* !def CONFIG_IPX_INTERN */ 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Source addresses are easy. It must be our network:node pair for 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds an interface routed to IPX with the ipx routing ioctl() */ 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EADDRINUSE; 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipxitf_find_socket(intrfc, addr->sipx_port)) { 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SOCK_DEBUG(sk, "IPX: bind failed because port %X in use.\n", 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ntohs((int)addr->sipx_port)); 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_put; 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_IPX_INTERN */ 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_insert_socket(intrfc, sk); 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock_reset_flag(sk, SOCK_ZAPPED); 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_put: 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(intrfc); 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 150483927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmannstatic int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 150583927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmann{ 1506b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann struct sock *sk = sock->sk; 150783927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmann int rc; 150883927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmann 1509b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann lock_sock(sk); 151083927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmann rc = __ipx_bind(sock, uaddr, addr_len); 1511b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann release_sock(sk); 151283927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmann 151383927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmann return rc; 151483927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmann} 151583927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmann 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipx_connect(struct socket *sock, struct sockaddr *uaddr, 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int addr_len, int flags) 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk = sock->sk; 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_sock *ipxs = ipx_sk(sk); 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr_ipx *addr; 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -EINVAL; 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_route *rt; 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk->sk_state = TCP_CLOSE; 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock->state = SS_UNCONNECTED; 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1528b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann lock_sock(sk); 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (addr_len != sizeof(*addr)) 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr = (struct sockaddr_ipx *)uaddr; 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* put the autobinding in */ 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ipxs->port) { 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr_ipx uaddr; 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uaddr.sipx_port = 0; 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uaddr.sipx_network = 0; 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IPX_INTERN 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENETDOWN; 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ipxs->intrfc) 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; /* Someone zonked the iface */ 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(uaddr.sipx_node, ipxs->intrfc->if_node, 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_NODE_LEN); 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_IPX_INTERN */ 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 154883927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmann rc = __ipx_bind(sock, (struct sockaddr *)&uaddr, 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct sockaddr_ipx)); 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1554981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki /* We can either connect to primary network or somewhere 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we can route to */ 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rt = ipxrtr_lookup(addr->sipx_network); 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENETUNREACH; 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!rt && !(!addr->sipx_network && ipx_primary_net)) 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxs->dest_addr.net = addr->sipx_network; 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxs->dest_addr.sock = addr->sipx_port; 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(ipxs->dest_addr.node, addr->sipx_node, IPX_NODE_LEN); 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxs->type = addr->sipx_type; 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sock->type == SOCK_DGRAM) { 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock->state = SS_CONNECTED; 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk->sk_state = TCP_ESTABLISHED; 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rt) 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxrtr_put(rt); 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1575b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann release_sock(sk); 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipx_getname(struct socket *sock, struct sockaddr *uaddr, 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int *uaddr_len, int peer) 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_address *addr; 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr_ipx sipx; 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk = sock->sk; 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_sock *ipxs = ipx_sk(sk); 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *uaddr_len = sizeof(struct sockaddr_ipx); 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann lock_sock(sk); 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (peer) { 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOTCONN; 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sk->sk_state != TCP_ESTABLISHED) 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr = &ipxs->dest_addr; 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx.sipx_network = addr->net; 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx.sipx_port = addr->sock; 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(sipx.sipx_node, addr->node, IPX_NODE_LEN); 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipxs->intrfc) { 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx.sipx_network = ipxs->intrfc->if_netnum; 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IPX_INTERN 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(sipx.sipx_node, ipxs->node, IPX_NODE_LEN); 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(sipx.sipx_node, ipxs->intrfc->if_node, 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_NODE_LEN); 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_IPX_INTERN */ 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx.sipx_network = 0; 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(sipx.sipx_node, '\0', IPX_NODE_LEN); 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx.sipx_port = ipxs->port; 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx.sipx_family = AF_IPX; 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx.sipx_type = ipxs->type; 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx.sipx_zero = 0; 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(uaddr, &sipx, sizeof(sipx)); 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1626b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann release_sock(sk); 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1630f2ccd8fa06c8e302116e71df372f5c1f83432e03David S. Millerstatic int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NULL here for pt means the packet was looped back */ 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_interface *intrfc; 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipxhdr *ipx; 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 ipx_pktsize; 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 1637981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki 1638721499e8931c5732202481ae24f2dfbf9910f129YOSHIFUJI Hideaki if (!net_eq(dev_net(dev), &init_net)) 1639e730c15519d09ea528b4d2f1103681fa5937c0e6Eric W. Biederman goto drop; 1640e730c15519d09ea528b4d2f1103681fa5937c0e6Eric W. Biederman 1641981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki /* Not ours */ 1642981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki if (skb->pkt_type == PACKET_OTHERHOST) 1643981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki goto drop; 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16487b1ba8de569460894efa892457af7a37c0d574f9Stephen Hemminger if (!pskb_may_pull(skb, sizeof(struct ipxhdr))) 16497b1ba8de569460894efa892457af7a37c0d574f9Stephen Hemminger goto drop; 16507b1ba8de569460894efa892457af7a37c0d574f9Stephen Hemminger 1651fff642570dc47ab76491fe81ee6599269c4eb13eDavid S. Miller ipx_pktsize = ntohs(ipx_hdr(skb)->ipx_pktsize); 1652981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Too small or invalid header? */ 16548b5cc5ef40c83c6ea4c90b203bb2c8b17edfa11bStephen Hemminger if (ipx_pktsize < sizeof(struct ipxhdr) || 16558b5cc5ef40c83c6ea4c90b203bb2c8b17edfa11bStephen Hemminger !pskb_may_pull(skb, ipx_pktsize)) 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto drop; 1657981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki 16587b1ba8de569460894efa892457af7a37c0d574f9Stephen Hemminger ipx = ipx_hdr(skb); 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipx->ipx_checksum != IPX_NO_CHECKSUM && 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx->ipx_checksum != ipx_cksum(ipx, ipx_pktsize)) 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto drop; 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_SKB_CB(skb)->ipx_tctrl = ipx->ipx_tctrl; 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_SKB_CB(skb)->ipx_dest_net = ipx->ipx_dest.net; 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_SKB_CB(skb)->ipx_source_net = ipx->ipx_source.net; 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Determine what local ipx endpoint this is */ 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc = ipxitf_find_using_phys(dev, pt->type); 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!intrfc) { 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipxcfg_auto_create_interfaces && 16714833ed094097323f5f219820f6ebdc8dd66f501fAl Viro IPX_SKB_CB(skb)->ipx_dest_net) { 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intrfc = ipxitf_auto_create(dev, pt->type); 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (intrfc) 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_hold(intrfc); 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!intrfc) /* Not one of ours */ 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* or invalid packet for auto creation */ 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto drop; 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxitf_rcv(intrfc, skb); 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_put(intrfc); 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdrop: 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipx_sendmsg(struct kiocb *iocb, struct socket *sock, 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct msghdr *msg, size_t len) 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk = sock->sk; 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_sock *ipxs = ipx_sk(sk); 1696342dfc306fb32155314dad277f3c3686b83fb9f1Steffen Hurrle DECLARE_SOCKADDR(struct sockaddr_ipx *, usipx, msg->msg_name); 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr_ipx local_sipx; 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -EINVAL; 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int flags = msg->msg_flags; 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann lock_sock(sk); 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Socket gets bound below anyway */ 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* if (sk->sk_zapped) 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; */ /* Socket not bound */ 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Max possible packet size limited by 16 bit pktsize in header */ 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len >= 65535 - sizeof(struct ipxhdr)) 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (usipx) { 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ipxs->port) { 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr_ipx uaddr; 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uaddr.sipx_port = 0; 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uaddr.sipx_network = 0; 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IPX_INTERN 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENETDOWN; 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ipxs->intrfc) 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; /* Someone zonked the iface */ 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(uaddr.sipx_node, ipxs->intrfc->if_node, 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IPX_NODE_LEN); 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 172583927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmann rc = __ipx_bind(sock, (struct sockaddr *)&uaddr, 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct sockaddr_ipx)); 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (msg->msg_namelen < sizeof(*usipx) || 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usipx->sipx_family != AF_IPX) 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOTCONN; 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sk->sk_state != TCP_ESTABLISHED) 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usipx = &local_sipx; 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usipx->sipx_family = AF_IPX; 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usipx->sipx_type = ipxs->type; 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usipx->sipx_port = ipxs->dest_addr.sock; 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usipx->sipx_network = ipxs->dest_addr.net; 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(usipx->sipx_node, ipxs->dest_addr.node, IPX_NODE_LEN); 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxrtr_route_packet(sk, usipx, msg->msg_iov, len, 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags & MSG_DONTWAIT); 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc >= 0) 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = len; 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1753b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann release_sock(sk); 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipx_recvmsg(struct kiocb *iocb, struct socket *sock, 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct msghdr *msg, size_t size, int flags) 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk = sock->sk; 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipx_sock *ipxs = ipx_sk(sk); 1763342dfc306fb32155314dad277f3c3686b83fb9f1Steffen Hurrle DECLARE_SOCKADDR(struct sockaddr_ipx *, sipx, msg->msg_name); 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipxhdr *ipx = NULL; 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int copied, rc; 176701462405f0c093b2f8dfddafcadcda6c9e4c5cdfJiri Bohac bool locked = true; 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1769b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann lock_sock(sk); 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* put the autobinding in */ 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ipxs->port) { 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr_ipx uaddr; 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uaddr.sipx_port = 0; 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uaddr.sipx_network = 0; 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_IPX_INTERN 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENETDOWN; 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ipxs->intrfc) 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; /* Someone zonked the iface */ 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(uaddr.sipx_node, ipxs->intrfc->if_node, IPX_NODE_LEN); 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_IPX_INTERN */ 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 178483927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmann rc = __ipx_bind(sock, (struct sockaddr *)&uaddr, 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct sockaddr_ipx)); 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1789981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOTCONN; 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sock_flag(sk, SOCK_ZAPPED)) 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 179401462405f0c093b2f8dfddafcadcda6c9e4c5cdfJiri Bohac release_sock(sk); 179501462405f0c093b2f8dfddafcadcda6c9e4c5cdfJiri Bohac locked = false; 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags & MSG_DONTWAIT, &rc); 17988815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca if (!skb) { 17998815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca if (rc == -EAGAIN && (sk->sk_shutdown & RCV_SHUTDOWN)) 18008815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca rc = 0; 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 18028815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca } 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx = ipx_hdr(skb); 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copied = ntohs(ipx->ipx_pktsize) - sizeof(struct ipxhdr); 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copied > size) { 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copied = size; 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->msg_flags |= MSG_TRUNC; 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = skb_copy_datagram_iovec(skb, sizeof(struct ipxhdr), msg->msg_iov, 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copied); 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free; 1815b7aa0bf70c4afb9e38be25f5c0922498d0f8684cEric Dumazet if (skb->tstamp.tv64) 1816b7aa0bf70c4afb9e38be25f5c0922498d0f8684cEric Dumazet sk->sk_stamp = skb->tstamp; 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sipx) { 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx->sipx_family = AF_IPX; 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx->sipx_port = ipx->ipx_source.sock; 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(sipx->sipx_node, ipx->ipx_source.node, IPX_NODE_LEN); 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx->sipx_network = IPX_SKB_CB(skb)->ipx_source_net; 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx->sipx_type = ipx->ipx_type; 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sipx->sipx_zero = 0; 1825f3d3342602f8bcbf37d7c46641cb9bca7618eb1cHannes Frederic Sowa msg->msg_namelen = sizeof(*sipx); 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = copied; 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_free: 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_free_datagram(sk, skb); 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 183201462405f0c093b2f8dfddafcadcda6c9e4c5cdfJiri Bohac if (locked) 183301462405f0c093b2f8dfddafcadcda6c9e4c5cdfJiri Bohac release_sock(sk); 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long amount = 0; 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk = sock->sk; 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *argp = (void __user *)arg; 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1845b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann lock_sock(sk); 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCOUTQ: 184831e6d363abcd0d05766c82f1a9c905a4c974a199Eric Dumazet amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amount < 0) 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = 0; 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = put_user(amount, (int __user *)argp); 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case TIOCINQ: { 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* These two are safe on a single CPU system as only 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * user tasks fiddle here */ 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb) 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = skb->len - sizeof(struct ipxhdr); 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = put_user(amount, (int __user *)argp); 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCADDRT: 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCDELRT: 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EPERM; 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (capable(CAP_NET_ADMIN)) 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxrtr_ioctl(cmd, argp); 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCSIFADDR: 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCAIPXITFCRT: 18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCAIPXPRISLT: 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EPERM; 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_NET_ADMIN)) 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCGIFADDR: 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxitf_ioctl(cmd, argp); 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCIPXCFGDATA: 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ipxcfg_get_config_data(argp); 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCIPXNCPCONN: 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This socket wants to take care of the NCP connection 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handed to us in arg. 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1885981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki rc = -EPERM; 1886981c0ff6900c981668a798fe9e0bc5ba32ee3fd4YOSHIFUJI Hideaki if (!capable(CAP_NET_ADMIN)) 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = get_user(ipx_sk(sk)->ipx_ncp_conn, 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (const unsigned short __user *)argp); 18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCGSTAMP: 189232e9072b92a1c556a303d8d0e0d64feb667e601dDavid S. Miller rc = sock_get_timestamp(sk, argp); 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCGIFDSTADDR: 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCSIFDSTADDR: 18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCGIFBRDADDR: 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCSIFBRDADDR: 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCGIFNETMASK: 18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIOCSIFNETMASK: 19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1903b5e5fa5e093e42cab4ee3d6dcbc4f450ad29a723Christoph Hellwig rc = -ENOIOCTLCMD; 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1906b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann release_sock(sk); 19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec 1912f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec#ifdef CONFIG_COMPAT 1913f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovecstatic int ipx_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 1914f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec{ 1915f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec /* 1916f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec * These 4 commands use same structure on 32bit and 64bit. Rest of IPX 1917f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec * commands is handled by generic ioctl code. As these commands are 1918f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec * SIOCPROTOPRIVATE..SIOCPROTOPRIVATE+3, they cannot be handled by generic 1919f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec * code. 1920f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec */ 1921f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec switch (cmd) { 1922f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec case SIOCAIPXITFCRT: 1923f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec case SIOCAIPXPRISLT: 1924f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec case SIOCIPXCFGDATA: 1925f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec case SIOCIPXNCPCONN: 1926f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec return ipx_ioctl(sock, cmd, arg); 1927f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec default: 1928f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec return -ENOIOCTLCMD; 1929f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec } 1930f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec} 1931f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec#endif 1932f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec 19338815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubrocastatic int ipx_shutdown(struct socket *sock, int mode) 19348815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca{ 19358815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca struct sock *sk = sock->sk; 19368815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca 19378815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca if (mode < SHUT_RD || mode > SHUT_RDWR) 19388815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca return -EINVAL; 19398815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca /* This maps: 19408815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca * SHUT_RD (0) -> RCV_SHUTDOWN (1) 19418815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca * SHUT_WR (1) -> SEND_SHUTDOWN (2) 19428815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca * SHUT_RDWR (2) -> SHUTDOWN_MASK (3) 19438815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca */ 19448815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca ++mode; 19458815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca 19468815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca lock_sock(sk); 19478815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca sk->sk_shutdown |= mode; 19488815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca release_sock(sk); 19498815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca sk->sk_state_change(sk); 19508815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca 19518815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca return 0; 19528815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca} 1953f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Socket family declarations 19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1958ec1b4cf74c81bfd0fbe5bf62bafc86c45917e72fStephen Hemmingerstatic const struct net_proto_family ipx_family_ops = { 19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .family = PF_IPX, 19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .create = ipx_create, 19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 196483927ba069a65326f39991a02d6a49ba3b7cea44Arnd Bergmannstatic const struct proto_ops ipx_dgram_ops = { 19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .family = PF_IPX, 19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = ipx_release, 19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bind = ipx_bind, 19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .connect = ipx_connect, 19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .socketpair = sock_no_socketpair, 19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .accept = sock_no_accept, 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .getname = ipx_getname, 1973b0d0d915d1d1a0fe486849f3e41333c66df620c4Arnd Bergmann .poll = datagram_poll, 19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = ipx_ioctl, 1975f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec#ifdef CONFIG_COMPAT 1976f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec .compat_ioctl = ipx_compat_ioctl, 1977f6c90b71a355a0a4a22e1cfee5748617adc25a53Petr Vandrovec#endif 19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .listen = sock_no_listen, 19798815cbd9e38a7a02bfb79854aa7d33f1e1e50305Sabrina Dubroca .shutdown = ipx_shutdown, 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .setsockopt = ipx_setsockopt, 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .getsockopt = ipx_getsockopt, 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .sendmsg = ipx_sendmsg, 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .recvmsg = ipx_recvmsg, 19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .mmap = sock_no_mmap, 19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .sendpage = sock_no_sendpage, 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19887546dd97d27306d939c13e03318aae695badaa88Stephen Hemmingerstatic struct packet_type ipx_8023_packet_type __read_mostly = { 198909640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison .type = cpu_to_be16(ETH_P_802_3), 19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .func = ipx_rcv, 19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19937546dd97d27306d939c13e03318aae695badaa88Stephen Hemmingerstatic struct packet_type ipx_dix_packet_type __read_mostly = { 199409640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison .type = cpu_to_be16(ETH_P_IPX), 19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .func = ipx_rcv, 19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct notifier_block ipx_dev_notifier = { 19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .notifier_call = ipxitf_device_event, 20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2002fa665ccf01440644a3956ed039e51e1088cd0f15Stephen Hemmingerstatic const unsigned char ipx_8022_type = 0xE0; 2003fa665ccf01440644a3956ed039e51e1088cd0f15Stephen Hemmingerstatic const unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 }; 2004fa665ccf01440644a3956ed039e51e1088cd0f15Stephen Hemmingerstatic const char ipx_EII_err_msg[] __initconst = 20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds KERN_CRIT "IPX: Unable to register with Ethernet II\n"; 2006fa665ccf01440644a3956ed039e51e1088cd0f15Stephen Hemmingerstatic const char ipx_8023_err_msg[] __initconst = 20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds KERN_CRIT "IPX: Unable to register with 802.3\n"; 2008fa665ccf01440644a3956ed039e51e1088cd0f15Stephen Hemmingerstatic const char ipx_llc_err_msg[] __initconst = 20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds KERN_CRIT "IPX: Unable to register with 802.2\n"; 2010fa665ccf01440644a3956ed039e51e1088cd0f15Stephen Hemmingerstatic const char ipx_snap_err_msg[] __initconst = 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds KERN_CRIT "IPX: Unable to register with SNAP\n"; 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ipx_init(void) 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = proto_register(&ipx_proto, 1); 20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != 0) 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock_register(&ipx_family_ops); 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pEII_datalink = make_EII_client(); 20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pEII_datalink) 20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_add_pack(&ipx_dix_packet_type); 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(ipx_EII_err_msg); 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p8023_datalink = make_8023_client(); 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p8023_datalink) 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_add_pack(&ipx_8023_packet_type); 20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(ipx_8023_err_msg); 20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p8022_datalink = register_8022_client(ipx_8022_type, ipx_rcv); 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!p8022_datalink) 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(ipx_llc_err_msg); 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pSNAP_datalink = register_snap_client(ipx_snap_id, ipx_rcv); 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pSNAP_datalink) 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(ipx_snap_err_msg); 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_netdevice_notifier(&ipx_dev_notifier); 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_register_sysctl(); 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_proc_init(); 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit ipx_proto_finito(void) 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_proc_exit(); 20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipx_unregister_sysctl(); 20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdevice_notifier(&ipx_dev_notifier); 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipxitf_cleanup(); 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20581539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac if (pSNAP_datalink) { 20591539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac unregister_snap_client(pSNAP_datalink); 20601539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac pSNAP_datalink = NULL; 20611539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac } 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20631539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac if (p8022_datalink) { 20641539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac unregister_8022_client(p8022_datalink); 20651539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac p8022_datalink = NULL; 20661539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac } 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_remove_pack(&ipx_8023_packet_type); 20691539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac if (p8023_datalink) { 20701539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac destroy_8023_client(p8023_datalink); 20711539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac p8023_datalink = NULL; 20721539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac } 20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_remove_pack(&ipx_dix_packet_type); 20751539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac if (pEII_datalink) { 20761539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac destroy_EII_client(pEII_datalink); 20771539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac pEII_datalink = NULL; 20781539b98b561754252dd520b98fa03a688a4f81b5Jiri Bohac } 20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds proto_unregister(&ipx_proto); 20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock_unregister(ipx_family_ops.family); 20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(ipx_init); 20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(ipx_proto_finito); 20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_ALIAS_NETPROTO(PF_IPX); 2088