* See net/ipx/ChangeLog.
*/
-#include <linux/config.h>
+#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/string.h>
-#include <linux/tcp.h>
#include <linux/types.h>
#include <linux/termios.h>
#include <net/p8022.h>
#include <net/psnap.h>
#include <net/sock.h>
+#include <net/tcp_states.h>
#include <asm/uaccess.h>
static struct datalink_proto *p8023_datalink;
static struct datalink_proto *pSNAP_datalink;
-static struct proto_ops ipx_dgram_ops;
+static const struct proto_ops ipx_dgram_ops;
LIST_HEAD(ipx_interfaces);
-spinlock_t ipx_interfaces_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(ipx_interfaces_lock);
struct ipx_interface *ipx_primary_net;
struct ipx_interface *ipx_internal_net;
-extern int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc,
+extern int ipxrtr_add_route(__be32 network, struct ipx_interface *intrfc,
unsigned char *node);
extern void ipxrtr_del_routes(struct ipx_interface *intrfc);
extern int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
struct iovec *iov, int len, int noblock);
extern int ipxrtr_route_skb(struct sk_buff *skb);
-extern struct ipx_route *ipxrtr_lookup(__u32 net);
-extern int ipxrtr_ioctl(unsigned int cmd, void *arg);
+extern struct ipx_route *ipxrtr_lookup(__be32 net);
+extern int ipxrtr_ioctl(unsigned int cmd, void __user *arg);
#undef IPX_REFCNT_DEBUG
#ifdef IPX_REFCNT_DEBUG
ipx_primary_net = ipx_interfaces_head();
}
-static int ipxcfg_get_config_data(struct ipx_config_data *arg)
+static int ipxcfg_get_config_data(struct ipx_config_data __user *arg)
{
struct ipx_config_data vals;
}
static struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev,
- unsigned short datalink)
+ __be16 datalink)
{
struct ipx_interface *i;
}
static struct ipx_interface *ipxitf_find_using_phys(struct net_device *dev,
- unsigned short datalink)
+ __be16 datalink)
{
struct ipx_interface *i;
return i;
}
-struct ipx_interface *ipxitf_find_using_net(__u32 net)
+struct ipx_interface *ipxitf_find_using_net(__be32 net)
{
struct ipx_interface *i;
/* caller must hold intrfc->if_sklist_lock */
static struct sock *__ipxitf_find_socket(struct ipx_interface *intrfc,
- unsigned short port)
+ __be16 port)
{
struct sock *s;
struct hlist_node *node;
/* caller must hold a reference to intrfc */
static struct sock *ipxitf_find_socket(struct ipx_interface *intrfc,
- unsigned short port)
+ __be16 port)
{
struct sock *s;
#ifdef CONFIG_IPX_INTERN
static struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc,
unsigned char *ipx_node,
- unsigned short port)
+ __be16 port)
{
struct sock *s;
struct hlist_node *node;
spin_lock_bh(&intrfc->if_sklist_lock);
sk_for_each(s, node, &intrfc->if_sklist) {
- struct ipx_opt *ipxs = ipx_sk(s);
+ struct ipx_sock *ipxs = ipx_sk(s);
if (ipxs->port == port &&
!memcmp(ipx_node, ipxs->node, IPX_NODE_LEN))
}
#endif
-void __ipxitf_down(struct ipx_interface *intrfc)
+static void __ipxitf_down(struct ipx_interface *intrfc)
{
struct sock *s;
struct hlist_node *node, *t;
spin_lock_bh(&intrfc->if_sklist_lock);
/* error sockets */
sk_for_each_safe(s, node, t, &intrfc->if_sklist) {
- struct ipx_opt *ipxs = ipx_sk(s);
+ struct ipx_sock *ipxs = ipx_sk(s);
s->sk_err = ENOLINK;
s->sk_error_report(s);
ipxs->intrfc = NULL;
ipxs->port = 0;
- s->sk_zapped = 1; /* Indicates it is no longer bound */
+ sock_set_flag(s, SOCK_ZAPPED); /* Indicates it is no longer bound */
sk_del_node_init(s);
}
INIT_HLIST_HEAD(&intrfc->if_sklist);
spin_unlock_bh(&ipx_interfaces_lock);
}
+static __inline__ void __ipxitf_put(struct ipx_interface *intrfc)
+{
+ if (atomic_dec_and_test(&intrfc->refcnt))
+ __ipxitf_down(intrfc);
+}
+
static int ipxitf_device_event(struct notifier_block *notifier,
unsigned long event, void *ptr)
{
spin_lock_bh(&intrfc->if_sklist_lock);
sk_for_each(s, node, &intrfc->if_sklist) {
- struct ipx_opt *ipxs = ipx_sk(s);
+ struct ipx_sock *ipxs = ipx_sk(s);
if (ipxs->port == ipx->ipx_dest.sock &&
(is_broadcast || !memcmp(ipx->ipx_dest.node,
/* see if we need to include the netnum in the route list */
if (IPX_SKB_CB(skb)->last_hop.index >= 0) {
- u32 *last_hop = (u32 *)(((u8 *) skb->data) +
+ __be32 *last_hop = (__be32 *)(((u8 *) skb->data) +
sizeof(struct ipxhdr) +
IPX_SKB_CB(skb)->last_hop.index *
- sizeof(u32));
+ sizeof(__be32));
*last_hop = IPX_SKB_CB(skb)->last_hop.netnum;
IPX_SKB_CB(skb)->last_hop.index = -1;
}
} else {
printk(KERN_WARNING "IPX: Network number collision "
"%lx\n %s %s and %s %s\n",
- (unsigned long) htonl(cb->ipx_source_net),
+ (unsigned long) ntohl(cb->ipx_source_net),
ipx_device_name(i),
ipx_frame_name(i->if_dlink_type),
ipx_device_name(intrfc),
int i, rc = -EINVAL;
struct ipx_interface *ifcs;
char *c;
- u32 *l;
+ __be32 *l;
/* Illegal packet - too many hops or too short */
/* We decide to throw it away: no broadcasting, no local processing.
goto out;
c = ((u8 *) ipx) + sizeof(struct ipxhdr);
- l = (u32 *) c;
+ l = (__be32 *) c;
/* Don't broadcast packet if already seen this net */
for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++)
/* That aren't in the list */
if (ifcs == intrfc)
continue;
- l = (__u32 *) c;
+ l = (__be32 *) c;
/* don't consider the last entry in the packet list,
* it is our netnum, and it is not there yet */
for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++)
ipx_primary_net = intrfc;
}
-static struct ipx_interface *ipxitf_alloc(struct net_device *dev, __u32 netnum,
- unsigned short dlink_type,
+static struct ipx_interface *ipxitf_alloc(struct net_device *dev, __be32 netnum,
+ __be16 dlink_type,
struct datalink_proto *dlink,
unsigned char internal,
int ipx_offset)
return rc;
}
-static int ipx_map_frame_type(unsigned char type)
+static __be16 ipx_map_frame_type(unsigned char type)
{
- int rc = 0;
+ __be16 rc = 0;
switch (type) {
case IPX_FRAME_ETHERII: rc = htons(ETH_P_IPX); break;
static int ipxitf_create(struct ipx_interface_definition *idef)
{
struct net_device *dev;
- unsigned short dlink_type = 0;
+ __be16 dlink_type = 0;
struct datalink_proto *datalink = NULL;
struct ipx_interface *intrfc;
int rc;
static int ipxitf_delete(struct ipx_interface_definition *idef)
{
struct net_device *dev = NULL;
- unsigned short dlink_type = 0;
+ __be16 dlink_type = 0;
struct ipx_interface *intrfc;
int rc = 0;
}
static struct ipx_interface *ipxitf_auto_create(struct net_device *dev,
- unsigned short dlink_type)
+ __be16 dlink_type)
{
struct ipx_interface *intrfc = NULL;
struct datalink_proto *datalink;
if (dev->addr_len > IPX_NODE_LEN)
goto out;
- switch (htons(dlink_type)) {
+ switch (ntohs(dlink_type)) {
case ETH_P_IPX: datalink = pEII_datalink; break;
case ETH_P_802_2: datalink = p8022_datalink; break;
case ETH_P_SNAP: datalink = pSNAP_datalink; break;
return intrfc;
}
-static int ipxitf_ioctl(unsigned int cmd, void *arg)
+static int ipxitf_ioctl(unsigned int cmd, void __user *arg)
{
int rc = -EINVAL;
struct ifreq ifr;
}
case SIOCAIPXITFCRT:
rc = -EFAULT;
- if (get_user(val, (unsigned char *) arg))
+ if (get_user(val, (unsigned char __user *) arg))
break;
rc = 0;
ipxcfg_auto_create_interfaces = val;
break;
case SIOCAIPXPRISLT:
rc = -EFAULT;
- if (get_user(val, (unsigned char *) arg))
+ if (get_user(val, (unsigned char __user *) arg))
break;
rc = 0;
ipxcfg_set_auto_select(val);
/* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize */
/* This functions should *not* mess with packet contents */
-__u16 ipx_cksum(struct ipxhdr *packet, int length)
+__be16 ipx_cksum(struct ipxhdr *packet, int length)
{
/*
* NOTE: sum is a net byte order quantity, which optimizes the
* loop. This only works on big and little endian machines. (I
* don't know of a machine that isn't.)
*/
- /* start at ipx_dest - We skip the checksum field and start with
- * ipx_type before the loop, not considering ipx_tctrl in the calc */
- __u16 *p = (__u16 *)&packet->ipx_dest;
- __u32 i = (length >> 1) - 1; /* Number of complete words */
- __u32 sum = packet->ipx_type << sizeof(packet->ipx_tctrl);
-
- /* Loop through all complete words except the checksum field,
- * ipx_type (accounted above) and ipx_tctrl (not used in the cksum) */
- while (--i)
+ /* handle the first 3 words separately; checksum should be skipped
+ * and ipx_tctrl masked out */
+ __u16 *p = (__u16 *)packet;
+ __u32 sum = p[1] + (p[2] & (__force u16)htons(0x00ff));
+ __u32 i = (length >> 1) - 3; /* Number of remaining complete words */
+
+ /* Loop through them */
+ p += 3;
+ while (i--)
sum += *p++;
/* Add on the last part word if it exists */
if (packet->ipx_pktsize & htons(1))
- sum += ntohs(0xff00) & *p;
+ sum += (__force u16)htons(0xff00) & *p;
/* Do final fixup */
sum = (sum & 0xffff) + (sum >> 16);
if (sum >= 0x10000)
sum++;
- return ~sum;
+ /*
+ * Leave 0 alone; we don't want 0xffff here. Note that we can't get
+ * here with 0x10000, so this check is the same as ((__u16)sum)
+ */
+ if (sum)
+ sum = ~sum;
+
+ return (__force __be16)sum;
}
-const char *ipx_frame_name(unsigned short frame)
+const char *ipx_frame_name(__be16 frame)
{
char* rc = "None";
* socket object. */
static int ipx_setsockopt(struct socket *sock, int level, int optname,
- char *optval, int optlen)
+ char __user *optval, int optlen)
{
struct sock *sk = sock->sk;
int opt;
goto out;
rc = -EFAULT;
- if (get_user(opt, (unsigned int *)optval))
+ if (get_user(opt, (unsigned int __user *)optval))
goto out;
rc = -ENOPROTOOPT;
}
static int ipx_getsockopt(struct socket *sock, int level, int optname,
- char *optval, int *optlen)
+ char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
int val = 0;
return rc;
}
+static struct proto ipx_proto = {
+ .name = "IPX",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct ipx_sock),
+};
+
static int ipx_create(struct socket *sock, int protocol)
{
int rc = -ESOCKTNOSUPPORT;
- struct ipx_opt *ipx = NULL;
struct sock *sk;
- switch (sock->type) {
- case SOCK_DGRAM:
- sk = sk_alloc(PF_IPX, GFP_KERNEL, 1, NULL);
- rc = -ENOMEM;
- if (!sk)
- goto out;
- ipx = sk->sk_protinfo = kmalloc(sizeof(*ipx), GFP_KERNEL);
- if (!ipx)
- goto outsk;
- memset(ipx, 0, sizeof(*ipx));
- sock->ops = &ipx_dgram_ops;
- break;
- case SOCK_SEQPACKET:
- /*
- * SPX support is not anymore in the kernel sources. If
- * you want to ressurrect it, completing it and making
- * it understand shared skbs, be fully multithreaded,
- * etc, grab the sources in an early 2.5 kernel tree.
- */
- case SOCK_STREAM: /* Allow higher levels to piggyback */
- default:
+ /*
+ * SPX support is not anymore in the kernel sources. If you want to
+ * ressurrect it, completing it and making it understand shared skbs,
+ * be fully multithreaded, etc, grab the sources in an early 2.5 kernel
+ * tree.
+ */
+ if (sock->type != SOCK_DGRAM)
+ goto out;
+
+ rc = -ENOMEM;
+ sk = sk_alloc(PF_IPX, GFP_KERNEL, &ipx_proto, 1);
+ if (!sk)
goto out;
- }
#ifdef IPX_REFCNT_DEBUG
atomic_inc(&ipx_sock_nr);
printk(KERN_DEBUG "IPX socket %p created, now we have %d alive\n", sk,
atomic_read(&ipx_sock_nr));
#endif
sock_init_data(sock, sk);
- sk_set_owner(sk, THIS_MODULE);
sk->sk_no_check = 1; /* Checksum off by default */
+ sock->ops = &ipx_dgram_ops;
rc = 0;
out:
return rc;
-outsk:
- sk_free(sk);
- goto out;
}
static int ipx_release(struct socket *sock)
/* caller must hold a reference to intrfc */
-static unsigned short ipx_first_free_socketnum(struct ipx_interface *intrfc)
+static __be16 ipx_first_free_socketnum(struct ipx_interface *intrfc)
{
unsigned short socketNum = intrfc->if_sknum;
if (socketNum < IPX_MIN_EPHEMERAL_SOCKET)
socketNum = IPX_MIN_EPHEMERAL_SOCKET;
- while (__ipxitf_find_socket(intrfc, ntohs(socketNum)))
+ while (__ipxitf_find_socket(intrfc, htons(socketNum)))
if (socketNum > IPX_MAX_EPHEMERAL_SOCKET)
socketNum = IPX_MIN_EPHEMERAL_SOCKET;
else
spin_unlock_bh(&intrfc->if_sklist_lock);
intrfc->if_sknum = socketNum;
- return ntohs(socketNum);
+ return htons(socketNum);
}
static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sock *sk = sock->sk;
- struct ipx_opt *ipxs = ipx_sk(sk);
+ struct ipx_sock *ipxs = ipx_sk(sk);
struct ipx_interface *intrfc;
struct sockaddr_ipx *addr = (struct sockaddr_ipx *)uaddr;
int rc = -EINVAL;
- if (!sk->sk_zapped || addr_len != sizeof(struct sockaddr_ipx))
+ if (!sock_flag(sk, SOCK_ZAPPED) || addr_len != sizeof(struct sockaddr_ipx))
goto out;
intrfc = ipxitf_find_using_net(addr->sipx_network);
ipxs->port)) {
SOCK_DEBUG(sk,
"IPX: bind failed because port %X in use.\n",
- ntohs((int)addr->sipx_port));
+ ntohs(addr->sipx_port));
goto out_put;
}
} else {
if (ipxitf_find_socket(intrfc, addr->sipx_port)) {
SOCK_DEBUG(sk,
"IPX: bind failed because port %X in use.\n",
- ntohs((int)addr->sipx_port));
+ ntohs(addr->sipx_port));
goto out_put;
}
}
#endif /* CONFIG_IPX_INTERN */
ipxitf_insert_socket(intrfc, sk);
- sk->sk_zapped = 0;
+ sock_reset_flag(sk, SOCK_ZAPPED);
rc = 0;
out_put:
int addr_len, int flags)
{
struct sock *sk = sock->sk;
- struct ipx_opt *ipxs = ipx_sk(sk);
+ struct ipx_sock *ipxs = ipx_sk(sk);
struct sockaddr_ipx *addr;
int rc = -EINVAL;
struct ipx_route *rt;
struct ipx_address *addr;
struct sockaddr_ipx sipx;
struct sock *sk = sock->sk;
- struct ipx_opt *ipxs = ipx_sk(sk);
+ struct ipx_sock *ipxs = ipx_sk(sk);
int rc;
*uaddr_len = sizeof(struct sockaddr_ipx);
sipx.sipx_family = AF_IPX;
sipx.sipx_type = ipxs->type;
+ sipx.sipx_zero = 0;
memcpy(uaddr, &sipx, sizeof(sipx));
rc = 0;
return rc;
}
-int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
/* NULL here for pt means the packet was looped back */
struct ipx_interface *intrfc;
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
goto out;
- ipx = ipx_hdr(skb);
- ipx_pktsize = ntohs(ipx->ipx_pktsize);
+ if (!pskb_may_pull(skb, sizeof(struct ipxhdr)))
+ goto drop;
+
+ ipx_pktsize = ntohs(ipx_hdr(skb)->ipx_pktsize);
/* Too small or invalid header? */
- if (ipx_pktsize < sizeof(struct ipxhdr) || ipx_pktsize > skb->len)
+ if (ipx_pktsize < sizeof(struct ipxhdr) ||
+ !pskb_may_pull(skb, ipx_pktsize))
goto drop;
+ ipx = ipx_hdr(skb);
if (ipx->ipx_checksum != IPX_NO_CHECKSUM &&
ipx->ipx_checksum != ipx_cksum(ipx, ipx_pktsize))
goto drop;
intrfc = ipxitf_find_using_phys(dev, pt->type);
if (!intrfc) {
if (ipxcfg_auto_create_interfaces &&
- ntohl(IPX_SKB_CB(skb)->ipx_dest_net)) {
+ IPX_SKB_CB(skb)->ipx_dest_net) {
intrfc = ipxitf_auto_create(dev, pt->type);
if (intrfc)
ipxitf_hold(intrfc);
struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
- struct ipx_opt *ipxs = ipx_sk(sk);
+ struct ipx_sock *ipxs = ipx_sk(sk);
struct sockaddr_ipx *usipx = (struct sockaddr_ipx *)msg->msg_name;
struct sockaddr_ipx local_sipx;
int rc = -EINVAL;
/* Socket gets bound below anyway */
/* if (sk->sk_zapped)
return -EIO; */ /* Socket not bound */
- if (flags & ~MSG_DONTWAIT)
+ if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
goto out;
/* Max possible packet size limited by 16 bit pktsize in header */
struct msghdr *msg, size_t size, int flags)
{
struct sock *sk = sock->sk;
- struct ipx_opt *ipxs = ipx_sk(sk);
+ struct ipx_sock *ipxs = ipx_sk(sk);
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name;
struct ipxhdr *ipx = NULL;
struct sk_buff *skb;
}
rc = -ENOTCONN;
- if (sk->sk_zapped)
+ if (sock_flag(sk, SOCK_ZAPPED))
goto out;
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
copied);
if (rc)
goto out_free;
- if (skb->stamp.tv_sec)
- sk->sk_stamp = skb->stamp;
+ if (skb->tstamp.off_sec)
+ skb_get_timestamp(skb, &sk->sk_stamp);
msg->msg_namelen = sizeof(*sipx);
memcpy(sipx->sipx_node, ipx->ipx_source.node, IPX_NODE_LEN);
sipx->sipx_network = IPX_SKB_CB(skb)->ipx_source_net;
sipx->sipx_type = ipx->ipx_type;
+ sipx->sipx_zero = 0;
}
rc = copied;
int rc = 0;
long amount = 0;
struct sock *sk = sock->sk;
+ void __user *argp = (void __user *)arg;
switch (cmd) {
case TIOCOUTQ:
amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
if (amount < 0)
amount = 0;
- rc = put_user(amount, (int *)arg);
+ rc = put_user(amount, (int __user *)argp);
break;
case TIOCINQ: {
struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
* user tasks fiddle here */
if (skb)
amount = skb->len - sizeof(struct ipxhdr);
- rc = put_user(amount, (int *)arg);
+ rc = put_user(amount, (int __user *)argp);
break;
}
case SIOCADDRT:
case SIOCDELRT:
rc = -EPERM;
if (capable(CAP_NET_ADMIN))
- rc = ipxrtr_ioctl(cmd, (void *)arg);
+ rc = ipxrtr_ioctl(cmd, argp);
break;
case SIOCSIFADDR:
case SIOCAIPXITFCRT:
if (!capable(CAP_NET_ADMIN))
break;
case SIOCGIFADDR:
- rc = ipxitf_ioctl(cmd, (void *)arg);
+ rc = ipxitf_ioctl(cmd, argp);
break;
case SIOCIPXCFGDATA:
- rc = ipxcfg_get_config_data((void *)arg);
+ rc = ipxcfg_get_config_data(argp);
break;
case SIOCIPXNCPCONN:
/*
if (!capable(CAP_NET_ADMIN))
break;
rc = get_user(ipx_sk(sk)->ipx_ncp_conn,
- (const unsigned short *)(arg));
+ (const unsigned short __user *)argp);
break;
case SIOCGSTAMP:
rc = -EINVAL;
if (sk)
- rc = sock_get_timestamp(sk, (struct timeval *)arg);
+ rc = sock_get_timestamp(sk, argp);
break;
case SIOCGIFDSTADDR:
case SIOCSIFDSTADDR:
rc = -EINVAL;
break;
default:
- rc = dev_ioctl(cmd,(void *) arg);
+ rc = -ENOIOCTLCMD;
break;
}
return rc;
}
+
+#ifdef CONFIG_COMPAT
+static int ipx_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ /*
+ * These 4 commands use same structure on 32bit and 64bit. Rest of IPX
+ * commands is handled by generic ioctl code. As these commands are
+ * SIOCPROTOPRIVATE..SIOCPROTOPRIVATE+3, they cannot be handled by generic
+ * code.
+ */
+ switch (cmd) {
+ case SIOCAIPXITFCRT:
+ case SIOCAIPXPRISLT:
+ case SIOCIPXCFGDATA:
+ case SIOCIPXNCPCONN:
+ return ipx_ioctl(sock, cmd, arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+#endif
+
+
/*
* Socket family declarations
*/
.owner = THIS_MODULE,
};
-static struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
+static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
.family = PF_IPX,
.owner = THIS_MODULE,
.release = ipx_release,
.getname = ipx_getname,
.poll = datagram_poll,
.ioctl = ipx_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ipx_compat_ioctl,
+#endif
.listen = sock_no_listen,
.shutdown = sock_no_shutdown, /* FIXME: support shutdown */
.setsockopt = ipx_setsockopt,
};
extern struct datalink_proto *make_EII_client(void);
-extern struct datalink_proto *make_8023_client(void);
extern void destroy_EII_client(struct datalink_proto *);
-extern void destroy_8023_client(struct datalink_proto *);
static unsigned char ipx_8022_type = 0xE0;
static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
static int __init ipx_init(void)
{
+ int rc = proto_register(&ipx_proto, 1);
+
+ if (rc != 0)
+ goto out;
+
sock_register(&ipx_family_ops);
pEII_datalink = make_EII_client();
register_netdevice_notifier(&ipx_dev_notifier);
ipx_register_sysctl();
ipx_proc_init();
- return 0;
+out:
+ return rc;
}
static void __exit ipx_proto_finito(void)
ipxitf_cleanup();
- unregister_snap_client(pSNAP_datalink);
- pSNAP_datalink = NULL;
+ if (pSNAP_datalink) {
+ unregister_snap_client(pSNAP_datalink);
+ pSNAP_datalink = NULL;
+ }
- unregister_8022_client(p8022_datalink);
- p8022_datalink = NULL;
+ if (p8022_datalink) {
+ unregister_8022_client(p8022_datalink);
+ p8022_datalink = NULL;
+ }
dev_remove_pack(&ipx_8023_packet_type);
- destroy_8023_client(p8023_datalink);
- p8023_datalink = NULL;
+ if (p8023_datalink) {
+ destroy_8023_client(p8023_datalink);
+ p8023_datalink = NULL;
+ }
dev_remove_pack(&ipx_dix_packet_type);
- destroy_EII_client(pEII_datalink);
- pEII_datalink = NULL;
+ if (pEII_datalink) {
+ destroy_EII_client(pEII_datalink);
+ pEII_datalink = NULL;
+ }
+ proto_unregister(&ipx_proto);
sock_unregister(ipx_family_ops.family);
}