X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fdecnet%2Faf_decnet.c;h=07d98695d74db8c549d9ed1569d6f4ca6aff81aa;hb=7172c64a7cee4dfa95864f49c914f7ea8cf497c8;hp=c08a80fd380db6fdf1ab660799d828d842778b6c;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index c08a80fd3..07d98695d 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -99,7 +99,6 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat dn_bind fixes *******************************************************************************/ -#include #include #include #include @@ -118,10 +117,11 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat #include #include #include -#include +#include #include #include #include +#include #include #include #include @@ -149,11 +149,11 @@ static void dn_keepalive(struct sock *sk); #define DN_SK_HASH_MASK (DN_SK_HASH_SIZE - 1) -static kmem_cache_t *dn_sk_cachep; -static struct proto_ops dn_proto_ops; -static rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED; +static const struct proto_ops dn_proto_ops; +static DEFINE_RWLOCK(dn_hash_lock); static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE]; static struct hlist_head dn_wild_sk; +static atomic_t decnet_memory_allocated; static int __dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen, int flags); static int __dn_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen, int flags); @@ -171,7 +171,7 @@ static struct hlist_head *dn_find_list(struct sock *sk) /* * Valid ports are those greater than zero and not already in use. */ -static int check_port(unsigned short port) +static int check_port(__le16 port) { struct sock *sk; struct hlist_node *node; @@ -246,7 +246,7 @@ static void dn_unhash_sock_bh(struct sock *sk) write_unlock_bh(&dn_hash_lock); } -struct hlist_head *listen_hash(struct sockaddr_dn *addr) +static struct hlist_head *listen_hash(struct sockaddr_dn *addr) { int i; unsigned hash = addr->sdn_objnum; @@ -447,21 +447,39 @@ static void dn_destruct(struct sock *sk) dst_release(xchg(&sk->sk_dst_cache, NULL)); } -struct sock *dn_alloc_sock(struct socket *sock, int gfp) +static int dn_memory_pressure; + +static void dn_enter_memory_pressure(void) +{ + if (!dn_memory_pressure) { + dn_memory_pressure = 1; + } +} + +static struct proto dn_proto = { + .name = "NSP", + .owner = THIS_MODULE, + .enter_memory_pressure = dn_enter_memory_pressure, + .memory_pressure = &dn_memory_pressure, + .memory_allocated = &decnet_memory_allocated, + .sysctl_mem = sysctl_decnet_mem, + .sysctl_wmem = sysctl_decnet_wmem, + .sysctl_rmem = sysctl_decnet_rmem, + .max_header = DN_MAX_NSP_DATA_HEADER + 64, + .obj_size = sizeof(struct dn_sock), +}; + +static struct sock *dn_alloc_sock(struct socket *sock, gfp_t gfp) { struct dn_scp *scp; - struct sock *sk = sk_alloc(PF_DECnet, gfp, sizeof(struct dn_sock), - dn_sk_cachep); + struct sock *sk = sk_alloc(PF_DECnet, gfp, &dn_proto, 1); if (!sk) goto out; - sk->sk_protinfo = scp = (struct dn_scp *)(sk + 1); - if (sock) sock->ops = &dn_proto_ops; sock_init_data(sock, sk); - sk_set_owner(sk, THIS_MODULE); sk->sk_backlog_rcv = dn_nsp_backlog_rcv; sk->sk_destruct = dn_destruct; @@ -469,8 +487,11 @@ struct sock *dn_alloc_sock(struct socket *sock, int gfp) sk->sk_family = PF_DECnet; sk->sk_protocol = 0; sk->sk_allocation = gfp; + sk->sk_sndbuf = sysctl_decnet_wmem[1]; + sk->sk_rcvbuf = sysctl_decnet_rmem[1]; /* Initialization of DECnet Session Control Port */ + scp = DN_SK(sk); scp->state = DN_O; /* Open */ scp->numdat = 1; /* Next data seg to tx */ scp->numoth = 1; /* Next oth data to tx */ @@ -534,7 +555,7 @@ static void dn_keepalive(struct sock *sk) * we are double checking that we are not sending too * many of these keepalive frames. */ - if (skb_queue_len(&scp->other_xmit_queue) == 0) + if (skb_queue_empty(&scp->other_xmit_queue)) dn_nsp_send_link(sk, DN_NOCHANGE, 0); } @@ -578,7 +599,6 @@ int dn_destroy_timer(struct sock *sk) if (sk->sk_socket) return 0; - dn_stop_fast_timer(sk); /* unlikely, but possible that this is runninng */ if ((jiffies - scp->stamp) >= (HZ * decnet_time_wait)) { dn_unhash_sock(sk); sock_put(sk); @@ -631,7 +651,6 @@ disc_reject: default: printk(KERN_DEBUG "DECnet: dn_destroy_sock passed socket in invalid state\n"); case DN_O: - dn_stop_fast_timer(sk); dn_stop_slow_timer(sk); dn_unhash_sock_bh(sk); @@ -641,7 +660,7 @@ disc_reject: } } -char *dn_addr2asc(dn_address addr, char *buf) +char *dn_addr2asc(__u16 addr, char *buf) { unsigned short node, area; @@ -719,22 +738,9 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (saddr->sdn_flags & ~SDF_WILD) return -EINVAL; -#if 1 if (!capable(CAP_NET_BIND_SERVICE) && (saddr->sdn_objnum || (saddr->sdn_flags & SDF_WILD))) return -EACCES; -#else - /* - * Maybe put the default actions in the default security ops for - * dn_prot_sock ? Would be nice if the capable call would go there - * too. - */ - if (security_dn_prot_sock(saddr) && - !capable(CAP_NET_BIND_SERVICE) || - saddr->sdn_objnum || (saddr->sdn_flags & SDF_WILD)) - return -EACCES; -#endif - if (!(saddr->sdn_flags & SDF_WILD)) { if (dn_ntohs(saddr->sdn_nodeaddrl)) { @@ -753,14 +759,13 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) rv = -EINVAL; lock_sock(sk); - if (sk->sk_zapped) { + if (sock_flag(sk, SOCK_ZAPPED)) { memcpy(&scp->addr, saddr, addr_len); - sk->sk_zapped = 0; + sock_reset_flag(sk, SOCK_ZAPPED); rv = dn_hash_sock(sk); - if (rv) { - sk->sk_zapped = 1; - } + if (rv) + sock_set_flag(sk, SOCK_ZAPPED); } release_sock(sk); @@ -774,7 +779,7 @@ static int dn_auto_bind(struct socket *sock) struct dn_scp *scp = DN_SK(sk); int rv; - sk->sk_zapped = 0; + sock_reset_flag(sk, SOCK_ZAPPED); scp->addr.sdn_flags = 0; scp->addr.sdn_objnum = 0; @@ -795,18 +800,17 @@ static int dn_auto_bind(struct socket *sock) /* End of compatibility stuff */ scp->addr.sdn_add.a_len = dn_htons(2); - rv = dn_dev_bind_default((dn_address *)scp->addr.sdn_add.a_addr); + rv = dn_dev_bind_default((__le16 *)scp->addr.sdn_add.a_addr); if (rv == 0) { rv = dn_hash_sock(sk); - if (rv) { - sk->sk_zapped = 1; - } + if (rv) + sock_set_flag(sk, SOCK_ZAPPED); } return rv; } -static int dn_confirm_accept(struct sock *sk, long *timeo, int allocation) +static int dn_confirm_accept(struct sock *sk, long *timeo, gfp_t allocation) { struct dn_scp *scp = DN_SK(sk); DEFINE_WAIT(wait); @@ -816,7 +820,7 @@ static int dn_confirm_accept(struct sock *sk, long *timeo, int allocation) return -EINVAL; scp->state = DN_CC; - scp->segsize_loc = dst_path_metric(__sk_dst_get(sk), RTAX_ADVMSS); + scp->segsize_loc = dst_metric(__sk_dst_get(sk), RTAX_ADVMSS); dn_send_conn_conf(sk, allocation); prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); @@ -925,7 +929,7 @@ static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen, if (addr->sdn_flags & SDF_WILD) goto out; - if (sk->sk_zapped) { + if (sock_flag(sk, SOCK_ZAPPED)) { err = dn_auto_bind(sk->sk_socket); if (err) goto out; @@ -945,7 +949,7 @@ static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen, sk->sk_route_caps = sk->sk_dst_cache->dev->features; sock->state = SS_CONNECTING; scp->state = DN_CI; - scp->segsize_loc = dst_path_metric(sk->sk_dst_cache, RTAX_ADVMSS); + scp->segsize_loc = dst_metric(sk->sk_dst_cache, RTAX_ADVMSS); dn_nsp_send_conninit(sk, NSP_CI); err = -EINPROGRESS; @@ -1016,7 +1020,7 @@ static void dn_user_copy(struct sk_buff *skb, struct optdata_dn *opt) opt->opt_optl = *ptr++; opt->opt_status = 0; memcpy(opt->opt_data, ptr, opt->opt_optl); - skb_pull(skb, opt->opt_optl + 1); + skb_pull(skb, dn_ntohs(opt->opt_optl) + 1); } @@ -1075,7 +1079,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) skb = dn_wait_for_connect(sk, &timeo); if (IS_ERR(skb)) { release_sock(sk); - return PTR_ERR(sk); + return PTR_ERR(skb); } } @@ -1116,8 +1120,8 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->addr), &type)); skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->peer), &type)); - *(dn_address *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src; - *(dn_address *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst; + *(__le16 *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src; + *(__le16 *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst; menuver = *skb->data; skb_pull(skb, 1); @@ -1144,7 +1148,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) lock_sock(newsk); err = dn_hash_sock(newsk); if (err == 0) { - newsk->sk_zapped = 0; + sock_reset_flag(newsk, SOCK_ZAPPED); dn_send_conn_ack(newsk); /* @@ -1173,8 +1177,10 @@ static int dn_getname(struct socket *sock, struct sockaddr *uaddr,int *uaddr_len if (peer) { if ((sock->state != SS_CONNECTED && sock->state != SS_CONNECTING) && - scp->accept_mode == ACC_IMMED) + scp->accept_mode == ACC_IMMED) { + release_sock(sk); return -ENOTCONN; + } memcpy(sa, &scp->peer, sizeof(struct sockaddr_dn)); } else { @@ -1193,7 +1199,7 @@ static unsigned int dn_poll(struct file *file, struct socket *sock, poll_table struct dn_scp *scp = DN_SK(sk); int mask = datagram_poll(file, sock, wait); - if (skb_queue_len(&scp->other_receive_queue)) + if (!skb_queue_empty(&scp->other_receive_queue)) mask |= POLLRDBAND; return mask; @@ -1216,7 +1222,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCATMARK: lock_sock(sk); - val = (skb_queue_len(&scp->other_receive_queue) != 0); + val = !skb_queue_empty(&scp->other_receive_queue); if (scp->state != DN_RUN) val = -ENOTCONN; release_sock(sk); @@ -1248,7 +1254,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) break; default: - err = dev_ioctl(cmd, (void __user *)arg); + err = -ENOIOCTLCMD; break; } @@ -1262,7 +1268,7 @@ static int dn_listen(struct socket *sock, int backlog) lock_sock(sk); - if (sk->sk_zapped) + if (sock_flag(sk, SOCK_ZAPPED)) goto out; if ((DN_SK(sk)->state != DN_O) || (sk->sk_state == TCP_LISTEN)) @@ -1360,7 +1366,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us if (optlen != sizeof(struct optdata_dn)) return -EINVAL; - if (u.opt.opt_optl > 16) + if (dn_ntohs(u.opt.opt_optl) > 16) return -EINVAL; memcpy(&scp->conndata_out, &u.opt, optlen); @@ -1373,7 +1379,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us if (optlen != sizeof(struct optdata_dn)) return -EINVAL; - if (u.opt.opt_optl > 16) + if (dn_ntohs(u.opt.opt_optl) > 16) return -EINVAL; memcpy(&scp->discdata_out, &u.opt, optlen); @@ -1632,7 +1638,7 @@ static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int int len = 0; if (flags & MSG_OOB) - return skb_queue_len(q) ? 1 : 0; + return !skb_queue_empty(q) ? 1 : 0; while(skb != (struct sk_buff *)q) { struct dn_skb_cb *cb = DN_SKB_CB(skb); @@ -1674,23 +1680,21 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, lock_sock(sk); - if (sk->sk_zapped) { + if (sock_flag(sk, SOCK_ZAPPED)) { rv = -EADDRNOTAVAIL; goto out; } - rv = dn_check_state(sk, NULL, 0, &timeo, flags); - if (rv) - goto out; - if (sk->sk_shutdown & RCV_SHUTDOWN) { - if (!(flags & MSG_NOSIGNAL)) - send_sig(SIGPIPE, current, 0); - rv = -EPIPE; + rv = 0; goto out; } - if (flags & ~(MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT|MSG_NOSIGNAL)) { + rv = dn_check_state(sk, NULL, 0, &timeo, flags); + if (rv) + goto out; + + if (flags & ~(MSG_CMSG_COMPAT|MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT|MSG_NOSIGNAL)) { rv = -EOPNOTSUPP; goto out; } @@ -1709,7 +1713,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, if (sk->sk_err) goto out; - if (skb_queue_len(&scp->other_receive_queue)) { + if (!skb_queue_empty(&scp->other_receive_queue)) { if (!(flags & MSG_OOB)) { msg->msg_flags |= MSG_OOB; if (!scp->other_report) { @@ -1723,7 +1727,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; if (signal_pending(current)) { - rv = -ERESTARTSYS; + rv = sock_intr_errno(timeo); goto out; } @@ -1765,7 +1769,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, nskb = skb->next; if (skb->len == 0) { - skb_unlink(skb); + skb_unlink(skb, queue); kfree_skb(skb); /* * N.B. Don't refer to skb or cb after this point @@ -1871,24 +1875,34 @@ static inline unsigned int dn_current_mss(struct sock *sk, int flags) /* This works out the maximum size of segment we can send out */ if (dst) { - u32 mtu = dst_pmtu(dst); + u32 mtu = dst_mtu(dst); mss_now = min_t(int, dn_mss_from_pmtu(dst->dev, mtu), mss_now); } return mss_now; } -static int dn_error(struct sock *sk, int flags, int err) +/* + * N.B. We get the timeout wrong here, but then we always did get it + * wrong before and this is another step along the road to correcting + * it. It ought to get updated each time we pass through the routine, + * but in practise it probably doesn't matter too much for now. + */ +static inline struct sk_buff *dn_alloc_send_pskb(struct sock *sk, + unsigned long datalen, int noblock, + int *errcode) { - if (err == -EPIPE) - err = sock_error(sk) ? : -EPIPE; - if (err == -EPIPE && !(flags & MSG_NOSIGNAL)) - send_sig(SIGPIPE, current, 0); - return err; + struct sk_buff *skb = sock_alloc_send_skb(sk, datalen, + noblock, errcode); + if (skb) { + skb->protocol = __constant_htons(ETH_P_DNA_RT); + skb->pkt_type = PACKET_OUTGOING; + } + return skb; } static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t size) + struct msghdr *msg, size_t size) { struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); @@ -1903,7 +1917,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, struct dn_skb_cb *cb; size_t len; unsigned char fctype; - long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); + long timeo; if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE|MSG_CMSG_COMPAT)) return -EOPNOTSUPP; @@ -1911,18 +1925,21 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, if (addr_len && (addr_len != sizeof(struct sockaddr_dn))) return -EINVAL; + lock_sock(sk); + timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); /* * The only difference between stream sockets and sequenced packet * sockets is that the stream sockets always behave as if MSG_EOR * has been set. */ if (sock->type == SOCK_STREAM) { - if (flags & MSG_EOR) - return -EINVAL; + if (flags & MSG_EOR) { + err = -EINVAL; + goto out; + } flags |= MSG_EOR; } - lock_sock(sk); err = dn_check_state(sk, addr, addr_len, &timeo, flags); if (err) @@ -1930,6 +1947,8 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, if (sk->sk_shutdown & SEND_SHUTDOWN) { err = -EPIPE; + if (!(flags & MSG_NOSIGNAL)) + send_sig(SIGPIPE, current, 0); goto out_err; } @@ -1957,7 +1976,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, goto out; if (signal_pending(current)) { - err = -ERESTARTSYS; + err = sock_intr_errno(timeo); goto out; } @@ -1991,8 +2010,12 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, /* * Get a suitably sized skb. + * 64 is a bit of a hack really, but its larger than any + * link-layer headers and has served us well as a good + * guess as to their real length. */ - skb = dn_alloc_send_skb(sk, &len, flags & MSG_DONTWAIT, &err); + skb = dn_alloc_send_pskb(sk, len + 64 + DN_MAX_NSP_DATA_HEADER, + flags & MSG_DONTWAIT, &err); if (err) break; @@ -2002,7 +2025,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, cb = DN_SKB_CB(skb); - skb_reserve(skb, DN_MAX_NSP_DATA_HEADER); + skb_reserve(skb, 64 + DN_MAX_NSP_DATA_HEADER); if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { err = -EFAULT; @@ -2047,7 +2070,7 @@ out: return sent ? sent : err; out_err: - err = dn_error(sk, flags, err); + err = sk_stream_error(sk, flags, err); release_sock(sk); return err; } @@ -2075,7 +2098,7 @@ static struct notifier_block dn_dev_notifier = { .notifier_call = dn_device_event, }; -extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *); +extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); static struct packet_type dn_dix_packet_type = { .type = __constant_htons(ETH_P_DNA_RT), @@ -2321,7 +2344,7 @@ static struct net_proto_family dn_family_ops = { .owner = THIS_MODULE, }; -static struct proto_ops dn_proto_ops = { +static const struct proto_ops dn_proto_ops = { .family = AF_DECnet, .owner = THIS_MODULE, .release = dn_release, @@ -2354,14 +2377,13 @@ static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.68s ( static int __init decnet_init(void) { + int rc; + printk(banner); - dn_sk_cachep = kmem_cache_create("decnet_socket_cache", - sizeof(struct dn_sock), - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); - if (!dn_sk_cachep) - return -ENOMEM; + rc = proto_register(&dn_proto, 1); + if (rc != 0) + goto out; dn_neigh_init(); dn_dev_init(); @@ -2374,8 +2396,8 @@ static int __init decnet_init(void) proc_net_fops_create("decnet", S_IRUGO, &dn_socket_seq_fops); dn_register_sysctl(); - - return 0; +out: + return rc; } module_init(decnet_init); @@ -2402,7 +2424,7 @@ static void __exit decnet_exit(void) proc_net_remove("decnet"); - kmem_cache_destroy(dn_sk_cachep); + proto_unregister(&dn_proto); } module_exit(decnet_exit); #endif