diff options
Diffstat (limited to 'net/sctp/sm_make_chunk.c')
-rw-r--r-- | net/sctp/sm_make_chunk.c | 112 |
1 files changed, 77 insertions, 35 deletions
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 51c4d7fef1d2..79856c924525 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -110,7 +110,7 @@ static const struct sctp_paramhdr prsctp_param = { | |||
110 | * abort chunk. | 110 | * abort chunk. |
111 | */ | 111 | */ |
112 | void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code, | 112 | void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code, |
113 | const void *payload, size_t paylen) | 113 | size_t paylen) |
114 | { | 114 | { |
115 | sctp_errhdr_t err; | 115 | sctp_errhdr_t err; |
116 | __u16 len; | 116 | __u16 len; |
@@ -120,7 +120,6 @@ void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code, | |||
120 | len = sizeof(sctp_errhdr_t) + paylen; | 120 | len = sizeof(sctp_errhdr_t) + paylen; |
121 | err.length = htons(len); | 121 | err.length = htons(len); |
122 | chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); | 122 | chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); |
123 | sctp_addto_chunk(chunk, paylen, payload); | ||
124 | } | 123 | } |
125 | 124 | ||
126 | /* 3.3.2 Initiation (INIT) (1) | 125 | /* 3.3.2 Initiation (INIT) (1) |
@@ -780,8 +779,8 @@ struct sctp_chunk *sctp_make_abort_no_data( | |||
780 | 779 | ||
781 | /* Put the tsn back into network byte order. */ | 780 | /* Put the tsn back into network byte order. */ |
782 | payload = htonl(tsn); | 781 | payload = htonl(tsn); |
783 | sctp_init_cause(retval, SCTP_ERROR_NO_DATA, (const void *)&payload, | 782 | sctp_init_cause(retval, SCTP_ERROR_NO_DATA, sizeof(payload)); |
784 | sizeof(payload)); | 783 | sctp_addto_chunk(retval, sizeof(payload), (const void *)&payload); |
785 | 784 | ||
786 | /* RFC 2960 6.4 Multi-homed SCTP Endpoints | 785 | /* RFC 2960 6.4 Multi-homed SCTP Endpoints |
787 | * | 786 | * |
@@ -823,7 +822,8 @@ struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc, | |||
823 | goto err_copy; | 822 | goto err_copy; |
824 | } | 823 | } |
825 | 824 | ||
826 | sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, payload, paylen); | 825 | sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, paylen); |
826 | sctp_addto_chunk(retval, paylen, payload); | ||
827 | 827 | ||
828 | if (paylen) | 828 | if (paylen) |
829 | kfree(payload); | 829 | kfree(payload); |
@@ -850,15 +850,17 @@ struct sctp_chunk *sctp_make_abort_violation( | |||
850 | struct sctp_paramhdr phdr; | 850 | struct sctp_paramhdr phdr; |
851 | 851 | ||
852 | retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen | 852 | retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen |
853 | + sizeof(sctp_chunkhdr_t)); | 853 | + sizeof(sctp_paramhdr_t)); |
854 | if (!retval) | 854 | if (!retval) |
855 | goto end; | 855 | goto end; |
856 | 856 | ||
857 | sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, payload, paylen); | 857 | sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, paylen |
858 | + sizeof(sctp_paramhdr_t)); | ||
858 | 859 | ||
859 | phdr.type = htons(chunk->chunk_hdr->type); | 860 | phdr.type = htons(chunk->chunk_hdr->type); |
860 | phdr.length = chunk->chunk_hdr->length; | 861 | phdr.length = chunk->chunk_hdr->length; |
861 | sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &phdr); | 862 | sctp_addto_chunk(retval, paylen, payload); |
863 | sctp_addto_param(retval, sizeof(sctp_paramhdr_t), &phdr); | ||
862 | 864 | ||
863 | end: | 865 | end: |
864 | return retval; | 866 | return retval; |
@@ -955,7 +957,8 @@ struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, | |||
955 | if (!retval) | 957 | if (!retval) |
956 | goto nodata; | 958 | goto nodata; |
957 | 959 | ||
958 | sctp_init_cause(retval, cause_code, payload, paylen); | 960 | sctp_init_cause(retval, cause_code, paylen); |
961 | sctp_addto_chunk(retval, paylen, payload); | ||
959 | 962 | ||
960 | nodata: | 963 | nodata: |
961 | return retval; | 964 | return retval; |
@@ -1128,7 +1131,7 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) | |||
1128 | void *target; | 1131 | void *target; |
1129 | void *padding; | 1132 | void *padding; |
1130 | int chunklen = ntohs(chunk->chunk_hdr->length); | 1133 | int chunklen = ntohs(chunk->chunk_hdr->length); |
1131 | int padlen = chunklen % 4; | 1134 | int padlen = WORD_ROUND(chunklen) - chunklen; |
1132 | 1135 | ||
1133 | padding = skb_put(chunk->skb, padlen); | 1136 | padding = skb_put(chunk->skb, padlen); |
1134 | target = skb_put(chunk->skb, len); | 1137 | target = skb_put(chunk->skb, len); |
@@ -1143,6 +1146,25 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) | |||
1143 | return target; | 1146 | return target; |
1144 | } | 1147 | } |
1145 | 1148 | ||
1149 | /* Append bytes to the end of a parameter. Will panic if chunk is not big | ||
1150 | * enough. | ||
1151 | */ | ||
1152 | void *sctp_addto_param(struct sctp_chunk *chunk, int len, const void *data) | ||
1153 | { | ||
1154 | void *target; | ||
1155 | int chunklen = ntohs(chunk->chunk_hdr->length); | ||
1156 | |||
1157 | target = skb_put(chunk->skb, len); | ||
1158 | |||
1159 | memcpy(target, data, len); | ||
1160 | |||
1161 | /* Adjust the chunk length field. */ | ||
1162 | chunk->chunk_hdr->length = htons(chunklen + len); | ||
1163 | chunk->chunk_end = skb_tail_pointer(chunk->skb); | ||
1164 | |||
1165 | return target; | ||
1166 | } | ||
1167 | |||
1146 | /* Append bytes from user space to the end of a chunk. Will panic if | 1168 | /* Append bytes from user space to the end of a chunk. Will panic if |
1147 | * chunk is not big enough. | 1169 | * chunk is not big enough. |
1148 | * Returns a kernel err value. | 1170 | * Returns a kernel err value. |
@@ -1174,25 +1196,36 @@ out: | |||
1174 | */ | 1196 | */ |
1175 | void sctp_chunk_assign_ssn(struct sctp_chunk *chunk) | 1197 | void sctp_chunk_assign_ssn(struct sctp_chunk *chunk) |
1176 | { | 1198 | { |
1199 | struct sctp_datamsg *msg; | ||
1200 | struct sctp_chunk *lchunk; | ||
1201 | struct sctp_stream *stream; | ||
1177 | __u16 ssn; | 1202 | __u16 ssn; |
1178 | __u16 sid; | 1203 | __u16 sid; |
1179 | 1204 | ||
1180 | if (chunk->has_ssn) | 1205 | if (chunk->has_ssn) |
1181 | return; | 1206 | return; |
1182 | 1207 | ||
1183 | /* This is the last possible instant to assign a SSN. */ | 1208 | /* All fragments will be on the same stream */ |
1184 | if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { | 1209 | sid = ntohs(chunk->subh.data_hdr->stream); |
1185 | ssn = 0; | 1210 | stream = &chunk->asoc->ssnmap->out; |
1186 | } else { | ||
1187 | sid = ntohs(chunk->subh.data_hdr->stream); | ||
1188 | if (chunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG) | ||
1189 | ssn = sctp_ssn_next(&chunk->asoc->ssnmap->out, sid); | ||
1190 | else | ||
1191 | ssn = sctp_ssn_peek(&chunk->asoc->ssnmap->out, sid); | ||
1192 | } | ||
1193 | 1211 | ||
1194 | chunk->subh.data_hdr->ssn = htons(ssn); | 1212 | /* Now assign the sequence number to the entire message. |
1195 | chunk->has_ssn = 1; | 1213 | * All fragments must have the same stream sequence number. |
1214 | */ | ||
1215 | msg = chunk->msg; | ||
1216 | list_for_each_entry(lchunk, &msg->chunks, frag_list) { | ||
1217 | if (lchunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { | ||
1218 | ssn = 0; | ||
1219 | } else { | ||
1220 | if (lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG) | ||
1221 | ssn = sctp_ssn_next(stream, sid); | ||
1222 | else | ||
1223 | ssn = sctp_ssn_peek(stream, sid); | ||
1224 | } | ||
1225 | |||
1226 | lchunk->subh.data_hdr->ssn = htons(ssn); | ||
1227 | lchunk->has_ssn = 1; | ||
1228 | } | ||
1196 | } | 1229 | } |
1197 | 1230 | ||
1198 | /* Helper function to assign a TSN if needed. This assumes that both | 1231 | /* Helper function to assign a TSN if needed. This assumes that both |
@@ -1466,7 +1499,8 @@ no_hmac: | |||
1466 | __be32 n = htonl(usecs); | 1499 | __be32 n = htonl(usecs); |
1467 | 1500 | ||
1468 | sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE, | 1501 | sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE, |
1469 | &n, sizeof(n)); | 1502 | sizeof(n)); |
1503 | sctp_addto_chunk(*errp, sizeof(n), &n); | ||
1470 | *error = -SCTP_IERROR_STALE_COOKIE; | 1504 | *error = -SCTP_IERROR_STALE_COOKIE; |
1471 | } else | 1505 | } else |
1472 | *error = -SCTP_IERROR_NOMEM; | 1506 | *error = -SCTP_IERROR_NOMEM; |
@@ -1556,7 +1590,8 @@ static int sctp_process_missing_param(const struct sctp_association *asoc, | |||
1556 | report.num_missing = htonl(1); | 1590 | report.num_missing = htonl(1); |
1557 | report.type = paramtype; | 1591 | report.type = paramtype; |
1558 | sctp_init_cause(*errp, SCTP_ERROR_MISS_PARAM, | 1592 | sctp_init_cause(*errp, SCTP_ERROR_MISS_PARAM, |
1559 | &report, sizeof(report)); | 1593 | sizeof(report)); |
1594 | sctp_addto_chunk(*errp, sizeof(report), &report); | ||
1560 | } | 1595 | } |
1561 | 1596 | ||
1562 | /* Stop processing this chunk. */ | 1597 | /* Stop processing this chunk. */ |
@@ -1574,7 +1609,7 @@ static int sctp_process_inv_mandatory(const struct sctp_association *asoc, | |||
1574 | *errp = sctp_make_op_error_space(asoc, chunk, 0); | 1609 | *errp = sctp_make_op_error_space(asoc, chunk, 0); |
1575 | 1610 | ||
1576 | if (*errp) | 1611 | if (*errp) |
1577 | sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, NULL, 0); | 1612 | sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, 0); |
1578 | 1613 | ||
1579 | /* Stop processing this chunk. */ | 1614 | /* Stop processing this chunk. */ |
1580 | return 0; | 1615 | return 0; |
@@ -1595,9 +1630,10 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc, | |||
1595 | *errp = sctp_make_op_error_space(asoc, chunk, payload_len); | 1630 | *errp = sctp_make_op_error_space(asoc, chunk, payload_len); |
1596 | 1631 | ||
1597 | if (*errp) { | 1632 | if (*errp) { |
1598 | sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, error, | 1633 | sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, |
1599 | sizeof(error)); | 1634 | sizeof(error) + sizeof(sctp_paramhdr_t)); |
1600 | sctp_addto_chunk(*errp, sizeof(sctp_paramhdr_t), param); | 1635 | sctp_addto_chunk(*errp, sizeof(error), error); |
1636 | sctp_addto_param(*errp, sizeof(sctp_paramhdr_t), param); | ||
1601 | } | 1637 | } |
1602 | 1638 | ||
1603 | return 0; | 1639 | return 0; |
@@ -1618,9 +1654,10 @@ static int sctp_process_hn_param(const struct sctp_association *asoc, | |||
1618 | if (!*errp) | 1654 | if (!*errp) |
1619 | *errp = sctp_make_op_error_space(asoc, chunk, len); | 1655 | *errp = sctp_make_op_error_space(asoc, chunk, len); |
1620 | 1656 | ||
1621 | if (*errp) | 1657 | if (*errp) { |
1622 | sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, | 1658 | sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, len); |
1623 | param.v, len); | 1659 | sctp_addto_chunk(*errp, len, param.v); |
1660 | } | ||
1624 | 1661 | ||
1625 | /* Stop processing this chunk. */ | 1662 | /* Stop processing this chunk. */ |
1626 | return 0; | 1663 | return 0; |
@@ -1672,10 +1709,13 @@ static int sctp_process_unk_param(const struct sctp_association *asoc, | |||
1672 | *errp = sctp_make_op_error_space(asoc, chunk, | 1709 | *errp = sctp_make_op_error_space(asoc, chunk, |
1673 | ntohs(chunk->chunk_hdr->length)); | 1710 | ntohs(chunk->chunk_hdr->length)); |
1674 | 1711 | ||
1675 | if (*errp) | 1712 | if (*errp) { |
1676 | sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, | 1713 | sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, |
1677 | param.v, | ||
1678 | WORD_ROUND(ntohs(param.p->length))); | 1714 | WORD_ROUND(ntohs(param.p->length))); |
1715 | sctp_addto_chunk(*errp, | ||
1716 | WORD_ROUND(ntohs(param.p->length)), | ||
1717 | param.v); | ||
1718 | } | ||
1679 | 1719 | ||
1680 | break; | 1720 | break; |
1681 | case SCTP_PARAM_ACTION_SKIP: | 1721 | case SCTP_PARAM_ACTION_SKIP: |
@@ -1690,8 +1730,10 @@ static int sctp_process_unk_param(const struct sctp_association *asoc, | |||
1690 | 1730 | ||
1691 | if (*errp) { | 1731 | if (*errp) { |
1692 | sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, | 1732 | sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, |
1693 | param.v, | ||
1694 | WORD_ROUND(ntohs(param.p->length))); | 1733 | WORD_ROUND(ntohs(param.p->length))); |
1734 | sctp_addto_chunk(*errp, | ||
1735 | WORD_ROUND(ntohs(param.p->length)), | ||
1736 | param.v); | ||
1695 | } else { | 1737 | } else { |
1696 | /* If there is no memory for generating the ERROR | 1738 | /* If there is no memory for generating the ERROR |
1697 | * report as specified, an ABORT will be triggered | 1739 | * report as specified, an ABORT will be triggered |
@@ -1791,7 +1833,7 @@ int sctp_verify_init(const struct sctp_association *asoc, | |||
1791 | * VIOLATION error. We build the ERROR chunk here and let the normal | 1833 | * VIOLATION error. We build the ERROR chunk here and let the normal |
1792 | * error handling code build and send the packet. | 1834 | * error handling code build and send the packet. |
1793 | */ | 1835 | */ |
1794 | if (param.v < (void*)chunk->chunk_end - sizeof(sctp_paramhdr_t)) { | 1836 | if (param.v != (void*)chunk->chunk_end) { |
1795 | sctp_process_inv_paramlength(asoc, param.p, chunk, errp); | 1837 | sctp_process_inv_paramlength(asoc, param.p, chunk, errp); |
1796 | return 0; | 1838 | return 0; |
1797 | } | 1839 | } |