fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / ipx / af_ipx.c
index 163223d..89f283c 100644 (file)
@@ -28,7 +28,7 @@
  *     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>
@@ -44,7 +44,6 @@
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/string.h>
-#include <linux/tcp.h>
 #include <linux/types.h>
 #include <linux/termios.h>
 
@@ -52,6 +51,7 @@
 #include <net/p8022.h>
 #include <net/psnap.h>
 #include <net/sock.h>
+#include <net/tcp_states.h>
 
 #include <asm/uaccess.h>
 
@@ -75,21 +75,21 @@ static struct datalink_proto *pEII_datalink;
 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 struct ipx_route *ipxrtr_lookup(__be32 net);
 extern int ipxrtr_ioctl(unsigned int cmd, void __user *arg);
 
 #undef IPX_REFCNT_DEBUG
@@ -177,7 +177,7 @@ static void ipxitf_clear_primary_net(void)
 }
 
 static struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev,
-                                                     unsigned short datalink)
+                                                     __be16 datalink)
 {
        struct ipx_interface *i;
 
@@ -190,7 +190,7 @@ out:
 }
 
 static struct ipx_interface *ipxitf_find_using_phys(struct net_device *dev,
-                                                   unsigned short datalink)
+                                                   __be16 datalink)
 {
        struct ipx_interface *i;
 
@@ -202,7 +202,7 @@ static struct ipx_interface *ipxitf_find_using_phys(struct net_device *dev,
        return i;
 }
 
-struct ipx_interface *ipxitf_find_using_net(__u32 net)
+struct ipx_interface *ipxitf_find_using_net(__be32 net)
 {
        struct ipx_interface *i;
 
@@ -237,7 +237,7 @@ static void ipxitf_insert_socket(struct ipx_interface *intrfc, struct sock *sk)
 
 /* 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;
@@ -252,7 +252,7 @@ found:
 
 /* 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;
 
@@ -268,7 +268,7 @@ static struct sock *ipxitf_find_socket(struct ipx_interface *intrfc,
 #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;
@@ -277,7 +277,7 @@ static struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc,
        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))
@@ -291,7 +291,7 @@ found:
 }
 #endif
 
-void __ipxitf_down(struct ipx_interface *intrfc)
+static void __ipxitf_down(struct ipx_interface *intrfc)
 {
        struct sock *s;
        struct hlist_node *node, *t;
@@ -302,13 +302,13 @@ void __ipxitf_down(struct ipx_interface *intrfc)
        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);
@@ -335,6 +335,12 @@ void ipxitf_down(struct ipx_interface *intrfc)
        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)
 {
@@ -394,7 +400,7 @@ static int ipxitf_demux_socket(struct ipx_interface *intrfc,
        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,
@@ -594,10 +600,10 @@ int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb, char *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;
        }
@@ -766,7 +772,7 @@ static void ipxitf_discover_netnum(struct ipx_interface *intrfc,
                } 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),
@@ -806,7 +812,7 @@ static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb)
        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.
@@ -827,7 +833,7 @@ static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb)
                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++)
@@ -849,7 +855,7 @@ static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb)
                /* 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++)
@@ -879,8 +885,8 @@ static void ipxitf_insert(struct ipx_interface *intrfc)
                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)
@@ -937,9 +943,9 @@ out:
        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;
@@ -954,7 +960,7 @@ static int ipx_map_frame_type(unsigned char type)
 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;
@@ -1067,7 +1073,7 @@ out:
 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;
 
@@ -1104,7 +1110,7 @@ out:
 }
 
 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;
@@ -1116,7 +1122,7 @@ static struct ipx_interface *ipxitf_auto_create(struct net_device *dev,
        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;
@@ -1228,27 +1234,27 @@ static int ipxitf_ioctl(unsigned int cmd, void __user *arg)
 /* 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);
@@ -1257,10 +1263,17 @@ __u16 ipx_cksum(struct ipxhdr *packet, int length)
        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";
 
@@ -1339,49 +1352,41 @@ out:
        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)
@@ -1403,7 +1408,7 @@ out:
 
 /* 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;
 
@@ -1412,7 +1417,7 @@ static unsigned short ipx_first_free_socketnum(struct ipx_interface *intrfc)
        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
@@ -1421,18 +1426,18 @@ static unsigned short ipx_first_free_socketnum(struct ipx_interface *intrfc)
        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);
@@ -1475,7 +1480,7 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                                                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 {
@@ -1490,7 +1495,7 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                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;
                }
        }
@@ -1510,7 +1515,7 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 #endif /* CONFIG_IPX_INTERN */
 
        ipxitf_insert_socket(intrfc, sk);
-       sk->sk_zapped = 0;
+       sock_reset_flag(sk, SOCK_ZAPPED);
 
        rc = 0;
 out_put:
@@ -1523,7 +1528,7 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
        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;
@@ -1587,7 +1592,7 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
        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);
@@ -1621,6 +1626,7 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
 
        sipx.sipx_family = AF_IPX;
        sipx.sipx_type   = ipxs->type;
+       sipx.sipx_zero   = 0;
        memcpy(uaddr, &sipx, sizeof(sipx));
 
        rc = 0;
@@ -1628,7 +1634,7 @@ out:
        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;
@@ -1643,13 +1649,17 @@ int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
        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;
@@ -1662,7 +1672,7 @@ int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
        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);
@@ -1686,7 +1696,7 @@ static int ipx_sendmsg(struct kiocb *iocb, struct socket *sock,
        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;
@@ -1751,7 +1761,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
                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;
@@ -1778,7 +1788,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
        }
        
        rc = -ENOTCONN;
-       if (sk->sk_zapped)
+       if (sock_flag(sk, SOCK_ZAPPED))
                goto out;
 
        skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
@@ -1797,8 +1807,8 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
                                     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);
 
@@ -1808,6 +1818,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
                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;
 
@@ -1884,13 +1895,36 @@ static int ipx_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                rc = -EINVAL;
                break;
        default:
-               rc = dev_ioctl(cmd, argp);
+               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
  */
@@ -1901,7 +1935,7 @@ static struct net_proto_family ipx_family_ops = {
        .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,
@@ -1912,6 +1946,9 @@ static struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
        .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,
@@ -1940,9 +1977,7 @@ static struct notifier_block ipx_dev_notifier = {
 };
 
 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 };
@@ -1957,6 +1992,11 @@ static char ipx_snap_err_msg[] __initdata =
 
 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();
@@ -1982,7 +2022,8 @@ static int __init ipx_init(void)
        register_netdevice_notifier(&ipx_dev_notifier);
        ipx_register_sysctl();
        ipx_proc_init();
-       return 0;
+out:
+       return rc;
 }
 
 static void __exit ipx_proto_finito(void)
@@ -1994,20 +2035,29 @@ 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);
 }