This patch adds a base infrastructure that allows SCTP to do memory accounting for control chunks. Real accounting code will follow. This patch alos fixes the following triggered bug ... [ 553.109742] kernel BUG at include/linux/skbuff.h:1813! [ 553.109766] invalid opcode: 0000 [#1] SMP [ 553.109789] Modules linked in: sctp libcrc32c rfcomm [...] [ 553.110259] uinput i915 i2c_algo_bit drm_kms_helper e1000e drm ptp pps_core i2c_core wmi video sunrpc [ 553.110320] CPU: 0 PID: 1636 Comm: lt-test_1_to_1_ Not tainted 3.11.0-rc3+ #2 [ 553.110350] Hardware name: LENOVO 74597D6/74597D6, BIOS 6DET60WW (3.10 ) 09/17/2009 [ 553.110381] task: ffff88020a01dd40 ti: ffff880204ed0000 task.ti: ffff880204ed0000 [ 553.110411] RIP: 0010:[<ffffffffa0698017>] [<ffffffffa0698017>] skb_orphan.part.9+0x4/0x6 [sctp] [ 553.110459] RSP: 0018:ffff880204ed1bb8 EFLAGS: 00010286 [ 553.110483] RAX: ffff8802086f5a40 RBX: ffff880204303300 RCX: 0000000000000000 [ 553.110487] RDX: ffff880204303c28 RSI: ffff8802086f5a40 RDI: ffff880202158000 [ 553.110487] RBP: ffff880204ed1bb8 R08: 0000000000000000 R09: 0000000000000000 [ 553.110487] R10: ffff88022f2d9a04 R11: ffff880233001600 R12: 0000000000000000 [ 553.110487] R13: ffff880204303c00 R14: ffff8802293d0000 R15: ffff880202158000 [ 553.110487] FS: 00007f31b31fe740(0000) GS:ffff88023bc00000(0000) knlGS:0000000000000000 [ 553.110487] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 553.110487] CR2: 000000379980e3e0 CR3: 000000020d225000 CR4: 00000000000407f0 [ 553.110487] Stack: [ 553.110487] ffff880204ed1ca8 ffffffffa068d7fc 0000000000000000 0000000000000000 [ 553.110487] 0000000000000000 ffff8802293d0000 ffff880202158000 ffffffff81cb7900 [ 553.110487] 0000000000000000 0000400000001c68 ffff8802086f5a40 000000000000000f [ 553.110487] Call Trace: [ 553.110487] [<ffffffffa068d7fc>] sctp_sendmsg+0x6bc/0xc80 [sctp] [ 553.110487] [<ffffffff8128f185>] ? sock_has_perm+0x75/0x90 [ 553.110487] [<ffffffff815a3593>] inet_sendmsg+0x63/0xb0 [ 553.110487] [<ffffffff8128f2b3>] ? selinux_socket_sendmsg+0x23/0x30 [ 553.110487] [<ffffffff8151c5d6>] sock_sendmsg+0xa6/0xd0 [ 553.110487] [<ffffffff81637b05>] ? _raw_spin_unlock_bh+0x15/0x20 [ 553.110487] [<ffffffff8151cd38>] SYSC_sendto+0x128/0x180 [ 553.110487] [<ffffffff8151ce6b>] ? SYSC_connect+0xdb/0x100 [ 553.110487] [<ffffffffa0690031>] ? sctp_inet_listen+0x71/0x1f0 [sctp] [ 553.110487] [<ffffffff8151d35e>] SyS_sendto+0xe/0x10 [ 553.110487] [<ffffffff81640202>] system_call_fastpath+0x16/0x1b [ 553.110487] Code: e0 48 c7 c7 00 22 6a a0 e8 67 a3 f0 e0 48 c7 [...] [ 553.110487] RIP [<ffffffffa0698017>] skb_orphan.part.9+0x4/0x6 [sctp] [ 553.110487] RSP <ffff880204ed1bb8> [ 553.121578] ---[ end trace 46c20c5903ef5be2 ]--- The approach taken here is to split data and control chunks creation a bit. Data chunks already have memory accounting so noting needs to happen. For control chunks, add stubs handlers.
Unified · Split
| @@ -62,8 +62,12 @@ · 61 unmodified lines | ||
| 62 | 62 | #include <net/sctp/sctp.h> |
| 63 | 63 | #include <net/sctp/sm.h> |
| 64 | 64 | |
| 65 | −static struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, | |
| 66 | − __u8 type, __u8 flags, int paylen); | |
| 65 | +static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc, | |
| 66 | + __u8 type, __u8 flags, int paylen); | |
| 67 | +static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc, | |
| 68 | + __u8 flags, int paylen); | |
| 69 | +static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, | |
| 70 | + __u8 type, __u8 flags, int paylen); | |
| 67 | 71 | static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, |
| 68 | 72 | const struct sctp_association *asoc, |
| 69 | 73 | const struct sctp_chunk *init_chunk, |
| @@ -76,6 +80,28 @@ static int sctp_process_param(struct sctp_association *asoc, · 6 unmodified lines | ||
| 76 | 80 | static void *sctp_addto_param(struct sctp_chunk *chunk, int len, |
| 77 | 81 | const void *data); |
| 78 | 82 | |
| 83 | +/* Control chunk destructor */ | |
| 84 | +static void sctp_control_release_owner(struct sk_buff *skb) | |
| 85 | +{ | |
| 86 | + /*TODO: do memory release */ | |
| 87 | +} | |
| 88 | + | |
| 89 | +static void sctp_control_set_owner_w(struct sctp_chunk *chunk) | |
| 90 | +{ | |
| 91 | + struct sctp_association *asoc = chunk->asoc; | |
| 92 | + struct sk_buff *skb = chunk->skb; | |
| 93 | + | |
| 94 | + /* TODO: properly account for control chunks. | |
| 95 | + * To do it right we'll need: | |
| 96 | + * 1) endpoint if association isn't known. | |
| 97 | + * 2) proper memory accounting. | |
| 98 | + * | |
| 99 | + * For now don't do anything for now. | |
| 100 | + */ | |
| 101 | + skb->sk = asoc ? asoc->base.sk : NULL; | |
| 102 | + skb->destructor = sctp_control_release_owner; | |
| 103 | +} | |
| 104 | + | |
| 79 | 105 | /* What was the inbound interface for this chunk? */ |
| 80 | 106 | int sctp_chunk_iif(const struct sctp_chunk *chunk) |
| 81 | 107 | { |
| @@ -290,7 +316,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, · 208 unmodified lines | ||
| 290 | 316 | * PLEASE DO NOT FIXME [This version does not support Host Name.] |
| 291 | 317 | */ |
| 292 | 318 | |
| 293 | − retval = sctp_make_chunk(asoc, SCTP_CID_INIT, 0, chunksize); | |
| 319 | + retval = sctp_make_control(asoc, SCTP_CID_INIT, 0, chunksize); | |
| 294 | 320 | if (!retval) |
| 295 | 321 | goto nodata; |
| 296 | 322 | |
| @@ -437,7 +463,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, · 140 unmodified lines | ||
| 437 | 463 | num_ext); |
| 438 | 464 | |
| 439 | 465 | /* Now allocate and fill out the chunk. */ |
| 440 | − retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); | |
| 466 | + retval = sctp_make_control(asoc, SCTP_CID_INIT_ACK, 0, chunksize); | |
| 441 | 467 | if (!retval) |
| 442 | 468 | goto nomem_chunk; |
| 443 | 469 | |
| @@ -542,7 +568,7 @@ struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc, · 98 unmodified lines | ||
| 542 | 568 | cookie_len = asoc->peer.cookie_len; |
| 543 | 569 | |
| 544 | 570 | /* Build a cookie echo chunk. */ |
| 545 | − retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len); | |
| 571 | + retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len); | |
| 546 | 572 | if (!retval) |
| 547 | 573 | goto nodata; |
| 548 | 574 | retval->subh.cookie_hdr = |
| @@ -587,7 +613,7 @@ struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc, · 38 unmodified lines | ||
| 587 | 613 | { |
| 588 | 614 | struct sctp_chunk *retval; |
| 589 | 615 | |
| 590 | − retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0); | |
| 616 | + retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ACK, 0, 0); | |
| 591 | 617 | |
| 592 | 618 | /* RFC 2960 6.4 Multi-homed SCTP Endpoints |
| 593 | 619 | * |
| @@ -635,8 +661,8 @@ struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc, · 41 unmodified lines | ||
| 635 | 661 | sctp_cwrhdr_t cwr; |
| 636 | 662 | |
| 637 | 663 | cwr.lowest_tsn = htonl(lowest_tsn); |
| 638 | − retval = sctp_make_chunk(asoc, SCTP_CID_ECN_CWR, 0, | |
| 639 | − sizeof(sctp_cwrhdr_t)); | |
| 664 | + retval = sctp_make_control(asoc, SCTP_CID_ECN_CWR, 0, | |
| 665 | + sizeof(sctp_cwrhdr_t)); | |
| 640 | 666 | |
| 641 | 667 | if (!retval) |
| 642 | 668 | goto nodata; |
| @@ -669,8 +695,8 @@ struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc, · 26 unmodified lines | ||
| 669 | 695 | sctp_ecnehdr_t ecne; |
| 670 | 696 | |
| 671 | 697 | ecne.lowest_tsn = htonl(lowest_tsn); |
| 672 | − retval = sctp_make_chunk(asoc, SCTP_CID_ECN_ECNE, 0, | |
| 673 | − sizeof(sctp_ecnehdr_t)); | |
| 698 | + retval = sctp_make_control(asoc, SCTP_CID_ECN_ECNE, 0, | |
| 699 | + sizeof(sctp_ecnehdr_t)); | |
| 674 | 700 | if (!retval) |
| 675 | 701 | goto nodata; |
| 676 | 702 | retval->subh.ecne_hdr = |
| @@ -706,7 +732,7 @@ struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc, · 29 unmodified lines | ||
| 706 | 732 | dp.ssn = htons(ssn); |
| 707 | 733 | |
| 708 | 734 | chunk_len = sizeof(dp) + data_len; |
| 709 | − retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len); | |
| 735 | + retval = sctp_make_data(asoc, flags, chunk_len); | |
| 710 | 736 | if (!retval) |
| 711 | 737 | goto nodata; |
| 712 | 738 | |
| @@ -753,7 +779,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) · 40 unmodified lines | ||
| 753 | 779 | + sizeof(__u32) * num_dup_tsns; |
| 754 | 780 | |
| 755 | 781 | /* Create the chunk. */ |
| 756 | − retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, len); | |
| 782 | + retval = sctp_make_control(asoc, SCTP_CID_SACK, 0, len); | |
| 757 | 783 | if (!retval) |
| 758 | 784 | goto nodata; |
| 759 | 785 | |
| @@ -832,8 +858,8 @@ struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc, · 72 unmodified lines | ||
| 832 | 858 | ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); |
| 833 | 859 | shut.cum_tsn_ack = htonl(ctsn); |
| 834 | 860 | |
| 835 | − retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN, 0, | |
| 836 | − sizeof(sctp_shutdownhdr_t)); | |
| 861 | + retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN, 0, | |
| 862 | + sizeof(sctp_shutdownhdr_t)); | |
| 837 | 863 | if (!retval) |
| 838 | 864 | goto nodata; |
| 839 | 865 | |
| @@ -851,7 +877,7 @@ struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, · 11 unmodified lines | ||
| 851 | 877 | { |
| 852 | 878 | struct sctp_chunk *retval; |
| 853 | 879 | |
| 854 | − retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); | |
| 880 | + retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); | |
| 855 | 881 | |
| 856 | 882 | /* RFC 2960 6.4 Multi-homed SCTP Endpoints |
| 857 | 883 | * |
| @@ -880,7 +906,7 @@ struct sctp_chunk *sctp_make_shutdown_complete( · 22 unmodified lines | ||
| 880 | 906 | */ |
| 881 | 907 | flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; |
| 882 | 908 | |
| 883 | − retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0); | |
| 909 | + retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0); | |
| 884 | 910 | |
| 885 | 911 | /* RFC 2960 6.4 Multi-homed SCTP Endpoints |
| 886 | 912 | * |
| @@ -919,7 +945,7 @@ struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc, · 32 unmodified lines | ||
| 919 | 945 | flags = SCTP_CHUNK_FLAG_T; |
| 920 | 946 | } |
| 921 | 947 | |
| 922 | − retval = sctp_make_chunk(asoc, SCTP_CID_ABORT, flags, hint); | |
| 948 | + retval = sctp_make_control(asoc, SCTP_CID_ABORT, flags, hint); | |
| 923 | 949 | |
| 924 | 950 | /* RFC 2960 6.4 Multi-homed SCTP Endpoints |
| 925 | 951 | * |
| @@ -1111,7 +1137,7 @@ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, · 185 unmodified lines | ||
| 1111 | 1137 | struct sctp_chunk *retval; |
| 1112 | 1138 | sctp_sender_hb_info_t hbinfo; |
| 1113 | 1139 | |
| 1114 | − retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo)); | |
| 1140 | + retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo)); | |
| 1115 | 1141 | |
| 1116 | 1142 | if (!retval) |
| 1117 | 1143 | goto nodata; |
| @@ -1139,7 +1165,7 @@ struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc, · 21 unmodified lines | ||
| 1139 | 1165 | { |
| 1140 | 1166 | struct sctp_chunk *retval; |
| 1141 | 1167 | |
| 1142 | − retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen); | |
| 1168 | + retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen); | |
| 1143 | 1169 | if (!retval) |
| 1144 | 1170 | goto nodata; |
| 1145 | 1171 | |
| @@ -1171,8 +1197,8 @@ static struct sctp_chunk *sctp_make_op_error_space( · 25 unmodified lines | ||
| 1171 | 1197 | { |
| 1172 | 1198 | struct sctp_chunk *retval; |
| 1173 | 1199 | |
| 1174 | − retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, | |
| 1175 | − sizeof(sctp_errhdr_t) + size); | |
| 1200 | + retval = sctp_make_control(asoc, SCTP_CID_ERROR, 0, | |
| 1201 | + sizeof(sctp_errhdr_t) + size); | |
| 1176 | 1202 | if (!retval) |
| 1177 | 1203 | goto nodata; |
| 1178 | 1204 | |
| @@ -1242,7 +1268,7 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc) · 63 unmodified lines | ||
| 1242 | 1268 | if (unlikely(!hmac_desc)) |
| 1243 | 1269 | return NULL; |
| 1244 | 1270 | |
| 1245 | − retval = sctp_make_chunk(asoc, SCTP_CID_AUTH, 0, | |
| 1271 | + retval = sctp_make_control(asoc, SCTP_CID_AUTH, 0, | |
| 1246 | 1272 | hmac_desc->hmac_len + sizeof(sctp_authhdr_t)); |
| 1247 | 1273 | if (!retval) |
| 1248 | 1274 | return NULL; |
| @@ -1345,8 +1371,8 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk) · 96 unmodified lines | ||
| 1345 | 1371 | /* Create a new chunk, setting the type and flags headers from the |
| 1346 | 1372 | * arguments, reserving enough space for a 'paylen' byte payload. |
| 1347 | 1373 | */ |
| 1348 | −static struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, | |
| 1349 | − __u8 type, __u8 flags, int paylen) | |
| 1374 | +static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, | |
| 1375 | + __u8 type, __u8 flags, int paylen) | |
| 1350 | 1376 | { |
| 1351 | 1377 | struct sctp_chunk *retval; |
| 1352 | 1378 | sctp_chunkhdr_t *chunk_hdr; |
| @@ -1379,14 +1405,27 @@ static struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, · 26 unmodified lines | ||
| 1379 | 1405 | if (sctp_auth_send_cid(type, asoc)) |
| 1380 | 1406 | retval->auth = 1; |
| 1381 | 1407 | |
| 1382 | − /* Set the skb to the belonging sock for accounting. */ | |
| 1383 | − skb->sk = sk; | |
| 1384 | − | |
| 1385 | 1408 | return retval; |
| 1386 | 1409 | nodata: |
| 1387 | 1410 | return NULL; |
| 1388 | 1411 | } |
| 1389 | 1412 | |
| 1413 | +static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc, | |
| 1414 | + __u8 flags, int paylen) | |
| 1415 | +{ | |
| 1416 | + return _sctp_make_chunk(asoc, SCTP_CID_DATA, flags, paylen); | |
| 1417 | +} | |
| 1418 | + | |
| 1419 | +static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc, | |
| 1420 | + __u8 type, __u8 flags, int paylen) | |
| 1421 | +{ | |
| 1422 | + struct sctp_chunk *chunk = _sctp_make_chunk(asoc, type, flags, paylen); | |
| 1423 | + | |
| 1424 | + if (chunk) | |
| 1425 | + sctp_control_set_owner_w(chunk); | |
| 1426 | + | |
| 1427 | + return chunk; | |
| 1428 | +} | |
| 1390 | 1429 | |
| 1391 | 1430 | /* Release the memory occupied by a chunk. */ |
| 1392 | 1431 | static void sctp_chunk_destroy(struct sctp_chunk *chunk) |
| @@ -2727,7 +2766,7 @@ static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, · 1334 unmodified lines | ||
| 2727 | 2766 | length += addrlen; |
| 2728 | 2767 | |
| 2729 | 2768 | /* Create the chunk. */ |
| 2730 | − retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF, 0, length); | |
| 2769 | + retval = sctp_make_control(asoc, SCTP_CID_ASCONF, 0, length); | |
| 2731 | 2770 | if (!retval) |
| 2732 | 2771 | return NULL; |
| 2733 | 2772 | |
| @@ -2911,7 +2950,7 @@ static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *as · 177 unmodified lines | ||
| 2911 | 2950 | int length = sizeof(asconf) + vparam_len; |
| 2912 | 2951 | |
| 2913 | 2952 | /* Create the chunk. */ |
| 2914 | − retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF_ACK, 0, length); | |
| 2953 | + retval = sctp_make_control(asoc, SCTP_CID_ASCONF_ACK, 0, length); | |
| 2915 | 2954 | if (!retval) |
| 2916 | 2955 | return NULL; |
| 2917 | 2956 | |
| @@ -3442,7 +3481,7 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, · 524 unmodified lines | ||
| 3442 | 3481 | |
| 3443 | 3482 | hint = (nstreams + 1) * sizeof(__u32); |
| 3444 | 3483 | |
| 3445 | − retval = sctp_make_chunk(asoc, SCTP_CID_FWD_TSN, 0, hint); | |
| 3484 | + retval = sctp_make_control(asoc, SCTP_CID_FWD_TSN, 0, hint); | |
| 3446 | 3485 | |
| 3447 | 3486 | if (!retval) |
| 3448 | 3487 | return NULL; |