diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-23 23:44:19 -0500 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-23 23:44:19 -0500 |
| commit | 1ebbe2b20091d306453a5cf480a87e6cd28ae76f (patch) | |
| tree | f5cd7a0fa69b8b1938cb5a0faed2e7b0628072a5 /net/dccp/proto.c | |
| parent | ac58c9059da8886b5e8cde012a80266b18ca146e (diff) | |
| parent | 674a396c6d2ba0341ebdd7c1c9950f32f018e2dd (diff) | |
Merge branch 'linus'
Diffstat (limited to 'net/dccp/proto.c')
| -rw-r--r-- | net/dccp/proto.c | 440 |
1 files changed, 301 insertions, 139 deletions
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 65b11ea90d85..d4b293e16283 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
| @@ -23,9 +23,7 @@ | |||
| 23 | #include <linux/random.h> | 23 | #include <linux/random.h> |
| 24 | #include <net/checksum.h> | 24 | #include <net/checksum.h> |
| 25 | 25 | ||
| 26 | #include <net/inet_common.h> | ||
| 27 | #include <net/inet_sock.h> | 26 | #include <net/inet_sock.h> |
| 28 | #include <net/protocol.h> | ||
| 29 | #include <net/sock.h> | 27 | #include <net/sock.h> |
| 30 | #include <net/xfrm.h> | 28 | #include <net/xfrm.h> |
| 31 | 29 | ||
| @@ -37,6 +35,7 @@ | |||
| 37 | 35 | ||
| 38 | #include "ccid.h" | 36 | #include "ccid.h" |
| 39 | #include "dccp.h" | 37 | #include "dccp.h" |
| 38 | #include "feat.h" | ||
| 40 | 39 | ||
| 41 | DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly; | 40 | DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly; |
| 42 | 41 | ||
| @@ -46,12 +45,66 @@ atomic_t dccp_orphan_count = ATOMIC_INIT(0); | |||
| 46 | 45 | ||
| 47 | EXPORT_SYMBOL_GPL(dccp_orphan_count); | 46 | EXPORT_SYMBOL_GPL(dccp_orphan_count); |
| 48 | 47 | ||
| 49 | static struct net_protocol dccp_protocol = { | 48 | struct inet_hashinfo __cacheline_aligned dccp_hashinfo = { |
| 50 | .handler = dccp_v4_rcv, | 49 | .lhash_lock = RW_LOCK_UNLOCKED, |
| 51 | .err_handler = dccp_v4_err, | 50 | .lhash_users = ATOMIC_INIT(0), |
| 52 | .no_policy = 1, | 51 | .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait), |
| 53 | }; | 52 | }; |
| 54 | 53 | ||
| 54 | EXPORT_SYMBOL_GPL(dccp_hashinfo); | ||
| 55 | |||
| 56 | void dccp_set_state(struct sock *sk, const int state) | ||
| 57 | { | ||
| 58 | const int oldstate = sk->sk_state; | ||
| 59 | |||
| 60 | dccp_pr_debug("%s(%p) %-10.10s -> %s\n", | ||
| 61 | dccp_role(sk), sk, | ||
| 62 | dccp_state_name(oldstate), dccp_state_name(state)); | ||
| 63 | WARN_ON(state == oldstate); | ||
| 64 | |||
| 65 | switch (state) { | ||
| 66 | case DCCP_OPEN: | ||
| 67 | if (oldstate != DCCP_OPEN) | ||
| 68 | DCCP_INC_STATS(DCCP_MIB_CURRESTAB); | ||
| 69 | break; | ||
| 70 | |||
| 71 | case DCCP_CLOSED: | ||
| 72 | if (oldstate == DCCP_CLOSING || oldstate == DCCP_OPEN) | ||
| 73 | DCCP_INC_STATS(DCCP_MIB_ESTABRESETS); | ||
| 74 | |||
| 75 | sk->sk_prot->unhash(sk); | ||
| 76 | if (inet_csk(sk)->icsk_bind_hash != NULL && | ||
| 77 | !(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) | ||
| 78 | inet_put_port(&dccp_hashinfo, sk); | ||
| 79 | /* fall through */ | ||
| 80 | default: | ||
| 81 | if (oldstate == DCCP_OPEN) | ||
| 82 | DCCP_DEC_STATS(DCCP_MIB_CURRESTAB); | ||
| 83 | } | ||
| 84 | |||
| 85 | /* Change state AFTER socket is unhashed to avoid closed | ||
| 86 | * socket sitting in hash tables. | ||
| 87 | */ | ||
| 88 | sk->sk_state = state; | ||
| 89 | } | ||
| 90 | |||
| 91 | EXPORT_SYMBOL_GPL(dccp_set_state); | ||
| 92 | |||
| 93 | void dccp_done(struct sock *sk) | ||
| 94 | { | ||
| 95 | dccp_set_state(sk, DCCP_CLOSED); | ||
| 96 | dccp_clear_xmit_timers(sk); | ||
| 97 | |||
| 98 | sk->sk_shutdown = SHUTDOWN_MASK; | ||
| 99 | |||
| 100 | if (!sock_flag(sk, SOCK_DEAD)) | ||
| 101 | sk->sk_state_change(sk); | ||
| 102 | else | ||
| 103 | inet_csk_destroy_sock(sk); | ||
| 104 | } | ||
| 105 | |||
| 106 | EXPORT_SYMBOL_GPL(dccp_done); | ||
| 107 | |||
| 55 | const char *dccp_packet_name(const int type) | 108 | const char *dccp_packet_name(const int type) |
| 56 | { | 109 | { |
| 57 | static const char *dccp_packet_names[] = { | 110 | static const char *dccp_packet_names[] = { |
| @@ -96,6 +149,120 @@ const char *dccp_state_name(const int state) | |||
| 96 | 149 | ||
| 97 | EXPORT_SYMBOL_GPL(dccp_state_name); | 150 | EXPORT_SYMBOL_GPL(dccp_state_name); |
| 98 | 151 | ||
| 152 | void dccp_hash(struct sock *sk) | ||
| 153 | { | ||
| 154 | inet_hash(&dccp_hashinfo, sk); | ||
| 155 | } | ||
| 156 | |||
| 157 | EXPORT_SYMBOL_GPL(dccp_hash); | ||
| 158 | |||
| 159 | void dccp_unhash(struct sock *sk) | ||
| 160 | { | ||
| 161 | inet_unhash(&dccp_hashinfo, sk); | ||
| 162 | } | ||
| 163 | |||
| 164 | EXPORT_SYMBOL_GPL(dccp_unhash); | ||
| 165 | |||
| 166 | int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) | ||
| 167 | { | ||
| 168 | struct dccp_sock *dp = dccp_sk(sk); | ||
| 169 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
| 170 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
| 171 | |||
| 172 | dccp_minisock_init(&dp->dccps_minisock); | ||
| 173 | do_gettimeofday(&dp->dccps_epoch); | ||
| 174 | |||
| 175 | /* | ||
| 176 | * FIXME: We're hardcoding the CCID, and doing this at this point makes | ||
| 177 | * the listening (master) sock get CCID control blocks, which is not | ||
| 178 | * necessary, but for now, to not mess with the test userspace apps, | ||
| 179 | * lets leave it here, later the real solution is to do this in a | ||
| 180 | * setsockopt(CCIDs-I-want/accept). -acme | ||
| 181 | */ | ||
| 182 | if (likely(ctl_sock_initialized)) { | ||
| 183 | int rc = dccp_feat_init(dmsk); | ||
| 184 | |||
| 185 | if (rc) | ||
| 186 | return rc; | ||
| 187 | |||
| 188 | if (dmsk->dccpms_send_ack_vector) { | ||
| 189 | dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL); | ||
| 190 | if (dp->dccps_hc_rx_ackvec == NULL) | ||
| 191 | return -ENOMEM; | ||
| 192 | } | ||
| 193 | dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid, | ||
| 194 | sk, GFP_KERNEL); | ||
| 195 | dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid, | ||
| 196 | sk, GFP_KERNEL); | ||
| 197 | if (unlikely(dp->dccps_hc_rx_ccid == NULL || | ||
| 198 | dp->dccps_hc_tx_ccid == NULL)) { | ||
| 199 | ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); | ||
| 200 | ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); | ||
| 201 | if (dmsk->dccpms_send_ack_vector) { | ||
| 202 | dccp_ackvec_free(dp->dccps_hc_rx_ackvec); | ||
| 203 | dp->dccps_hc_rx_ackvec = NULL; | ||
| 204 | } | ||
| 205 | dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; | ||
| 206 | return -ENOMEM; | ||
| 207 | } | ||
| 208 | } else { | ||
| 209 | /* control socket doesn't need feat nego */ | ||
| 210 | INIT_LIST_HEAD(&dmsk->dccpms_pending); | ||
| 211 | INIT_LIST_HEAD(&dmsk->dccpms_conf); | ||
| 212 | } | ||
| 213 | |||
| 214 | dccp_init_xmit_timers(sk); | ||
| 215 | icsk->icsk_rto = DCCP_TIMEOUT_INIT; | ||
| 216 | sk->sk_state = DCCP_CLOSED; | ||
| 217 | sk->sk_write_space = dccp_write_space; | ||
| 218 | icsk->icsk_sync_mss = dccp_sync_mss; | ||
| 219 | dp->dccps_mss_cache = 536; | ||
| 220 | dp->dccps_role = DCCP_ROLE_UNDEFINED; | ||
| 221 | dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; | ||
| 222 | dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1; | ||
| 223 | |||
| 224 | return 0; | ||
| 225 | } | ||
| 226 | |||
| 227 | EXPORT_SYMBOL_GPL(dccp_init_sock); | ||
| 228 | |||
| 229 | int dccp_destroy_sock(struct sock *sk) | ||
| 230 | { | ||
| 231 | struct dccp_sock *dp = dccp_sk(sk); | ||
| 232 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
| 233 | |||
| 234 | /* | ||
| 235 | * DCCP doesn't use sk_write_queue, just sk_send_head | ||
| 236 | * for retransmissions | ||
| 237 | */ | ||
| 238 | if (sk->sk_send_head != NULL) { | ||
| 239 | kfree_skb(sk->sk_send_head); | ||
| 240 | sk->sk_send_head = NULL; | ||
| 241 | } | ||
| 242 | |||
| 243 | /* Clean up a referenced DCCP bind bucket. */ | ||
| 244 | if (inet_csk(sk)->icsk_bind_hash != NULL) | ||
| 245 | inet_put_port(&dccp_hashinfo, sk); | ||
| 246 | |||
| 247 | kfree(dp->dccps_service_list); | ||
| 248 | dp->dccps_service_list = NULL; | ||
| 249 | |||
| 250 | if (dmsk->dccpms_send_ack_vector) { | ||
| 251 | dccp_ackvec_free(dp->dccps_hc_rx_ackvec); | ||
| 252 | dp->dccps_hc_rx_ackvec = NULL; | ||
| 253 | } | ||
| 254 | ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); | ||
| 255 | ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); | ||
| 256 | dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; | ||
| 257 | |||
| 258 | /* clean up feature negotiation state */ | ||
| 259 | dccp_feat_clean(dmsk); | ||
| 260 | |||
| 261 | return 0; | ||
| 262 | } | ||
| 263 | |||
| 264 | EXPORT_SYMBOL_GPL(dccp_destroy_sock); | ||
| 265 | |||
| 99 | static inline int dccp_listen_start(struct sock *sk) | 266 | static inline int dccp_listen_start(struct sock *sk) |
| 100 | { | 267 | { |
| 101 | struct dccp_sock *dp = dccp_sk(sk); | 268 | struct dccp_sock *dp = dccp_sk(sk); |
| @@ -220,7 +387,7 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
| 220 | 387 | ||
| 221 | EXPORT_SYMBOL_GPL(dccp_ioctl); | 388 | EXPORT_SYMBOL_GPL(dccp_ioctl); |
| 222 | 389 | ||
| 223 | static int dccp_setsockopt_service(struct sock *sk, const u32 service, | 390 | static int dccp_setsockopt_service(struct sock *sk, const __be32 service, |
| 224 | char __user *optval, int optlen) | 391 | char __user *optval, int optlen) |
| 225 | { | 392 | { |
| 226 | struct dccp_sock *dp = dccp_sk(sk); | 393 | struct dccp_sock *dp = dccp_sk(sk); |
| @@ -255,18 +422,46 @@ static int dccp_setsockopt_service(struct sock *sk, const u32 service, | |||
| 255 | return 0; | 422 | return 0; |
| 256 | } | 423 | } |
| 257 | 424 | ||
| 258 | int dccp_setsockopt(struct sock *sk, int level, int optname, | 425 | /* byte 1 is feature. the rest is the preference list */ |
| 259 | char __user *optval, int optlen) | 426 | static int dccp_setsockopt_change(struct sock *sk, int type, |
| 427 | struct dccp_so_feat __user *optval) | ||
| 428 | { | ||
| 429 | struct dccp_so_feat opt; | ||
| 430 | u8 *val; | ||
| 431 | int rc; | ||
| 432 | |||
| 433 | if (copy_from_user(&opt, optval, sizeof(opt))) | ||
| 434 | return -EFAULT; | ||
| 435 | |||
| 436 | val = kmalloc(opt.dccpsf_len, GFP_KERNEL); | ||
| 437 | if (!val) | ||
| 438 | return -ENOMEM; | ||
| 439 | |||
| 440 | if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) { | ||
| 441 | rc = -EFAULT; | ||
| 442 | goto out_free_val; | ||
| 443 | } | ||
| 444 | |||
| 445 | rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat, | ||
| 446 | val, opt.dccpsf_len, GFP_KERNEL); | ||
| 447 | if (rc) | ||
| 448 | goto out_free_val; | ||
| 449 | |||
| 450 | out: | ||
| 451 | return rc; | ||
| 452 | |||
| 453 | out_free_val: | ||
| 454 | kfree(val); | ||
| 455 | goto out; | ||
| 456 | } | ||
| 457 | |||
| 458 | static int do_dccp_setsockopt(struct sock *sk, int level, int optname, | ||
| 459 | char __user *optval, int optlen) | ||
| 260 | { | 460 | { |
| 261 | struct dccp_sock *dp; | 461 | struct dccp_sock *dp; |
| 262 | int err; | 462 | int err; |
| 263 | int val; | 463 | int val; |
| 264 | 464 | ||
| 265 | if (level != SOL_DCCP) | ||
| 266 | return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level, | ||
| 267 | optname, optval, | ||
| 268 | optlen); | ||
| 269 | |||
| 270 | if (optlen < sizeof(int)) | 465 | if (optlen < sizeof(int)) |
| 271 | return -EINVAL; | 466 | return -EINVAL; |
| 272 | 467 | ||
| @@ -284,6 +479,25 @@ int dccp_setsockopt(struct sock *sk, int level, int optname, | |||
| 284 | case DCCP_SOCKOPT_PACKET_SIZE: | 479 | case DCCP_SOCKOPT_PACKET_SIZE: |
| 285 | dp->dccps_packet_size = val; | 480 | dp->dccps_packet_size = val; |
| 286 | break; | 481 | break; |
| 482 | |||
| 483 | case DCCP_SOCKOPT_CHANGE_L: | ||
| 484 | if (optlen != sizeof(struct dccp_so_feat)) | ||
| 485 | err = -EINVAL; | ||
| 486 | else | ||
| 487 | err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L, | ||
| 488 | (struct dccp_so_feat *) | ||
| 489 | optval); | ||
| 490 | break; | ||
| 491 | |||
| 492 | case DCCP_SOCKOPT_CHANGE_R: | ||
| 493 | if (optlen != sizeof(struct dccp_so_feat)) | ||
| 494 | err = -EINVAL; | ||
| 495 | else | ||
| 496 | err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R, | ||
| 497 | (struct dccp_so_feat *) | ||
| 498 | optval); | ||
| 499 | break; | ||
| 500 | |||
| 287 | default: | 501 | default: |
| 288 | err = -ENOPROTOOPT; | 502 | err = -ENOPROTOOPT; |
| 289 | break; | 503 | break; |
| @@ -293,10 +507,33 @@ int dccp_setsockopt(struct sock *sk, int level, int optname, | |||
| 293 | return err; | 507 | return err; |
| 294 | } | 508 | } |
| 295 | 509 | ||
| 510 | int dccp_setsockopt(struct sock *sk, int level, int optname, | ||
| 511 | char __user *optval, int optlen) | ||
| 512 | { | ||
| 513 | if (level != SOL_DCCP) | ||
| 514 | return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level, | ||
| 515 | optname, optval, | ||
| 516 | optlen); | ||
| 517 | return do_dccp_setsockopt(sk, level, optname, optval, optlen); | ||
| 518 | } | ||
| 519 | |||
| 296 | EXPORT_SYMBOL_GPL(dccp_setsockopt); | 520 | EXPORT_SYMBOL_GPL(dccp_setsockopt); |
| 297 | 521 | ||
| 522 | #ifdef CONFIG_COMPAT | ||
| 523 | int compat_dccp_setsockopt(struct sock *sk, int level, int optname, | ||
| 524 | char __user *optval, int optlen) | ||
| 525 | { | ||
| 526 | if (level != SOL_DCCP) | ||
| 527 | return inet_csk_compat_setsockopt(sk, level, optname, | ||
| 528 | optval, optlen); | ||
| 529 | return do_dccp_setsockopt(sk, level, optname, optval, optlen); | ||
| 530 | } | ||
| 531 | |||
| 532 | EXPORT_SYMBOL_GPL(compat_dccp_setsockopt); | ||
| 533 | #endif | ||
| 534 | |||
| 298 | static int dccp_getsockopt_service(struct sock *sk, int len, | 535 | static int dccp_getsockopt_service(struct sock *sk, int len, |
| 299 | u32 __user *optval, | 536 | __be32 __user *optval, |
| 300 | int __user *optlen) | 537 | int __user *optlen) |
| 301 | { | 538 | { |
| 302 | const struct dccp_sock *dp = dccp_sk(sk); | 539 | const struct dccp_sock *dp = dccp_sk(sk); |
| @@ -326,16 +563,12 @@ out: | |||
| 326 | return err; | 563 | return err; |
| 327 | } | 564 | } |
| 328 | 565 | ||
| 329 | int dccp_getsockopt(struct sock *sk, int level, int optname, | 566 | static int do_dccp_getsockopt(struct sock *sk, int level, int optname, |
| 330 | char __user *optval, int __user *optlen) | 567 | char __user *optval, int __user *optlen) |
| 331 | { | 568 | { |
| 332 | struct dccp_sock *dp; | 569 | struct dccp_sock *dp; |
| 333 | int val, len; | 570 | int val, len; |
| 334 | 571 | ||
| 335 | if (level != SOL_DCCP) | ||
| 336 | return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level, | ||
| 337 | optname, optval, | ||
| 338 | optlen); | ||
| 339 | if (get_user(len, optlen)) | 572 | if (get_user(len, optlen)) |
| 340 | return -EFAULT; | 573 | return -EFAULT; |
| 341 | 574 | ||
| @@ -351,7 +584,7 @@ int dccp_getsockopt(struct sock *sk, int level, int optname, | |||
| 351 | break; | 584 | break; |
| 352 | case DCCP_SOCKOPT_SERVICE: | 585 | case DCCP_SOCKOPT_SERVICE: |
| 353 | return dccp_getsockopt_service(sk, len, | 586 | return dccp_getsockopt_service(sk, len, |
| 354 | (u32 __user *)optval, optlen); | 587 | (__be32 __user *)optval, optlen); |
| 355 | case 128 ... 191: | 588 | case 128 ... 191: |
| 356 | return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, | 589 | return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, |
| 357 | len, (u32 __user *)optval, optlen); | 590 | len, (u32 __user *)optval, optlen); |
| @@ -368,8 +601,31 @@ int dccp_getsockopt(struct sock *sk, int level, int optname, | |||
| 368 | return 0; | 601 | return 0; |
| 369 | } | 602 | } |
| 370 | 603 | ||
| 604 | int dccp_getsockopt(struct sock *sk, int level, int optname, | ||
| 605 | char __user *optval, int __user *optlen) | ||
| 606 | { | ||
| 607 | if (level != SOL_DCCP) | ||
| 608 | return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level, | ||
| 609 | optname, optval, | ||
| 610 | optlen); | ||
| 611 | return do_dccp_getsockopt(sk, level, optname, optval, optlen); | ||
| 612 | } | ||
| 613 | |||
| 371 | EXPORT_SYMBOL_GPL(dccp_getsockopt); | 614 | EXPORT_SYMBOL_GPL(dccp_getsockopt); |
| 372 | 615 | ||
| 616 | #ifdef CONFIG_COMPAT | ||
| 617 | int compat_dccp_getsockopt(struct sock *sk, int level, int optname, | ||
| 618 | char __user *optval, int __user *optlen) | ||
| 619 | { | ||
| 620 | if (level != SOL_DCCP) | ||
| 621 | return inet_csk_compat_getsockopt(sk, level, optname, | ||
| 622 | optval, optlen); | ||
| 623 | return do_dccp_getsockopt(sk, level, optname, optval, optlen); | ||
| 624 | } | ||
| 625 | |||
| 626 | EXPORT_SYMBOL_GPL(compat_dccp_getsockopt); | ||
| 627 | #endif | ||
| 628 | |||
| 373 | int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 629 | int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
| 374 | size_t len) | 630 | size_t len) |
| 375 | { | 631 | { |
| @@ -679,84 +935,7 @@ void dccp_shutdown(struct sock *sk, int how) | |||
| 679 | 935 | ||
| 680 | EXPORT_SYMBOL_GPL(dccp_shutdown); | 936 | EXPORT_SYMBOL_GPL(dccp_shutdown); |
| 681 | 937 | ||
| 682 | static const struct proto_ops inet_dccp_ops = { | 938 | static int __init dccp_mib_init(void) |
| 683 | .family = PF_INET, | ||
| 684 | .owner = THIS_MODULE, | ||
| 685 | .release = inet_release, | ||
| 686 | .bind = inet_bind, | ||
| 687 | .connect = inet_stream_connect, | ||
| 688 | .socketpair = sock_no_socketpair, | ||
| 689 | .accept = inet_accept, | ||
| 690 | .getname = inet_getname, | ||
| 691 | /* FIXME: work on tcp_poll to rename it to inet_csk_poll */ | ||
| 692 | .poll = dccp_poll, | ||
| 693 | .ioctl = inet_ioctl, | ||
| 694 | /* FIXME: work on inet_listen to rename it to sock_common_listen */ | ||
| 695 | .listen = inet_dccp_listen, | ||
| 696 | .shutdown = inet_shutdown, | ||
| 697 | .setsockopt = sock_common_setsockopt, | ||
| 698 | .getsockopt = sock_common_getsockopt, | ||
| 699 | .sendmsg = inet_sendmsg, | ||
| 700 | .recvmsg = sock_common_recvmsg, | ||
| 701 | .mmap = sock_no_mmap, | ||
| 702 | .sendpage = sock_no_sendpage, | ||
| 703 | }; | ||
| 704 | |||
| 705 | extern struct net_proto_family inet_family_ops; | ||
| 706 | |||
| 707 | static struct inet_protosw dccp_v4_protosw = { | ||
| 708 | .type = SOCK_DCCP, | ||
| 709 | .protocol = IPPROTO_DCCP, | ||
| 710 | .prot = &dccp_prot, | ||
| 711 | .ops = &inet_dccp_ops, | ||
| 712 | .capability = -1, | ||
| 713 | .no_check = 0, | ||
| 714 | .flags = INET_PROTOSW_ICSK, | ||
| 715 | }; | ||
| 716 | |||
| 717 | /* | ||
| 718 | * This is the global socket data structure used for responding to | ||
| 719 | * the Out-of-the-blue (OOTB) packets. A control sock will be created | ||
| 720 | * for this socket at the initialization time. | ||
| 721 | */ | ||
| 722 | struct socket *dccp_ctl_socket; | ||
| 723 | |||
| 724 | static char dccp_ctl_socket_err_msg[] __initdata = | ||
| 725 | KERN_ERR "DCCP: Failed to create the control socket.\n"; | ||
| 726 | |||
| 727 | static int __init dccp_ctl_sock_init(void) | ||
| 728 | { | ||
| 729 | int rc = sock_create_kern(PF_INET, SOCK_DCCP, IPPROTO_DCCP, | ||
| 730 | &dccp_ctl_socket); | ||
| 731 | if (rc < 0) | ||
| 732 | printk(dccp_ctl_socket_err_msg); | ||
| 733 | else { | ||
| 734 | dccp_ctl_socket->sk->sk_allocation = GFP_ATOMIC; | ||
| 735 | inet_sk(dccp_ctl_socket->sk)->uc_ttl = -1; | ||
| 736 | |||
| 737 | /* Unhash it so that IP input processing does not even | ||
| 738 | * see it, we do not wish this socket to see incoming | ||
| 739 | * packets. | ||
| 740 | */ | ||
| 741 | dccp_ctl_socket->sk->sk_prot->unhash(dccp_ctl_socket->sk); | ||
| 742 | } | ||
| 743 | |||
| 744 | return rc; | ||
| 745 | } | ||
| 746 | |||
| 747 | #ifdef CONFIG_IP_DCCP_UNLOAD_HACK | ||
| 748 | void dccp_ctl_sock_exit(void) | ||
| 749 | { | ||
| 750 | if (dccp_ctl_socket != NULL) { | ||
| 751 | sock_release(dccp_ctl_socket); | ||
| 752 | dccp_ctl_socket = NULL; | ||
| 753 | } | ||
| 754 | } | ||
| 755 | |||
| 756 | EXPORT_SYMBOL_GPL(dccp_ctl_sock_exit); | ||
| 757 | #endif | ||
| 758 | |||
| 759 | static int __init init_dccp_v4_mibs(void) | ||
| 760 | { | 939 | { |
| 761 | int rc = -ENOMEM; | 940 | int rc = -ENOMEM; |
| 762 | 941 | ||
| @@ -778,6 +957,13 @@ out_free_one: | |||
| 778 | 957 | ||
| 779 | } | 958 | } |
| 780 | 959 | ||
| 960 | static void dccp_mib_exit(void) | ||
| 961 | { | ||
| 962 | free_percpu(dccp_statistics[0]); | ||
| 963 | free_percpu(dccp_statistics[1]); | ||
| 964 | dccp_statistics[0] = dccp_statistics[1] = NULL; | ||
| 965 | } | ||
| 966 | |||
| 781 | static int thash_entries; | 967 | static int thash_entries; |
| 782 | module_param(thash_entries, int, 0444); | 968 | module_param(thash_entries, int, 0444); |
| 783 | MODULE_PARM_DESC(thash_entries, "Number of ehash buckets"); | 969 | MODULE_PARM_DESC(thash_entries, "Number of ehash buckets"); |
| @@ -794,17 +980,14 @@ static int __init dccp_init(void) | |||
| 794 | { | 980 | { |
| 795 | unsigned long goal; | 981 | unsigned long goal; |
| 796 | int ehash_order, bhash_order, i; | 982 | int ehash_order, bhash_order, i; |
| 797 | int rc = proto_register(&dccp_prot, 1); | 983 | int rc = -ENOBUFS; |
| 798 | |||
| 799 | if (rc) | ||
| 800 | goto out; | ||
| 801 | 984 | ||
| 802 | dccp_hashinfo.bind_bucket_cachep = | 985 | dccp_hashinfo.bind_bucket_cachep = |
| 803 | kmem_cache_create("dccp_bind_bucket", | 986 | kmem_cache_create("dccp_bind_bucket", |
| 804 | sizeof(struct inet_bind_bucket), 0, | 987 | sizeof(struct inet_bind_bucket), 0, |
| 805 | SLAB_HWCACHE_ALIGN, NULL, NULL); | 988 | SLAB_HWCACHE_ALIGN, NULL, NULL); |
| 806 | if (!dccp_hashinfo.bind_bucket_cachep) | 989 | if (!dccp_hashinfo.bind_bucket_cachep) |
| 807 | goto out_proto_unregister; | 990 | goto out; |
| 808 | 991 | ||
| 809 | /* | 992 | /* |
| 810 | * Size and allocate the main established and bind bucket | 993 | * Size and allocate the main established and bind bucket |
| @@ -866,27 +1049,23 @@ static int __init dccp_init(void) | |||
| 866 | INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain); | 1049 | INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain); |
| 867 | } | 1050 | } |
| 868 | 1051 | ||
| 869 | if (init_dccp_v4_mibs()) | 1052 | rc = dccp_mib_init(); |
| 1053 | if (rc) | ||
| 870 | goto out_free_dccp_bhash; | 1054 | goto out_free_dccp_bhash; |
| 871 | 1055 | ||
| 872 | rc = -EAGAIN; | 1056 | rc = dccp_ackvec_init(); |
| 873 | if (inet_add_protocol(&dccp_protocol, IPPROTO_DCCP)) | 1057 | if (rc) |
| 874 | goto out_free_dccp_v4_mibs; | 1058 | goto out_free_dccp_mib; |
| 875 | |||
| 876 | inet_register_protosw(&dccp_v4_protosw); | ||
| 877 | 1059 | ||
| 878 | rc = dccp_ctl_sock_init(); | 1060 | rc = dccp_sysctl_init(); |
| 879 | if (rc) | 1061 | if (rc) |
| 880 | goto out_unregister_protosw; | 1062 | goto out_ackvec_exit; |
| 881 | out: | 1063 | out: |
| 882 | return rc; | 1064 | return rc; |
| 883 | out_unregister_protosw: | 1065 | out_ackvec_exit: |
| 884 | inet_unregister_protosw(&dccp_v4_protosw); | 1066 | dccp_ackvec_exit(); |
| 885 | inet_del_protocol(&dccp_protocol, IPPROTO_DCCP); | 1067 | out_free_dccp_mib: |
| 886 | out_free_dccp_v4_mibs: | 1068 | dccp_mib_exit(); |
| 887 | free_percpu(dccp_statistics[0]); | ||
| 888 | free_percpu(dccp_statistics[1]); | ||
| 889 | dccp_statistics[0] = dccp_statistics[1] = NULL; | ||
| 890 | out_free_dccp_bhash: | 1069 | out_free_dccp_bhash: |
| 891 | free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order); | 1070 | free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order); |
| 892 | dccp_hashinfo.bhash = NULL; | 1071 | dccp_hashinfo.bhash = NULL; |
| @@ -896,23 +1075,12 @@ out_free_dccp_ehash: | |||
| 896 | out_free_bind_bucket_cachep: | 1075 | out_free_bind_bucket_cachep: |
| 897 | kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); | 1076 | kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); |
| 898 | dccp_hashinfo.bind_bucket_cachep = NULL; | 1077 | dccp_hashinfo.bind_bucket_cachep = NULL; |
| 899 | out_proto_unregister: | ||
| 900 | proto_unregister(&dccp_prot); | ||
| 901 | goto out; | 1078 | goto out; |
| 902 | } | 1079 | } |
| 903 | 1080 | ||
| 904 | static const char dccp_del_proto_err_msg[] __exitdata = | ||
| 905 | KERN_ERR "can't remove dccp net_protocol\n"; | ||
| 906 | |||
| 907 | static void __exit dccp_fini(void) | 1081 | static void __exit dccp_fini(void) |
| 908 | { | 1082 | { |
| 909 | inet_unregister_protosw(&dccp_v4_protosw); | 1083 | dccp_mib_exit(); |
| 910 | |||
| 911 | if (inet_del_protocol(&dccp_protocol, IPPROTO_DCCP) < 0) | ||
| 912 | printk(dccp_del_proto_err_msg); | ||
| 913 | |||
| 914 | free_percpu(dccp_statistics[0]); | ||
| 915 | free_percpu(dccp_statistics[1]); | ||
| 916 | free_pages((unsigned long)dccp_hashinfo.bhash, | 1084 | free_pages((unsigned long)dccp_hashinfo.bhash, |
| 917 | get_order(dccp_hashinfo.bhash_size * | 1085 | get_order(dccp_hashinfo.bhash_size * |
| 918 | sizeof(struct inet_bind_hashbucket))); | 1086 | sizeof(struct inet_bind_hashbucket))); |
| @@ -920,19 +1088,13 @@ static void __exit dccp_fini(void) | |||
| 920 | get_order(dccp_hashinfo.ehash_size * | 1088 | get_order(dccp_hashinfo.ehash_size * |
| 921 | sizeof(struct inet_ehash_bucket))); | 1089 | sizeof(struct inet_ehash_bucket))); |
| 922 | kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); | 1090 | kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); |
| 923 | proto_unregister(&dccp_prot); | 1091 | dccp_ackvec_exit(); |
| 1092 | dccp_sysctl_exit(); | ||
| 924 | } | 1093 | } |
| 925 | 1094 | ||
| 926 | module_init(dccp_init); | 1095 | module_init(dccp_init); |
| 927 | module_exit(dccp_fini); | 1096 | module_exit(dccp_fini); |
| 928 | 1097 | ||
| 929 | /* | ||
| 930 | * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33) | ||
| 931 | * values directly, Also cover the case where the protocol is not specified, | ||
| 932 | * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP | ||
| 933 | */ | ||
| 934 | MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6"); | ||
| 935 | MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6"); | ||
| 936 | MODULE_LICENSE("GPL"); | 1098 | MODULE_LICENSE("GPL"); |
| 937 | MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>"); | 1099 | MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>"); |
| 938 | MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol"); | 1100 | MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol"); |
