[NET]: move struct proto_ops to const
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / dccp / proto.c
index 18a0e69c9dc75f709e15be01e7ef6def17de3eb5..e4e629ed9bf72e78c2c82edd343f232e3a0900bd 100644 (file)
 
 DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
 
+EXPORT_SYMBOL_GPL(dccp_statistics);
+
 atomic_t dccp_orphan_count = ATOMIC_INIT(0);
 
+EXPORT_SYMBOL_GPL(dccp_orphan_count);
+
 static struct net_protocol dccp_protocol = {
        .handler        = dccp_v4_rcv,
        .err_handler    = dccp_v4_err,
+       .no_policy      = 1,
 };
 
 const char *dccp_packet_name(const int type)
@@ -94,7 +99,15 @@ EXPORT_SYMBOL_GPL(dccp_state_name);
 
 static inline int dccp_listen_start(struct sock *sk)
 {
-       dccp_sk(sk)->dccps_role = DCCP_ROLE_LISTEN;
+       struct dccp_sock *dp = dccp_sk(sk);
+
+       dp->dccps_role = DCCP_ROLE_LISTEN;
+       /*
+        * Apps need to use setsockopt(DCCP_SOCKOPT_SERVICE)
+        * before calling listen()
+        */
+       if (dccp_service_not_initialized(sk))
+               return -EPROTO;
        return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE);
 }
 
@@ -140,6 +153,8 @@ int dccp_disconnect(struct sock *sk, int flags)
        return err;
 }
 
+EXPORT_SYMBOL_GPL(dccp_disconnect);
+
 /*
  *     Wait for a DCCP event.
  *
@@ -147,8 +162,8 @@ int dccp_disconnect(struct sock *sk, int flags)
  *     take care of normal races (between the test and the event) and we don't
  *     go look at any of the socket buffers directly.
  */
-static unsigned int dccp_poll(struct file *file, struct socket *sock,
-                             poll_table *wait)
+unsigned int dccp_poll(struct file *file, struct socket *sock,
+                      poll_table *wait)
 {
        unsigned int mask;
        struct sock *sk = sock->sk;
@@ -196,12 +211,51 @@ static unsigned int dccp_poll(struct file *file, struct socket *sock,
        return mask;
 }
 
+EXPORT_SYMBOL_GPL(dccp_poll);
+
 int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
        dccp_pr_debug("entry\n");
        return -ENOIOCTLCMD;
 }
 
+EXPORT_SYMBOL_GPL(dccp_ioctl);
+
+static int dccp_setsockopt_service(struct sock *sk, const u32 service,
+                                  char __user *optval, int optlen)
+{
+       struct dccp_sock *dp = dccp_sk(sk);
+       struct dccp_service_list *sl = NULL;
+
+       if (service == DCCP_SERVICE_INVALID_VALUE || 
+           optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32))
+               return -EINVAL;
+
+       if (optlen > sizeof(service)) {
+               sl = kmalloc(optlen, GFP_KERNEL);
+               if (sl == NULL)
+                       return -ENOMEM;
+
+               sl->dccpsl_nr = optlen / sizeof(u32) - 1;
+               if (copy_from_user(sl->dccpsl_list,
+                                  optval + sizeof(service),
+                                  optlen - sizeof(service)) ||
+                   dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) {
+                       kfree(sl);
+                       return -EFAULT;
+               }
+       }
+
+       lock_sock(sk);
+       dp->dccps_service = service;
+
+       kfree(dp->dccps_service_list);
+
+       dp->dccps_service_list = sl;
+       release_sock(sk);
+       return 0;
+}
+
 int dccp_setsockopt(struct sock *sk, int level, int optname,
                    char __user *optval, int optlen)
 {
@@ -210,7 +264,9 @@ int dccp_setsockopt(struct sock *sk, int level, int optname,
        int val;
 
        if (level != SOL_DCCP)
-               return ip_setsockopt(sk, level, optname, optval, optlen);
+               return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level,
+                                                            optname, optval,
+                                                            optlen);
 
        if (optlen < sizeof(int))
                return -EINVAL;
@@ -218,8 +274,10 @@ int dccp_setsockopt(struct sock *sk, int level, int optname,
        if (get_user(val, (int __user *)optval))
                return -EFAULT;
 
-       lock_sock(sk);
+       if (optname == DCCP_SOCKOPT_SERVICE)
+               return dccp_setsockopt_service(sk, val, optval, optlen);
 
+       lock_sock(sk);
        dp = dccp_sk(sk);
        err = 0;
 
@@ -236,6 +294,39 @@ int dccp_setsockopt(struct sock *sk, int level, int optname,
        return err;
 }
 
+EXPORT_SYMBOL_GPL(dccp_setsockopt);
+
+static int dccp_getsockopt_service(struct sock *sk, int len,
+                                  u32 __user *optval,
+                                  int __user *optlen)
+{
+       const struct dccp_sock *dp = dccp_sk(sk);
+       const struct dccp_service_list *sl;
+       int err = -ENOENT, slen = 0, total_len = sizeof(u32);
+
+       lock_sock(sk);
+       if (dccp_service_not_initialized(sk))
+               goto out;
+
+       if ((sl = dp->dccps_service_list) != NULL) {
+               slen = sl->dccpsl_nr * sizeof(u32);
+               total_len += slen;
+       }
+
+       err = -EINVAL;
+       if (total_len > len)
+               goto out;
+
+       err = 0;
+       if (put_user(total_len, optlen) ||
+           put_user(dp->dccps_service, optval) ||
+           (sl != NULL && copy_to_user(optval + 1, sl->dccpsl_list, slen)))
+               err = -EFAULT;
+out:
+       release_sock(sk);
+       return err;
+}
+
 int dccp_getsockopt(struct sock *sk, int level, int optname,
                    char __user *optval, int __user *optlen)
 {
@@ -243,13 +334,13 @@ int dccp_getsockopt(struct sock *sk, int level, int optname,
        int val, len;
 
        if (level != SOL_DCCP)
-               return ip_getsockopt(sk, level, optname, optval, optlen);
-
+               return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level,
+                                                            optname, optval,
+                                                            optlen);
        if (get_user(len, optlen))
                return -EFAULT;
 
-       len = min_t(unsigned int, len, sizeof(int));
-       if (len < 0)
+       if (len < sizeof(int))
                return -EINVAL;
 
        dp = dccp_sk(sk);
@@ -257,7 +348,17 @@ int dccp_getsockopt(struct sock *sk, int level, int optname,
        switch (optname) {
        case DCCP_SOCKOPT_PACKET_SIZE:
                val = dp->dccps_packet_size;
+               len = sizeof(dp->dccps_packet_size);
                break;
+       case DCCP_SOCKOPT_SERVICE:
+               return dccp_getsockopt_service(sk, len,
+                                              (u32 __user *)optval, optlen);
+       case 128 ... 191:
+               return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
+                                            len, (u32 __user *)optval, optlen);
+       case 192 ... 255:
+               return ccid_hc_tx_getsockopt(dp->dccps_hc_tx_ccid, sk, optname,
+                                            len, (u32 __user *)optval, optlen);
        default:
                return -ENOPROTOOPT;
        }
@@ -268,6 +369,8 @@ int dccp_getsockopt(struct sock *sk, int level, int optname,
        return 0;
 }
 
+EXPORT_SYMBOL_GPL(dccp_getsockopt);
+
 int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                 size_t len)
 {
@@ -316,8 +419,6 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
         *     This bug was _quickly_ found & fixed by just looking at an OSTRA
         *     generated callgraph 8) -acme
         */
-       if (rc != 0)
-               goto out_discard;
 out_release:
        release_sock(sk);
        return rc ? : len;
@@ -326,6 +427,8 @@ out_discard:
        goto out_release;
 }
 
+EXPORT_SYMBOL_GPL(dccp_sendmsg);
+
 int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                 size_t len, int nonblock, int flags, int *addr_len)
 {
@@ -423,7 +526,9 @@ out:
        return len;
 }
 
