1*7c657876SArnaldo Carvalho de Melo /* 2*7c657876SArnaldo Carvalho de Melo * net/dccp/proto.c 3*7c657876SArnaldo Carvalho de Melo * 4*7c657876SArnaldo Carvalho de Melo * An implementation of the DCCP protocol 5*7c657876SArnaldo Carvalho de Melo * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 6*7c657876SArnaldo Carvalho de Melo * 7*7c657876SArnaldo Carvalho de Melo * This program is free software; you can redistribute it and/or modify it 8*7c657876SArnaldo Carvalho de Melo * under the terms of the GNU General Public License version 2 as 9*7c657876SArnaldo Carvalho de Melo * published by the Free Software Foundation. 10*7c657876SArnaldo Carvalho de Melo */ 11*7c657876SArnaldo Carvalho de Melo 12*7c657876SArnaldo Carvalho de Melo #include <linux/config.h> 13*7c657876SArnaldo Carvalho de Melo #include <linux/dccp.h> 14*7c657876SArnaldo Carvalho de Melo #include <linux/module.h> 15*7c657876SArnaldo Carvalho de Melo #include <linux/types.h> 16*7c657876SArnaldo Carvalho de Melo #include <linux/sched.h> 17*7c657876SArnaldo Carvalho de Melo #include <linux/kernel.h> 18*7c657876SArnaldo Carvalho de Melo #include <linux/skbuff.h> 19*7c657876SArnaldo Carvalho de Melo #include <linux/netdevice.h> 20*7c657876SArnaldo Carvalho de Melo #include <linux/in.h> 21*7c657876SArnaldo Carvalho de Melo #include <linux/if_arp.h> 22*7c657876SArnaldo Carvalho de Melo #include <linux/init.h> 23*7c657876SArnaldo Carvalho de Melo #include <linux/random.h> 24*7c657876SArnaldo Carvalho de Melo #include <net/checksum.h> 25*7c657876SArnaldo Carvalho de Melo 26*7c657876SArnaldo Carvalho de Melo #include <net/inet_common.h> 27*7c657876SArnaldo Carvalho de Melo #include <net/ip.h> 28*7c657876SArnaldo Carvalho de Melo #include <net/protocol.h> 29*7c657876SArnaldo Carvalho de Melo #include <net/sock.h> 30*7c657876SArnaldo Carvalho de Melo #include <net/xfrm.h> 31*7c657876SArnaldo Carvalho de Melo 32*7c657876SArnaldo Carvalho de Melo #include <asm/semaphore.h> 33*7c657876SArnaldo Carvalho de Melo #include <linux/spinlock.h> 34*7c657876SArnaldo Carvalho de Melo #include <linux/timer.h> 35*7c657876SArnaldo Carvalho de Melo #include <linux/delay.h> 36*7c657876SArnaldo Carvalho de Melo #include <linux/poll.h> 37*7c657876SArnaldo Carvalho de Melo #include <linux/dccp.h> 38*7c657876SArnaldo Carvalho de Melo 39*7c657876SArnaldo Carvalho de Melo #include "ccid.h" 40*7c657876SArnaldo Carvalho de Melo #include "dccp.h" 41*7c657876SArnaldo Carvalho de Melo 42*7c657876SArnaldo Carvalho de Melo DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics); 43*7c657876SArnaldo Carvalho de Melo 44*7c657876SArnaldo Carvalho de Melo atomic_t dccp_orphan_count = ATOMIC_INIT(0); 45*7c657876SArnaldo Carvalho de Melo 46*7c657876SArnaldo Carvalho de Melo static struct net_protocol dccp_protocol = { 47*7c657876SArnaldo Carvalho de Melo .handler = dccp_v4_rcv, 48*7c657876SArnaldo Carvalho de Melo .err_handler = dccp_v4_err, 49*7c657876SArnaldo Carvalho de Melo }; 50*7c657876SArnaldo Carvalho de Melo 51*7c657876SArnaldo Carvalho de Melo const char *dccp_packet_name(const int type) 52*7c657876SArnaldo Carvalho de Melo { 53*7c657876SArnaldo Carvalho de Melo static const char *dccp_packet_names[] = { 54*7c657876SArnaldo Carvalho de Melo [DCCP_PKT_REQUEST] = "REQUEST", 55*7c657876SArnaldo Carvalho de Melo [DCCP_PKT_RESPONSE] = "RESPONSE", 56*7c657876SArnaldo Carvalho de Melo [DCCP_PKT_DATA] = "DATA", 57*7c657876SArnaldo Carvalho de Melo [DCCP_PKT_ACK] = "ACK", 58*7c657876SArnaldo Carvalho de Melo [DCCP_PKT_DATAACK] = "DATAACK", 59*7c657876SArnaldo Carvalho de Melo [DCCP_PKT_CLOSEREQ] = "CLOSEREQ", 60*7c657876SArnaldo Carvalho de Melo [DCCP_PKT_CLOSE] = "CLOSE", 61*7c657876SArnaldo Carvalho de Melo [DCCP_PKT_RESET] = "RESET", 62*7c657876SArnaldo Carvalho de Melo [DCCP_PKT_SYNC] = "SYNC", 63*7c657876SArnaldo Carvalho de Melo [DCCP_PKT_SYNCACK] = "SYNCACK", 64*7c657876SArnaldo Carvalho de Melo }; 65*7c657876SArnaldo Carvalho de Melo 66*7c657876SArnaldo Carvalho de Melo if (type >= DCCP_NR_PKT_TYPES) 67*7c657876SArnaldo Carvalho de Melo return "INVALID"; 68*7c657876SArnaldo Carvalho de Melo else 69*7c657876SArnaldo Carvalho de Melo return dccp_packet_names[type]; 70*7c657876SArnaldo Carvalho de Melo } 71*7c657876SArnaldo Carvalho de Melo 72*7c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(dccp_packet_name); 73*7c657876SArnaldo Carvalho de Melo 74*7c657876SArnaldo Carvalho de Melo const char *dccp_state_name(const int state) 75*7c657876SArnaldo Carvalho de Melo { 76*7c657876SArnaldo Carvalho de Melo static char *dccp_state_names[] = { 77*7c657876SArnaldo Carvalho de Melo [DCCP_OPEN] = "OPEN", 78*7c657876SArnaldo Carvalho de Melo [DCCP_REQUESTING] = "REQUESTING", 79*7c657876SArnaldo Carvalho de Melo [DCCP_PARTOPEN] = "PARTOPEN", 80*7c657876SArnaldo Carvalho de Melo [DCCP_LISTEN] = "LISTEN", 81*7c657876SArnaldo Carvalho de Melo [DCCP_RESPOND] = "RESPOND", 82*7c657876SArnaldo Carvalho de Melo [DCCP_CLOSING] = "CLOSING", 83*7c657876SArnaldo Carvalho de Melo [DCCP_TIME_WAIT] = "TIME_WAIT", 84*7c657876SArnaldo Carvalho de Melo [DCCP_CLOSED] = "CLOSED", 85*7c657876SArnaldo Carvalho de Melo }; 86*7c657876SArnaldo Carvalho de Melo 87*7c657876SArnaldo Carvalho de Melo if (state >= DCCP_MAX_STATES) 88*7c657876SArnaldo Carvalho de Melo return "INVALID STATE!"; 89*7c657876SArnaldo Carvalho de Melo else 90*7c657876SArnaldo Carvalho de Melo return dccp_state_names[state]; 91*7c657876SArnaldo Carvalho de Melo } 92*7c657876SArnaldo Carvalho de Melo 93*7c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(dccp_state_name); 94*7c657876SArnaldo Carvalho de Melo 95*7c657876SArnaldo Carvalho de Melo static inline int dccp_listen_start(struct sock *sk) 96*7c657876SArnaldo Carvalho de Melo { 97*7c657876SArnaldo Carvalho de Melo dccp_sk(sk)->dccps_role = DCCP_ROLE_LISTEN; 98*7c657876SArnaldo Carvalho de Melo return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE); 99*7c657876SArnaldo Carvalho de Melo } 100*7c657876SArnaldo Carvalho de Melo 101*7c657876SArnaldo Carvalho de Melo int dccp_disconnect(struct sock *sk, int flags) 102*7c657876SArnaldo Carvalho de Melo { 103*7c657876SArnaldo Carvalho de Melo struct inet_connection_sock *icsk = inet_csk(sk); 104*7c657876SArnaldo Carvalho de Melo struct inet_sock *inet = inet_sk(sk); 105*7c657876SArnaldo Carvalho de Melo int err = 0; 106*7c657876SArnaldo Carvalho de Melo const int old_state = sk->sk_state; 107*7c657876SArnaldo Carvalho de Melo 108*7c657876SArnaldo Carvalho de Melo if (old_state != DCCP_CLOSED) 109*7c657876SArnaldo Carvalho de Melo dccp_set_state(sk, DCCP_CLOSED); 110*7c657876SArnaldo Carvalho de Melo 111*7c657876SArnaldo Carvalho de Melo /* ABORT function of RFC793 */ 112*7c657876SArnaldo Carvalho de Melo if (old_state == DCCP_LISTEN) { 113*7c657876SArnaldo Carvalho de Melo inet_csk_listen_stop(sk); 114*7c657876SArnaldo Carvalho de Melo /* FIXME: do the active reset thing */ 115*7c657876SArnaldo Carvalho de Melo } else if (old_state == DCCP_REQUESTING) 116*7c657876SArnaldo Carvalho de Melo sk->sk_err = ECONNRESET; 117*7c657876SArnaldo Carvalho de Melo 118*7c657876SArnaldo Carvalho de Melo dccp_clear_xmit_timers(sk); 119*7c657876SArnaldo Carvalho de Melo __skb_queue_purge(&sk->sk_receive_queue); 120*7c657876SArnaldo Carvalho de Melo if (sk->sk_send_head != NULL) { 121*7c657876SArnaldo Carvalho de Melo __kfree_skb(sk->sk_send_head); 122*7c657876SArnaldo Carvalho de Melo sk->sk_send_head = NULL; 123*7c657876SArnaldo Carvalho de Melo } 124*7c657876SArnaldo Carvalho de Melo 125*7c657876SArnaldo Carvalho de Melo inet->dport = 0; 126*7c657876SArnaldo Carvalho de Melo 127*7c657876SArnaldo Carvalho de Melo if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) 128*7c657876SArnaldo Carvalho de Melo inet_reset_saddr(sk); 129*7c657876SArnaldo Carvalho de Melo 130*7c657876SArnaldo Carvalho de Melo sk->sk_shutdown = 0; 131*7c657876SArnaldo Carvalho de Melo sock_reset_flag(sk, SOCK_DONE); 132*7c657876SArnaldo Carvalho de Melo 133*7c657876SArnaldo Carvalho de Melo icsk->icsk_backoff = 0; 134*7c657876SArnaldo Carvalho de Melo inet_csk_delack_init(sk); 135*7c657876SArnaldo Carvalho de Melo __sk_dst_reset(sk); 136*7c657876SArnaldo Carvalho de Melo 137*7c657876SArnaldo Carvalho de Melo BUG_TRAP(!inet->num || icsk->icsk_bind_hash); 138*7c657876SArnaldo Carvalho de Melo 139*7c657876SArnaldo Carvalho de Melo sk->sk_error_report(sk); 140*7c657876SArnaldo Carvalho de Melo return err; 141*7c657876SArnaldo Carvalho de Melo } 142*7c657876SArnaldo Carvalho de Melo 143*7c657876SArnaldo Carvalho de Melo int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg) 144*7c657876SArnaldo Carvalho de Melo { 145*7c657876SArnaldo Carvalho de Melo dccp_pr_debug("entry\n"); 146*7c657876SArnaldo Carvalho de Melo return -ENOIOCTLCMD; 147*7c657876SArnaldo Carvalho de Melo } 148*7c657876SArnaldo Carvalho de Melo 149*7c657876SArnaldo Carvalho de Melo int dccp_setsockopt(struct sock *sk, int level, int optname, 150*7c657876SArnaldo Carvalho de Melo char *optval, int optlen) 151*7c657876SArnaldo Carvalho de Melo { 152*7c657876SArnaldo Carvalho de Melo dccp_pr_debug("entry\n"); 153*7c657876SArnaldo Carvalho de Melo 154*7c657876SArnaldo Carvalho de Melo if (level != SOL_DCCP) 155*7c657876SArnaldo Carvalho de Melo return ip_setsockopt(sk, level, optname, optval, optlen); 156*7c657876SArnaldo Carvalho de Melo 157*7c657876SArnaldo Carvalho de Melo return -EOPNOTSUPP; 158*7c657876SArnaldo Carvalho de Melo } 159*7c657876SArnaldo Carvalho de Melo 160*7c657876SArnaldo Carvalho de Melo int dccp_getsockopt(struct sock *sk, int level, int optname, 161*7c657876SArnaldo Carvalho de Melo char *optval, int *optlen) 162*7c657876SArnaldo Carvalho de Melo { 163*7c657876SArnaldo Carvalho de Melo dccp_pr_debug("entry\n"); 164*7c657876SArnaldo Carvalho de Melo 165*7c657876SArnaldo Carvalho de Melo if (level != SOL_DCCP) 166*7c657876SArnaldo Carvalho de Melo return ip_getsockopt(sk, level, optname, optval, optlen); 167*7c657876SArnaldo Carvalho de Melo 168*7c657876SArnaldo Carvalho de Melo return -EOPNOTSUPP; 169*7c657876SArnaldo Carvalho de Melo } 170*7c657876SArnaldo Carvalho de Melo 171*7c657876SArnaldo Carvalho de Melo int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 172*7c657876SArnaldo Carvalho de Melo size_t len) 173*7c657876SArnaldo Carvalho de Melo { 174*7c657876SArnaldo Carvalho de Melo const struct dccp_sock *dp = dccp_sk(sk); 175*7c657876SArnaldo Carvalho de Melo const int flags = msg->msg_flags; 176*7c657876SArnaldo Carvalho de Melo const int noblock = flags & MSG_DONTWAIT; 177*7c657876SArnaldo Carvalho de Melo struct sk_buff *skb; 178*7c657876SArnaldo Carvalho de Melo int rc, size; 179*7c657876SArnaldo Carvalho de Melo long timeo; 180*7c657876SArnaldo Carvalho de Melo 181*7c657876SArnaldo Carvalho de Melo if (len > dp->dccps_mss_cache) 182*7c657876SArnaldo Carvalho de Melo return -EMSGSIZE; 183*7c657876SArnaldo Carvalho de Melo 184*7c657876SArnaldo Carvalho de Melo lock_sock(sk); 185*7c657876SArnaldo Carvalho de Melo 186*7c657876SArnaldo Carvalho de Melo timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); 187*7c657876SArnaldo Carvalho de Melo 188*7c657876SArnaldo Carvalho de Melo /* 189*7c657876SArnaldo Carvalho de Melo * We have to use sk_stream_wait_connect here to set sk_write_pending, 190*7c657876SArnaldo Carvalho de Melo * so that the trick in dccp_rcv_request_sent_state_process. 191*7c657876SArnaldo Carvalho de Melo */ 192*7c657876SArnaldo Carvalho de Melo /* Wait for a connection to finish. */ 193*7c657876SArnaldo Carvalho de Melo if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN | DCCPF_CLOSING)) 194*7c657876SArnaldo Carvalho de Melo if ((rc = sk_stream_wait_connect(sk, &timeo)) != 0) 195*7c657876SArnaldo Carvalho de Melo goto out_err; 196*7c657876SArnaldo Carvalho de Melo 197*7c657876SArnaldo Carvalho de Melo size = sk->sk_prot->max_header + len; 198*7c657876SArnaldo Carvalho de Melo release_sock(sk); 199*7c657876SArnaldo Carvalho de Melo skb = sock_alloc_send_skb(sk, size, noblock, &rc); 200*7c657876SArnaldo Carvalho de Melo lock_sock(sk); 201*7c657876SArnaldo Carvalho de Melo 202*7c657876SArnaldo Carvalho de Melo if (skb == NULL) 203*7c657876SArnaldo Carvalho de Melo goto out_release; 204*7c657876SArnaldo Carvalho de Melo 205*7c657876SArnaldo Carvalho de Melo skb_reserve(skb, sk->sk_prot->max_header); 206*7c657876SArnaldo Carvalho de Melo rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); 207*7c657876SArnaldo Carvalho de Melo if (rc == 0) { 208*7c657876SArnaldo Carvalho de Melo struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); 209*7c657876SArnaldo Carvalho de Melo const struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts; 210*7c657876SArnaldo Carvalho de Melo long delay; 211*7c657876SArnaldo Carvalho de Melo 212*7c657876SArnaldo Carvalho de Melo /* 213*7c657876SArnaldo Carvalho de Melo * XXX: This is just to match the Waikato tree CA interaction 214*7c657876SArnaldo Carvalho de Melo * points, after the CCID3 code is stable and I have a better 215*7c657876SArnaldo Carvalho de Melo * understanding of behaviour I'll change this to look more like 216*7c657876SArnaldo Carvalho de Melo * TCP. 217*7c657876SArnaldo Carvalho de Melo */ 218*7c657876SArnaldo Carvalho de Melo while (1) { 219*7c657876SArnaldo Carvalho de Melo rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, 220*7c657876SArnaldo Carvalho de Melo skb, len, &delay); 221*7c657876SArnaldo Carvalho de Melo if (rc == 0) 222*7c657876SArnaldo Carvalho de Melo break; 223*7c657876SArnaldo Carvalho de Melo if (rc != -EAGAIN) 224*7c657876SArnaldo Carvalho de Melo goto out_discard; 225*7c657876SArnaldo Carvalho de Melo if (delay > timeo) 226*7c657876SArnaldo Carvalho de Melo goto out_discard; 227*7c657876SArnaldo Carvalho de Melo release_sock(sk); 228*7c657876SArnaldo Carvalho de Melo delay = schedule_timeout(delay); 229*7c657876SArnaldo Carvalho de Melo lock_sock(sk); 230*7c657876SArnaldo Carvalho de Melo timeo -= delay; 231*7c657876SArnaldo Carvalho de Melo if (signal_pending(current)) 232*7c657876SArnaldo Carvalho de Melo goto out_interrupted; 233*7c657876SArnaldo Carvalho de Melo rc = -EPIPE; 234*7c657876SArnaldo Carvalho de Melo if (!(sk->sk_state == DCCP_PARTOPEN || sk->sk_state == DCCP_OPEN)) 235*7c657876SArnaldo Carvalho de Melo goto out_discard; 236*7c657876SArnaldo Carvalho de Melo } 237*7c657876SArnaldo Carvalho de Melo 238*7c657876SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_PARTOPEN) { 239*7c657876SArnaldo Carvalho de Melo /* See 8.1.5. Handshake Completion */ 240*7c657876SArnaldo Carvalho de Melo inet_csk_schedule_ack(sk); 241*7c657876SArnaldo Carvalho de Melo inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, inet_csk(sk)->icsk_rto, TCP_RTO_MAX); 242*7c657876SArnaldo Carvalho de Melo dcb->dccpd_type = DCCP_PKT_DATAACK; 243*7c657876SArnaldo Carvalho de Melo /* FIXME: we really should have a dccps_ack_pending or use icsk */ 244*7c657876SArnaldo Carvalho de Melo } else if (inet_csk_ack_scheduled(sk) || 245*7c657876SArnaldo Carvalho de Melo (dp->dccps_options.dccpo_send_ack_vector && 246*7c657876SArnaldo Carvalho de Melo ap->dccpap_buf_ackno != DCCP_MAX_SEQNO + 1 && 247*7c657876SArnaldo Carvalho de Melo ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1)) 248*7c657876SArnaldo Carvalho de Melo dcb->dccpd_type = DCCP_PKT_DATAACK; 249*7c657876SArnaldo Carvalho de Melo else 250*7c657876SArnaldo Carvalho de Melo dcb->dccpd_type = DCCP_PKT_DATA; 251*7c657876SArnaldo Carvalho de Melo dccp_transmit_skb(sk, skb); 252*7c657876SArnaldo Carvalho de Melo ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len); 253*7c657876SArnaldo Carvalho de Melo } else { 254*7c657876SArnaldo Carvalho de Melo out_discard: 255*7c657876SArnaldo Carvalho de Melo kfree_skb(skb); 256*7c657876SArnaldo Carvalho de Melo } 257*7c657876SArnaldo Carvalho de Melo out_release: 258*7c657876SArnaldo Carvalho de Melo release_sock(sk); 259*7c657876SArnaldo Carvalho de Melo return rc ? : len; 260*7c657876SArnaldo Carvalho de Melo out_err: 261*7c657876SArnaldo Carvalho de Melo rc = sk_stream_error(sk, flags, rc); 262*7c657876SArnaldo Carvalho de Melo goto out_release; 263*7c657876SArnaldo Carvalho de Melo out_interrupted: 264*7c657876SArnaldo Carvalho de Melo rc = sock_intr_errno(timeo); 265*7c657876SArnaldo Carvalho de Melo goto out_discard; 266*7c657876SArnaldo Carvalho de Melo } 267*7c657876SArnaldo Carvalho de Melo 268*7c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL(dccp_sendmsg); 269*7c657876SArnaldo Carvalho de Melo 270*7c657876SArnaldo Carvalho de Melo int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 271*7c657876SArnaldo Carvalho de Melo size_t len, int nonblock, int flags, int *addr_len) 272*7c657876SArnaldo Carvalho de Melo { 273*7c657876SArnaldo Carvalho de Melo const struct dccp_hdr *dh; 274*7c657876SArnaldo Carvalho de Melo int copied = 0; 275*7c657876SArnaldo Carvalho de Melo unsigned long used; 276*7c657876SArnaldo Carvalho de Melo int err; 277*7c657876SArnaldo Carvalho de Melo int target; /* Read at least this many bytes */ 278*7c657876SArnaldo Carvalho de Melo long timeo; 279*7c657876SArnaldo Carvalho de Melo 280*7c657876SArnaldo Carvalho de Melo lock_sock(sk); 281*7c657876SArnaldo Carvalho de Melo 282*7c657876SArnaldo Carvalho de Melo err = -ENOTCONN; 283*7c657876SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_LISTEN) 284*7c657876SArnaldo Carvalho de Melo goto out; 285*7c657876SArnaldo Carvalho de Melo 286*7c657876SArnaldo Carvalho de Melo timeo = sock_rcvtimeo(sk, nonblock); 287*7c657876SArnaldo Carvalho de Melo 288*7c657876SArnaldo Carvalho de Melo /* Urgent data needs to be handled specially. */ 289*7c657876SArnaldo Carvalho de Melo if (flags & MSG_OOB) 290*7c657876SArnaldo Carvalho de Melo goto recv_urg; 291*7c657876SArnaldo Carvalho de Melo 292*7c657876SArnaldo Carvalho de Melo /* FIXME */ 293*7c657876SArnaldo Carvalho de Melo #if 0 294*7c657876SArnaldo Carvalho de Melo seq = &tp->copied_seq; 295*7c657876SArnaldo Carvalho de Melo if (flags & MSG_PEEK) { 296*7c657876SArnaldo Carvalho de Melo peek_seq = tp->copied_seq; 297*7c657876SArnaldo Carvalho de Melo seq = &peek_seq; 298*7c657876SArnaldo Carvalho de Melo } 299*7c657876SArnaldo Carvalho de Melo #endif 300*7c657876SArnaldo Carvalho de Melo 301*7c657876SArnaldo Carvalho de Melo target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); 302*7c657876SArnaldo Carvalho de Melo 303*7c657876SArnaldo Carvalho de Melo do { 304*7c657876SArnaldo Carvalho de Melo struct sk_buff *skb; 305*7c657876SArnaldo Carvalho de Melo u32 offset; 306*7c657876SArnaldo Carvalho de Melo 307*7c657876SArnaldo Carvalho de Melo /* FIXME */ 308*7c657876SArnaldo Carvalho de Melo #if 0 309*7c657876SArnaldo Carvalho de Melo /* Are we at urgent data? Stop if we have read anything or have SIGURG pending. */ 310*7c657876SArnaldo Carvalho de Melo if (tp->urg_data && tp->urg_seq == *seq) { 311*7c657876SArnaldo Carvalho de Melo if (copied) 312*7c657876SArnaldo Carvalho de Melo break; 313*7c657876SArnaldo Carvalho de Melo if (signal_pending(current)) { 314*7c657876SArnaldo Carvalho de Melo copied = timeo ? sock_intr_errno(timeo) : -EAGAIN; 315*7c657876SArnaldo Carvalho de Melo break; 316*7c657876SArnaldo Carvalho de Melo } 317*7c657876SArnaldo Carvalho de Melo } 318*7c657876SArnaldo Carvalho de Melo #endif 319*7c657876SArnaldo Carvalho de Melo 320*7c657876SArnaldo Carvalho de Melo /* Next get a buffer. */ 321*7c657876SArnaldo Carvalho de Melo 322*7c657876SArnaldo Carvalho de Melo skb = skb_peek(&sk->sk_receive_queue); 323*7c657876SArnaldo Carvalho de Melo do { 324*7c657876SArnaldo Carvalho de Melo if (!skb) 325*7c657876SArnaldo Carvalho de Melo break; 326*7c657876SArnaldo Carvalho de Melo 327*7c657876SArnaldo Carvalho de Melo offset = 0; 328*7c657876SArnaldo Carvalho de Melo dh = dccp_hdr(skb); 329*7c657876SArnaldo Carvalho de Melo 330*7c657876SArnaldo Carvalho de Melo if (dh->dccph_type == DCCP_PKT_DATA || 331*7c657876SArnaldo Carvalho de Melo dh->dccph_type == DCCP_PKT_DATAACK) 332*7c657876SArnaldo Carvalho de Melo goto found_ok_skb; 333*7c657876SArnaldo Carvalho de Melo 334*7c657876SArnaldo Carvalho de Melo if (dh->dccph_type == DCCP_PKT_RESET || 335*7c657876SArnaldo Carvalho de Melo dh->dccph_type == DCCP_PKT_CLOSE) { 336*7c657876SArnaldo Carvalho de Melo dccp_pr_debug("found fin ok!\n"); 337*7c657876SArnaldo Carvalho de Melo goto found_fin_ok; 338*7c657876SArnaldo Carvalho de Melo } 339*7c657876SArnaldo Carvalho de Melo dccp_pr_debug("packet_type=%s\n", dccp_packet_name(dh->dccph_type)); 340*7c657876SArnaldo Carvalho de Melo BUG_TRAP(flags & MSG_PEEK); 341*7c657876SArnaldo Carvalho de Melo skb = skb->next; 342*7c657876SArnaldo Carvalho de Melo } while (skb != (struct sk_buff *)&sk->sk_receive_queue); 343*7c657876SArnaldo Carvalho de Melo 344*7c657876SArnaldo Carvalho de Melo /* Well, if we have backlog, try to process it now yet. */ 345*7c657876SArnaldo Carvalho de Melo if (copied >= target && !sk->sk_backlog.tail) 346*7c657876SArnaldo Carvalho de Melo break; 347*7c657876SArnaldo Carvalho de Melo 348*7c657876SArnaldo Carvalho de Melo if (copied) { 349*7c657876SArnaldo Carvalho de Melo if (sk->sk_err || 350*7c657876SArnaldo Carvalho de Melo sk->sk_state == DCCP_CLOSED || 351*7c657876SArnaldo Carvalho de Melo (sk->sk_shutdown & RCV_SHUTDOWN) || 352*7c657876SArnaldo Carvalho de Melo !timeo || 353*7c657876SArnaldo Carvalho de Melo signal_pending(current) || 354*7c657876SArnaldo Carvalho de Melo (flags & MSG_PEEK)) 355*7c657876SArnaldo Carvalho de Melo break; 356*7c657876SArnaldo Carvalho de Melo } else { 357*7c657876SArnaldo Carvalho de Melo if (sock_flag(sk, SOCK_DONE)) 358*7c657876SArnaldo Carvalho de Melo break; 359*7c657876SArnaldo Carvalho de Melo 360*7c657876SArnaldo Carvalho de Melo if (sk->sk_err) { 361*7c657876SArnaldo Carvalho de Melo copied = sock_error(sk); 362*7c657876SArnaldo Carvalho de Melo break; 363*7c657876SArnaldo Carvalho de Melo } 364*7c657876SArnaldo Carvalho de Melo 365*7c657876SArnaldo Carvalho de Melo if (sk->sk_shutdown & RCV_SHUTDOWN) 366*7c657876SArnaldo Carvalho de Melo break; 367*7c657876SArnaldo Carvalho de Melo 368*7c657876SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_CLOSED) { 369*7c657876SArnaldo Carvalho de Melo if (!sock_flag(sk, SOCK_DONE)) { 370*7c657876SArnaldo Carvalho de Melo /* This occurs when user tries to read 371*7c657876SArnaldo Carvalho de Melo * from never connected socket. 372*7c657876SArnaldo Carvalho de Melo */ 373*7c657876SArnaldo Carvalho de Melo copied = -ENOTCONN; 374*7c657876SArnaldo Carvalho de Melo break; 375*7c657876SArnaldo Carvalho de Melo } 376*7c657876SArnaldo Carvalho de Melo break; 377*7c657876SArnaldo Carvalho de Melo } 378*7c657876SArnaldo Carvalho de Melo 379*7c657876SArnaldo Carvalho de Melo if (!timeo) { 380*7c657876SArnaldo Carvalho de Melo copied = -EAGAIN; 381*7c657876SArnaldo Carvalho de Melo break; 382*7c657876SArnaldo Carvalho de Melo } 383*7c657876SArnaldo Carvalho de Melo 384*7c657876SArnaldo Carvalho de Melo if (signal_pending(current)) { 385*7c657876SArnaldo Carvalho de Melo copied = sock_intr_errno(timeo); 386*7c657876SArnaldo Carvalho de Melo break; 387*7c657876SArnaldo Carvalho de Melo } 388*7c657876SArnaldo Carvalho de Melo } 389*7c657876SArnaldo Carvalho de Melo 390*7c657876SArnaldo Carvalho de Melo /* FIXME: cleanup_rbuf(sk, copied); */ 391*7c657876SArnaldo Carvalho de Melo 392*7c657876SArnaldo Carvalho de Melo if (copied >= target) { 393*7c657876SArnaldo Carvalho de Melo /* Do not sleep, just process backlog. */ 394*7c657876SArnaldo Carvalho de Melo release_sock(sk); 395*7c657876SArnaldo Carvalho de Melo lock_sock(sk); 396*7c657876SArnaldo Carvalho de Melo } else 397*7c657876SArnaldo Carvalho de Melo sk_wait_data(sk, &timeo); 398*7c657876SArnaldo Carvalho de Melo 399*7c657876SArnaldo Carvalho de Melo continue; 400*7c657876SArnaldo Carvalho de Melo 401*7c657876SArnaldo Carvalho de Melo found_ok_skb: 402*7c657876SArnaldo Carvalho de Melo /* Ok so how much can we use? */ 403*7c657876SArnaldo Carvalho de Melo used = skb->len - offset; 404*7c657876SArnaldo Carvalho de Melo if (len < used) 405*7c657876SArnaldo Carvalho de Melo used = len; 406*7c657876SArnaldo Carvalho de Melo 407*7c657876SArnaldo Carvalho de Melo if (!(flags & MSG_TRUNC)) { 408*7c657876SArnaldo Carvalho de Melo err = skb_copy_datagram_iovec(skb, offset, 409*7c657876SArnaldo Carvalho de Melo msg->msg_iov, used); 410*7c657876SArnaldo Carvalho de Melo if (err) { 411*7c657876SArnaldo Carvalho de Melo /* Exception. Bailout! */ 412*7c657876SArnaldo Carvalho de Melo if (!copied) 413*7c657876SArnaldo Carvalho de Melo copied = -EFAULT; 414*7c657876SArnaldo Carvalho de Melo break; 415*7c657876SArnaldo Carvalho de Melo } 416*7c657876SArnaldo Carvalho de Melo } 417*7c657876SArnaldo Carvalho de Melo 418*7c657876SArnaldo Carvalho de Melo copied += used; 419*7c657876SArnaldo Carvalho de Melo len -= used; 420*7c657876SArnaldo Carvalho de Melo 421*7c657876SArnaldo Carvalho de Melo /* FIXME: tcp_rcv_space_adjust(sk); */ 422*7c657876SArnaldo Carvalho de Melo 423*7c657876SArnaldo Carvalho de Melo //skip_copy: 424*7c657876SArnaldo Carvalho de Melo if (used + offset < skb->len) 425*7c657876SArnaldo Carvalho de Melo continue; 426*7c657876SArnaldo Carvalho de Melo 427*7c657876SArnaldo Carvalho de Melo if (!(flags & MSG_PEEK)) 428*7c657876SArnaldo Carvalho de Melo sk_eat_skb(sk, skb); 429*7c657876SArnaldo Carvalho de Melo continue; 430*7c657876SArnaldo Carvalho de Melo found_fin_ok: 431*7c657876SArnaldo Carvalho de Melo if (!(flags & MSG_PEEK)) 432*7c657876SArnaldo Carvalho de Melo sk_eat_skb(sk, skb); 433*7c657876SArnaldo Carvalho de Melo break; 434*7c657876SArnaldo Carvalho de Melo 435*7c657876SArnaldo Carvalho de Melo } while (len > 0); 436*7c657876SArnaldo Carvalho de Melo 437*7c657876SArnaldo Carvalho de Melo /* According to UNIX98, msg_name/msg_namelen are ignored 438*7c657876SArnaldo Carvalho de Melo * on connected socket. I was just happy when found this 8) --ANK 439*7c657876SArnaldo Carvalho de Melo */ 440*7c657876SArnaldo Carvalho de Melo 441*7c657876SArnaldo Carvalho de Melo /* Clean up data we have read: This will do ACK frames. */ 442*7c657876SArnaldo Carvalho de Melo /* FIXME: cleanup_rbuf(sk, copied); */ 443*7c657876SArnaldo Carvalho de Melo 444*7c657876SArnaldo Carvalho de Melo release_sock(sk); 445*7c657876SArnaldo Carvalho de Melo return copied; 446*7c657876SArnaldo Carvalho de Melo 447*7c657876SArnaldo Carvalho de Melo out: 448*7c657876SArnaldo Carvalho de Melo release_sock(sk); 449*7c657876SArnaldo Carvalho de Melo return err; 450*7c657876SArnaldo Carvalho de Melo 451*7c657876SArnaldo Carvalho de Melo recv_urg: 452*7c657876SArnaldo Carvalho de Melo /* FIXME: err = tcp_recv_urg(sk, timeo, msg, len, flags, addr_len); */ 453*7c657876SArnaldo Carvalho de Melo goto out; 454*7c657876SArnaldo Carvalho de Melo } 455*7c657876SArnaldo Carvalho de Melo 456*7c657876SArnaldo Carvalho de Melo static int inet_dccp_listen(struct socket *sock, int backlog) 457*7c657876SArnaldo Carvalho de Melo { 458*7c657876SArnaldo Carvalho de Melo struct sock *sk = sock->sk; 459*7c657876SArnaldo Carvalho de Melo unsigned char old_state; 460*7c657876SArnaldo Carvalho de Melo int err; 461*7c657876SArnaldo Carvalho de Melo 462*7c657876SArnaldo Carvalho de Melo lock_sock(sk); 463*7c657876SArnaldo Carvalho de Melo 464*7c657876SArnaldo Carvalho de Melo err = -EINVAL; 465*7c657876SArnaldo Carvalho de Melo if (sock->state != SS_UNCONNECTED || sock->type != SOCK_DCCP) 466*7c657876SArnaldo Carvalho de Melo goto out; 467*7c657876SArnaldo Carvalho de Melo 468*7c657876SArnaldo Carvalho de Melo old_state = sk->sk_state; 469*7c657876SArnaldo Carvalho de Melo if (!((1 << old_state) & (DCCPF_CLOSED | DCCPF_LISTEN))) 470*7c657876SArnaldo Carvalho de Melo goto out; 471*7c657876SArnaldo Carvalho de Melo 472*7c657876SArnaldo Carvalho de Melo /* Really, if the socket is already in listen state 473*7c657876SArnaldo Carvalho de Melo * we can only allow the backlog to be adjusted. 474*7c657876SArnaldo Carvalho de Melo */ 475*7c657876SArnaldo Carvalho de Melo if (old_state != DCCP_LISTEN) { 476*7c657876SArnaldo Carvalho de Melo /* 477*7c657876SArnaldo Carvalho de Melo * FIXME: here it probably should be sk->sk_prot->listen_start 478*7c657876SArnaldo Carvalho de Melo * see tcp_listen_start 479*7c657876SArnaldo Carvalho de Melo */ 480*7c657876SArnaldo Carvalho de Melo err = dccp_listen_start(sk); 481*7c657876SArnaldo Carvalho de Melo if (err) 482*7c657876SArnaldo Carvalho de Melo goto out; 483*7c657876SArnaldo Carvalho de Melo } 484*7c657876SArnaldo Carvalho de Melo sk->sk_max_ack_backlog = backlog; 485*7c657876SArnaldo Carvalho de Melo err = 0; 486*7c657876SArnaldo Carvalho de Melo 487*7c657876SArnaldo Carvalho de Melo out: 488*7c657876SArnaldo Carvalho de Melo release_sock(sk); 489*7c657876SArnaldo Carvalho de Melo return err; 490*7c657876SArnaldo Carvalho de Melo } 491*7c657876SArnaldo Carvalho de Melo 492*7c657876SArnaldo Carvalho de Melo static const unsigned char dccp_new_state[] = { 493*7c657876SArnaldo Carvalho de Melo /* current state: new state: action: */ 494*7c657876SArnaldo Carvalho de Melo [0] = DCCP_CLOSED, 495*7c657876SArnaldo Carvalho de Melo [DCCP_OPEN] = DCCP_CLOSING | DCCP_ACTION_FIN, 496*7c657876SArnaldo Carvalho de Melo [DCCP_REQUESTING] = DCCP_CLOSED, 497*7c657876SArnaldo Carvalho de Melo [DCCP_PARTOPEN] = DCCP_CLOSING | DCCP_ACTION_FIN, 498*7c657876SArnaldo Carvalho de Melo [DCCP_LISTEN] = DCCP_CLOSED, 499*7c657876SArnaldo Carvalho de Melo [DCCP_RESPOND] = DCCP_CLOSED, 500*7c657876SArnaldo Carvalho de Melo [DCCP_CLOSING] = DCCP_CLOSED, 501*7c657876SArnaldo Carvalho de Melo [DCCP_TIME_WAIT] = DCCP_CLOSED, 502*7c657876SArnaldo Carvalho de Melo [DCCP_CLOSED] = DCCP_CLOSED, 503*7c657876SArnaldo Carvalho de Melo }; 504*7c657876SArnaldo Carvalho de Melo 505*7c657876SArnaldo Carvalho de Melo static int dccp_close_state(struct sock *sk) 506*7c657876SArnaldo Carvalho de Melo { 507*7c657876SArnaldo Carvalho de Melo const int next = dccp_new_state[sk->sk_state]; 508*7c657876SArnaldo Carvalho de Melo const int ns = next & DCCP_STATE_MASK; 509*7c657876SArnaldo Carvalho de Melo 510*7c657876SArnaldo Carvalho de Melo if (ns != sk->sk_state) 511*7c657876SArnaldo Carvalho de Melo dccp_set_state(sk, ns); 512*7c657876SArnaldo Carvalho de Melo 513*7c657876SArnaldo Carvalho de Melo return next & DCCP_ACTION_FIN; 514*7c657876SArnaldo Carvalho de Melo } 515*7c657876SArnaldo Carvalho de Melo 516*7c657876SArnaldo Carvalho de Melo void dccp_close(struct sock *sk, long timeout) 517*7c657876SArnaldo Carvalho de Melo { 518*7c657876SArnaldo Carvalho de Melo struct sk_buff *skb; 519*7c657876SArnaldo Carvalho de Melo 520*7c657876SArnaldo Carvalho de Melo lock_sock(sk); 521*7c657876SArnaldo Carvalho de Melo 522*7c657876SArnaldo Carvalho de Melo sk->sk_shutdown = SHUTDOWN_MASK; 523*7c657876SArnaldo Carvalho de Melo 524*7c657876SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_LISTEN) { 525*7c657876SArnaldo Carvalho de Melo dccp_set_state(sk, DCCP_CLOSED); 526*7c657876SArnaldo Carvalho de Melo 527*7c657876SArnaldo Carvalho de Melo /* Special case. */ 528*7c657876SArnaldo Carvalho de Melo inet_csk_listen_stop(sk); 529*7c657876SArnaldo Carvalho de Melo 530*7c657876SArnaldo Carvalho de Melo goto adjudge_to_death; 531*7c657876SArnaldo Carvalho de Melo } 532*7c657876SArnaldo Carvalho de Melo 533*7c657876SArnaldo Carvalho de Melo /* 534*7c657876SArnaldo Carvalho de Melo * We need to flush the recv. buffs. We do this only on the 535*7c657876SArnaldo Carvalho de Melo * descriptor close, not protocol-sourced closes, because the 536*7c657876SArnaldo Carvalho de Melo *reader process may not have drained the data yet! 537*7c657876SArnaldo Carvalho de Melo */ 538*7c657876SArnaldo Carvalho de Melo /* FIXME: check for unread data */ 539*7c657876SArnaldo Carvalho de Melo while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { 540*7c657876SArnaldo Carvalho de Melo __kfree_skb(skb); 541*7c657876SArnaldo Carvalho de Melo } 542*7c657876SArnaldo Carvalho de Melo 543*7c657876SArnaldo Carvalho de Melo if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { 544*7c657876SArnaldo Carvalho de Melo /* Check zero linger _after_ checking for unread data. */ 545*7c657876SArnaldo Carvalho de Melo sk->sk_prot->disconnect(sk, 0); 546*7c657876SArnaldo Carvalho de Melo } else if (dccp_close_state(sk)) { 547*7c657876SArnaldo Carvalho de Melo dccp_send_close(sk); 548*7c657876SArnaldo Carvalho de Melo } 549*7c657876SArnaldo Carvalho de Melo 550*7c657876SArnaldo Carvalho de Melo sk_stream_wait_close(sk, timeout); 551*7c657876SArnaldo Carvalho de Melo 552*7c657876SArnaldo Carvalho de Melo adjudge_to_death: 553*7c657876SArnaldo Carvalho de Melo release_sock(sk); 554*7c657876SArnaldo Carvalho de Melo /* 555*7c657876SArnaldo Carvalho de Melo * Now socket is owned by kernel and we acquire BH lock 556*7c657876SArnaldo Carvalho de Melo * to finish close. No need to check for user refs. 557*7c657876SArnaldo Carvalho de Melo */ 558*7c657876SArnaldo Carvalho de Melo local_bh_disable(); 559*7c657876SArnaldo Carvalho de Melo bh_lock_sock(sk); 560*7c657876SArnaldo Carvalho de Melo BUG_TRAP(!sock_owned_by_user(sk)); 561*7c657876SArnaldo Carvalho de Melo 562*7c657876SArnaldo Carvalho de Melo sock_hold(sk); 563*7c657876SArnaldo Carvalho de Melo sock_orphan(sk); 564*7c657876SArnaldo Carvalho de Melo 565*7c657876SArnaldo Carvalho de Melo if (sk->sk_state != DCCP_CLOSED) 566*7c657876SArnaldo Carvalho de Melo dccp_set_state(sk, DCCP_CLOSED); 567*7c657876SArnaldo Carvalho de Melo 568*7c657876SArnaldo Carvalho de Melo atomic_inc(&dccp_orphan_count); 569*7c657876SArnaldo Carvalho de Melo if (sk->sk_state == DCCP_CLOSED) 570*7c657876SArnaldo Carvalho de Melo inet_csk_destroy_sock(sk); 571*7c657876SArnaldo Carvalho de Melo 572*7c657876SArnaldo Carvalho de Melo /* Otherwise, socket is reprieved until protocol close. */ 573*7c657876SArnaldo Carvalho de Melo 574*7c657876SArnaldo Carvalho de Melo bh_unlock_sock(sk); 575*7c657876SArnaldo Carvalho de Melo local_bh_enable(); 576*7c657876SArnaldo Carvalho de Melo sock_put(sk); 577*7c657876SArnaldo Carvalho de Melo } 578*7c657876SArnaldo Carvalho de Melo 579*7c657876SArnaldo Carvalho de Melo void dccp_shutdown(struct sock *sk, int how) 580*7c657876SArnaldo Carvalho de Melo { 581*7c657876SArnaldo Carvalho de Melo dccp_pr_debug("entry\n"); 582*7c657876SArnaldo Carvalho de Melo } 583*7c657876SArnaldo Carvalho de Melo 584*7c657876SArnaldo Carvalho de Melo struct proto_ops inet_dccp_ops = { 585*7c657876SArnaldo Carvalho de Melo .family = PF_INET, 586*7c657876SArnaldo Carvalho de Melo .owner = THIS_MODULE, 587*7c657876SArnaldo Carvalho de Melo .release = inet_release, 588*7c657876SArnaldo Carvalho de Melo .bind = inet_bind, 589*7c657876SArnaldo Carvalho de Melo .connect = inet_stream_connect, 590*7c657876SArnaldo Carvalho de Melo .socketpair = sock_no_socketpair, 591*7c657876SArnaldo Carvalho de Melo .accept = inet_accept, 592*7c657876SArnaldo Carvalho de Melo .getname = inet_getname, 593*7c657876SArnaldo Carvalho de Melo .poll = sock_no_poll, 594*7c657876SArnaldo Carvalho de Melo .ioctl = inet_ioctl, 595*7c657876SArnaldo Carvalho de Melo .listen = inet_dccp_listen, /* FIXME: work on inet_listen to rename it to sock_common_listen */ 596*7c657876SArnaldo Carvalho de Melo .shutdown = inet_shutdown, 597*7c657876SArnaldo Carvalho de Melo .setsockopt = sock_common_setsockopt, 598*7c657876SArnaldo Carvalho de Melo .getsockopt = sock_common_getsockopt, 599*7c657876SArnaldo Carvalho de Melo .sendmsg = inet_sendmsg, 600*7c657876SArnaldo Carvalho de Melo .recvmsg = sock_common_recvmsg, 601*7c657876SArnaldo Carvalho de Melo .mmap = sock_no_mmap, 602*7c657876SArnaldo Carvalho de Melo .sendpage = sock_no_sendpage, 603*7c657876SArnaldo Carvalho de Melo }; 604*7c657876SArnaldo Carvalho de Melo 605*7c657876SArnaldo Carvalho de Melo extern struct net_proto_family inet_family_ops; 606*7c657876SArnaldo Carvalho de Melo 607*7c657876SArnaldo Carvalho de Melo static struct inet_protosw dccp_v4_protosw = { 608*7c657876SArnaldo Carvalho de Melo .type = SOCK_DCCP, 609*7c657876SArnaldo Carvalho de Melo .protocol = IPPROTO_DCCP, 610*7c657876SArnaldo Carvalho de Melo .prot = &dccp_v4_prot, 611*7c657876SArnaldo Carvalho de Melo .ops = &inet_dccp_ops, 612*7c657876SArnaldo Carvalho de Melo .capability = -1, 613*7c657876SArnaldo Carvalho de Melo .no_check = 0, 614*7c657876SArnaldo Carvalho de Melo .flags = 0, 615*7c657876SArnaldo Carvalho de Melo }; 616*7c657876SArnaldo Carvalho de Melo 617*7c657876SArnaldo Carvalho de Melo /* 618*7c657876SArnaldo Carvalho de Melo * This is the global socket data structure used for responding to 619*7c657876SArnaldo Carvalho de Melo * the Out-of-the-blue (OOTB) packets. A control sock will be created 620*7c657876SArnaldo Carvalho de Melo * for this socket at the initialization time. 621*7c657876SArnaldo Carvalho de Melo */ 622*7c657876SArnaldo Carvalho de Melo struct socket *dccp_ctl_socket; 623*7c657876SArnaldo Carvalho de Melo 624*7c657876SArnaldo Carvalho de Melo static char dccp_ctl_socket_err_msg[] __initdata = 625*7c657876SArnaldo Carvalho de Melo KERN_ERR "DCCP: Failed to create the control socket.\n"; 626*7c657876SArnaldo Carvalho de Melo 627*7c657876SArnaldo Carvalho de Melo static int __init dccp_ctl_sock_init(void) 628*7c657876SArnaldo Carvalho de Melo { 629*7c657876SArnaldo Carvalho de Melo int rc = sock_create_kern(PF_INET, SOCK_DCCP, IPPROTO_DCCP, 630*7c657876SArnaldo Carvalho de Melo &dccp_ctl_socket); 631*7c657876SArnaldo Carvalho de Melo if (rc < 0) 632*7c657876SArnaldo Carvalho de Melo printk(dccp_ctl_socket_err_msg); 633*7c657876SArnaldo Carvalho de Melo else { 634*7c657876SArnaldo Carvalho de Melo dccp_ctl_socket->sk->sk_allocation = GFP_ATOMIC; 635*7c657876SArnaldo Carvalho de Melo inet_sk(dccp_ctl_socket->sk)->uc_ttl = -1; 636*7c657876SArnaldo Carvalho de Melo 637*7c657876SArnaldo Carvalho de Melo /* Unhash it so that IP input processing does not even 638*7c657876SArnaldo Carvalho de Melo * see it, we do not wish this socket to see incoming 639*7c657876SArnaldo Carvalho de Melo * packets. 640*7c657876SArnaldo Carvalho de Melo */ 641*7c657876SArnaldo Carvalho de Melo dccp_ctl_socket->sk->sk_prot->unhash(dccp_ctl_socket->sk); 642*7c657876SArnaldo Carvalho de Melo } 643*7c657876SArnaldo Carvalho de Melo 644*7c657876SArnaldo Carvalho de Melo return rc; 645*7c657876SArnaldo Carvalho de Melo } 646*7c657876SArnaldo Carvalho de Melo 647*7c657876SArnaldo Carvalho de Melo static void __exit dccp_ctl_sock_exit(void) 648*7c657876SArnaldo Carvalho de Melo { 649*7c657876SArnaldo Carvalho de Melo if (dccp_ctl_socket != NULL) 650*7c657876SArnaldo Carvalho de Melo sock_release(dccp_ctl_socket); 651*7c657876SArnaldo Carvalho de Melo } 652*7c657876SArnaldo Carvalho de Melo 653*7c657876SArnaldo Carvalho de Melo static int __init init_dccp_v4_mibs(void) 654*7c657876SArnaldo Carvalho de Melo { 655*7c657876SArnaldo Carvalho de Melo int rc = -ENOMEM; 656*7c657876SArnaldo Carvalho de Melo 657*7c657876SArnaldo Carvalho de Melo dccp_statistics[0] = alloc_percpu(struct dccp_mib); 658*7c657876SArnaldo Carvalho de Melo if (dccp_statistics[0] == NULL) 659*7c657876SArnaldo Carvalho de Melo goto out; 660*7c657876SArnaldo Carvalho de Melo 661*7c657876SArnaldo Carvalho de Melo dccp_statistics[1] = alloc_percpu(struct dccp_mib); 662*7c657876SArnaldo Carvalho de Melo if (dccp_statistics[1] == NULL) 663*7c657876SArnaldo Carvalho de Melo goto out_free_one; 664*7c657876SArnaldo Carvalho de Melo 665*7c657876SArnaldo Carvalho de Melo rc = 0; 666*7c657876SArnaldo Carvalho de Melo out: 667*7c657876SArnaldo Carvalho de Melo return rc; 668*7c657876SArnaldo Carvalho de Melo out_free_one: 669*7c657876SArnaldo Carvalho de Melo free_percpu(dccp_statistics[0]); 670*7c657876SArnaldo Carvalho de Melo dccp_statistics[0] = NULL; 671*7c657876SArnaldo Carvalho de Melo goto out; 672*7c657876SArnaldo Carvalho de Melo 673*7c657876SArnaldo Carvalho de Melo } 674*7c657876SArnaldo Carvalho de Melo 675*7c657876SArnaldo Carvalho de Melo static int thash_entries; 676*7c657876SArnaldo Carvalho de Melo module_param(thash_entries, int, 0444); 677*7c657876SArnaldo Carvalho de Melo MODULE_PARM_DESC(thash_entries, "Number of ehash buckets"); 678*7c657876SArnaldo Carvalho de Melo 679*7c657876SArnaldo Carvalho de Melo int dccp_debug; 680*7c657876SArnaldo Carvalho de Melo module_param(dccp_debug, int, 0444); 681*7c657876SArnaldo Carvalho de Melo MODULE_PARM_DESC(dccp_debug, "Enable debug messages"); 682*7c657876SArnaldo Carvalho de Melo 683*7c657876SArnaldo Carvalho de Melo static int __init dccp_init(void) 684*7c657876SArnaldo Carvalho de Melo { 685*7c657876SArnaldo Carvalho de Melo unsigned long goal; 686*7c657876SArnaldo Carvalho de Melo int ehash_order, bhash_order, i; 687*7c657876SArnaldo Carvalho de Melo int rc = proto_register(&dccp_v4_prot, 1); 688*7c657876SArnaldo Carvalho de Melo 689*7c657876SArnaldo Carvalho de Melo if (rc) 690*7c657876SArnaldo Carvalho de Melo goto out; 691*7c657876SArnaldo Carvalho de Melo 692*7c657876SArnaldo Carvalho de Melo dccp_hashinfo.bind_bucket_cachep = kmem_cache_create("dccp_bind_bucket", 693*7c657876SArnaldo Carvalho de Melo sizeof(struct inet_bind_bucket), 694*7c657876SArnaldo Carvalho de Melo 0, SLAB_HWCACHE_ALIGN, 695*7c657876SArnaldo Carvalho de Melo NULL, NULL); 696*7c657876SArnaldo Carvalho de Melo if (!dccp_hashinfo.bind_bucket_cachep) 697*7c657876SArnaldo Carvalho de Melo goto out_proto_unregister; 698*7c657876SArnaldo Carvalho de Melo 699*7c657876SArnaldo Carvalho de Melo /* 700*7c657876SArnaldo Carvalho de Melo * Size and allocate the main established and bind bucket 701*7c657876SArnaldo Carvalho de Melo * hash tables. 702*7c657876SArnaldo Carvalho de Melo * 703*7c657876SArnaldo Carvalho de Melo * The methodology is similar to that of the buffer cache. 704*7c657876SArnaldo Carvalho de Melo */ 705*7c657876SArnaldo Carvalho de Melo if (num_physpages >= (128 * 1024)) 706*7c657876SArnaldo Carvalho de Melo goal = num_physpages >> (21 - PAGE_SHIFT); 707*7c657876SArnaldo Carvalho de Melo else 708*7c657876SArnaldo Carvalho de Melo goal = num_physpages >> (23 - PAGE_SHIFT); 709*7c657876SArnaldo Carvalho de Melo 710*7c657876SArnaldo Carvalho de Melo if (thash_entries) 711*7c657876SArnaldo Carvalho de Melo goal = (thash_entries * sizeof(struct inet_ehash_bucket)) >> PAGE_SHIFT; 712*7c657876SArnaldo Carvalho de Melo for (ehash_order = 0; (1UL << ehash_order) < goal; ehash_order++) 713*7c657876SArnaldo Carvalho de Melo ; 714*7c657876SArnaldo Carvalho de Melo do { 715*7c657876SArnaldo Carvalho de Melo dccp_hashinfo.ehash_size = (1UL << ehash_order) * PAGE_SIZE / 716*7c657876SArnaldo Carvalho de Melo sizeof(struct inet_ehash_bucket); 717*7c657876SArnaldo Carvalho de Melo dccp_hashinfo.ehash_size >>= 1; 718*7c657876SArnaldo Carvalho de Melo while (dccp_hashinfo.ehash_size & (dccp_hashinfo.ehash_size - 1)) 719*7c657876SArnaldo Carvalho de Melo dccp_hashinfo.ehash_size--; 720*7c657876SArnaldo Carvalho de Melo dccp_hashinfo.ehash = (struct inet_ehash_bucket *) 721*7c657876SArnaldo Carvalho de Melo __get_free_pages(GFP_ATOMIC, ehash_order); 722*7c657876SArnaldo Carvalho de Melo } while (!dccp_hashinfo.ehash && --ehash_order > 0); 723*7c657876SArnaldo Carvalho de Melo 724*7c657876SArnaldo Carvalho de Melo if (!dccp_hashinfo.ehash) { 725*7c657876SArnaldo Carvalho de Melo printk(KERN_CRIT "Failed to allocate DCCP " 726*7c657876SArnaldo Carvalho de Melo "established hash table\n"); 727*7c657876SArnaldo Carvalho de Melo goto out_free_bind_bucket_cachep; 728*7c657876SArnaldo Carvalho de Melo } 729*7c657876SArnaldo Carvalho de Melo 730*7c657876SArnaldo Carvalho de Melo for (i = 0; i < (dccp_hashinfo.ehash_size << 1); i++) { 731*7c657876SArnaldo Carvalho de Melo rwlock_init(&dccp_hashinfo.ehash[i].lock); 732*7c657876SArnaldo Carvalho de Melo INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].chain); 733*7c657876SArnaldo Carvalho de Melo } 734*7c657876SArnaldo Carvalho de Melo 735*7c657876SArnaldo Carvalho de Melo bhash_order = ehash_order; 736*7c657876SArnaldo Carvalho de Melo 737*7c657876SArnaldo Carvalho de Melo do { 738*7c657876SArnaldo Carvalho de Melo dccp_hashinfo.bhash_size = (1UL << bhash_order) * PAGE_SIZE / 739*7c657876SArnaldo Carvalho de Melo sizeof(struct inet_bind_hashbucket); 740*7c657876SArnaldo Carvalho de Melo if ((dccp_hashinfo.bhash_size > (64 * 1024)) && bhash_order > 0) 741*7c657876SArnaldo Carvalho de Melo continue; 742*7c657876SArnaldo Carvalho de Melo dccp_hashinfo.bhash = (struct inet_bind_hashbucket *) 743*7c657876SArnaldo Carvalho de Melo __get_free_pages(GFP_ATOMIC, bhash_order); 744*7c657876SArnaldo Carvalho de Melo } while (!dccp_hashinfo.bhash && --bhash_order >= 0); 745*7c657876SArnaldo Carvalho de Melo 746*7c657876SArnaldo Carvalho de Melo if (!dccp_hashinfo.bhash) { 747*7c657876SArnaldo Carvalho de Melo printk(KERN_CRIT "Failed to allocate DCCP bind hash table\n"); 748*7c657876SArnaldo Carvalho de Melo goto out_free_dccp_ehash; 749*7c657876SArnaldo Carvalho de Melo } 750*7c657876SArnaldo Carvalho de Melo 751*7c657876SArnaldo Carvalho de Melo for (i = 0; i < dccp_hashinfo.bhash_size; i++) { 752*7c657876SArnaldo Carvalho de Melo spin_lock_init(&dccp_hashinfo.bhash[i].lock); 753*7c657876SArnaldo Carvalho de Melo INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain); 754*7c657876SArnaldo Carvalho de Melo } 755*7c657876SArnaldo Carvalho de Melo 756*7c657876SArnaldo Carvalho de Melo if (init_dccp_v4_mibs()) 757*7c657876SArnaldo Carvalho de Melo goto out_free_dccp_bhash; 758*7c657876SArnaldo Carvalho de Melo 759*7c657876SArnaldo Carvalho de Melo rc = -EAGAIN; 760*7c657876SArnaldo Carvalho de Melo if (inet_add_protocol(&dccp_protocol, IPPROTO_DCCP)) 761*7c657876SArnaldo Carvalho de Melo goto out_free_dccp_v4_mibs; 762*7c657876SArnaldo Carvalho de Melo 763*7c657876SArnaldo Carvalho de Melo inet_register_protosw(&dccp_v4_protosw); 764*7c657876SArnaldo Carvalho de Melo 765*7c657876SArnaldo Carvalho de Melo rc = dccp_ctl_sock_init(); 766*7c657876SArnaldo Carvalho de Melo if (rc) 767*7c657876SArnaldo Carvalho de Melo goto out_unregister_protosw; 768*7c657876SArnaldo Carvalho de Melo out: 769*7c657876SArnaldo Carvalho de Melo return rc; 770*7c657876SArnaldo Carvalho de Melo out_unregister_protosw: 771*7c657876SArnaldo Carvalho de Melo inet_unregister_protosw(&dccp_v4_protosw); 772*7c657876SArnaldo Carvalho de Melo inet_del_protocol(&dccp_protocol, IPPROTO_DCCP); 773*7c657876SArnaldo Carvalho de Melo out_free_dccp_v4_mibs: 774*7c657876SArnaldo Carvalho de Melo free_percpu(dccp_statistics[0]); 775*7c657876SArnaldo Carvalho de Melo free_percpu(dccp_statistics[1]); 776*7c657876SArnaldo Carvalho de Melo dccp_statistics[0] = dccp_statistics[1] = NULL; 777*7c657876SArnaldo Carvalho de Melo out_free_dccp_bhash: 778*7c657876SArnaldo Carvalho de Melo free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order); 779*7c657876SArnaldo Carvalho de Melo dccp_hashinfo.bhash = NULL; 780*7c657876SArnaldo Carvalho de Melo out_free_dccp_ehash: 781*7c657876SArnaldo Carvalho de Melo free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order); 782*7c657876SArnaldo Carvalho de Melo dccp_hashinfo.ehash = NULL; 783*7c657876SArnaldo Carvalho de Melo out_free_bind_bucket_cachep: 784*7c657876SArnaldo Carvalho de Melo kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); 785*7c657876SArnaldo Carvalho de Melo dccp_hashinfo.bind_bucket_cachep = NULL; 786*7c657876SArnaldo Carvalho de Melo out_proto_unregister: 787*7c657876SArnaldo Carvalho de Melo proto_unregister(&dccp_v4_prot); 788*7c657876SArnaldo Carvalho de Melo goto out; 789*7c657876SArnaldo Carvalho de Melo } 790*7c657876SArnaldo Carvalho de Melo 791*7c657876SArnaldo Carvalho de Melo static const char dccp_del_proto_err_msg[] __exitdata = 792*7c657876SArnaldo Carvalho de Melo KERN_ERR "can't remove dccp net_protocol\n"; 793*7c657876SArnaldo Carvalho de Melo 794*7c657876SArnaldo Carvalho de Melo static void __exit dccp_fini(void) 795*7c657876SArnaldo Carvalho de Melo { 796*7c657876SArnaldo Carvalho de Melo dccp_ctl_sock_exit(); 797*7c657876SArnaldo Carvalho de Melo 798*7c657876SArnaldo Carvalho de Melo inet_unregister_protosw(&dccp_v4_protosw); 799*7c657876SArnaldo Carvalho de Melo 800*7c657876SArnaldo Carvalho de Melo if (inet_del_protocol(&dccp_protocol, IPPROTO_DCCP) < 0) 801*7c657876SArnaldo Carvalho de Melo printk(dccp_del_proto_err_msg); 802*7c657876SArnaldo Carvalho de Melo 803*7c657876SArnaldo Carvalho de Melo /* Free the control endpoint. */ 804*7c657876SArnaldo Carvalho de Melo sock_release(dccp_ctl_socket); 805*7c657876SArnaldo Carvalho de Melo 806*7c657876SArnaldo Carvalho de Melo proto_unregister(&dccp_v4_prot); 807*7c657876SArnaldo Carvalho de Melo 808*7c657876SArnaldo Carvalho de Melo kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); 809*7c657876SArnaldo Carvalho de Melo } 810*7c657876SArnaldo Carvalho de Melo 811*7c657876SArnaldo Carvalho de Melo module_init(dccp_init); 812*7c657876SArnaldo Carvalho de Melo module_exit(dccp_fini); 813*7c657876SArnaldo Carvalho de Melo 814*7c657876SArnaldo Carvalho de Melo /* __stringify doesn't likes enums, so use SOCK_DCCP (6) value directly */ 815*7c657876SArnaldo Carvalho de Melo MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-6"); 816*7c657876SArnaldo Carvalho de Melo MODULE_LICENSE("GPL"); 817*7c657876SArnaldo Carvalho de Melo MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>"); 818*7c657876SArnaldo Carvalho de Melo MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol"); 819