X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipx%2Faf_ipx.c;h=89f283c51dff7314e2ff6f97ba565618617d7df3;hb=refs%2Fheads%2Fvserver;hp=163223daf47b77a67a17ac47fe71e462b5503e03;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 163223daf..89f283c51 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -28,7 +28,7 @@ * See net/ipx/ChangeLog. */ -#include +#include #include #include #include @@ -44,7 +44,6 @@ #include #include #include -#include #include #include @@ -52,6 +51,7 @@ #include #include #include +#include #include @@ -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); }