-static int inet_dccp_listen(struct socket *sock, int backlog)
+EXPORT_SYMBOL_GPL(dccp_recvmsg);
+
+int inet_dccp_listen(struct socket *sock, int backlog)
 {
        struct sock *sk = sock->sk;
        unsigned char old_state;
@@ -459,6 +564,8 @@ out:
        return err;
 }
 
+EXPORT_SYMBOL_GPL(inet_dccp_listen);
+
 static const unsigned char dccp_new_state[] = {
        /* current state:   new state:      action:     */
        [0]               = DCCP_CLOSED,
@@ -564,12 +671,16 @@ adjudge_to_death:
        sock_put(sk);
 }
 
+EXPORT_SYMBOL_GPL(dccp_close);
+
 void dccp_shutdown(struct sock *sk, int how)
 {
        dccp_pr_debug("entry\n");
 }
 
-static struct proto_ops inet_dccp_ops = {
+EXPORT_SYMBOL_GPL(dccp_shutdown);
+
+static const struct proto_ops inet_dccp_ops = {
        .family         = PF_INET,
        .owner          = THIS_MODULE,
        .release        = inet_release,
@@ -597,11 +708,11 @@ extern struct net_proto_family inet_family_ops;
 static struct inet_protosw dccp_v4_protosw = {
        .type           = SOCK_DCCP,
        .protocol       = IPPROTO_DCCP,
-       .prot           = &dccp_v4_prot,
+       .prot           = &dccp_prot,
        .ops            = &inet_dccp_ops,
        .capability     = -1,
        .no_check       = 0,
-       .flags          = 0,
+       .flags          = INET_PROTOSW_ICSK,
 };
 
 /*
@@ -676,13 +787,15 @@ MODULE_PARM_DESC(thash_entries, "Number of ehash buckets");
 int dccp_debug;
 module_param(dccp_debug, int, 0444);
 MODULE_PARM_DESC(dccp_debug, "Enable debug messages");
+
+EXPORT_SYMBOL_GPL(dccp_debug);
 #endif
 
 static int __init dccp_init(void)
 {
        unsigned long goal;
        int ehash_order, bhash_order, i;
-       int rc = proto_register(&dccp_v4_prot, 1);
+       int rc = proto_register(&dccp_prot, 1);
 
        if (rc)
                goto out;
@@ -785,7 +898,7 @@ out_free_bind_bucket_cachep:
        kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
        dccp_hashinfo.bind_bucket_cachep = NULL;
 out_proto_unregister:
-       proto_unregister(&dccp_v4_prot);
+       proto_unregister(&dccp_prot);
        goto out;
 }
 
@@ -808,7 +921,7 @@ static void __exit dccp_fini(void)
                   get_order(dccp_hashinfo.ehash_size *
                             sizeof(struct inet_ehash_bucket)));
        kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
-       proto_unregister(&dccp_v4_prot);
+       proto_unregister(&dccp_prot);
 }
 
 module_init(dccp_init);