0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/list.h>
0018 #include <net/sctp/sctp.h>
0019 #include <net/sctp/sm.h>
0020 #include <net/sctp/stream_sched.h>
0021
0022
0023
0024
0025 static int sctp_sched_fcfs_set(struct sctp_stream *stream, __u16 sid,
0026 __u16 value, gfp_t gfp)
0027 {
0028 return 0;
0029 }
0030
0031 static int sctp_sched_fcfs_get(struct sctp_stream *stream, __u16 sid,
0032 __u16 *value)
0033 {
0034 *value = 0;
0035 return 0;
0036 }
0037
0038 static int sctp_sched_fcfs_init(struct sctp_stream *stream)
0039 {
0040 return 0;
0041 }
0042
0043 static int sctp_sched_fcfs_init_sid(struct sctp_stream *stream, __u16 sid,
0044 gfp_t gfp)
0045 {
0046 return 0;
0047 }
0048
0049 static void sctp_sched_fcfs_free(struct sctp_stream *stream)
0050 {
0051 }
0052
0053 static void sctp_sched_fcfs_enqueue(struct sctp_outq *q,
0054 struct sctp_datamsg *msg)
0055 {
0056 }
0057
0058 static struct sctp_chunk *sctp_sched_fcfs_dequeue(struct sctp_outq *q)
0059 {
0060 struct sctp_stream *stream = &q->asoc->stream;
0061 struct sctp_chunk *ch = NULL;
0062 struct list_head *entry;
0063
0064 if (list_empty(&q->out_chunk_list))
0065 goto out;
0066
0067 if (stream->out_curr) {
0068 ch = list_entry(stream->out_curr->ext->outq.next,
0069 struct sctp_chunk, stream_list);
0070 } else {
0071 entry = q->out_chunk_list.next;
0072 ch = list_entry(entry, struct sctp_chunk, list);
0073 }
0074
0075 sctp_sched_dequeue_common(q, ch);
0076
0077 out:
0078 return ch;
0079 }
0080
0081 static void sctp_sched_fcfs_dequeue_done(struct sctp_outq *q,
0082 struct sctp_chunk *chunk)
0083 {
0084 }
0085
0086 static void sctp_sched_fcfs_sched_all(struct sctp_stream *stream)
0087 {
0088 }
0089
0090 static void sctp_sched_fcfs_unsched_all(struct sctp_stream *stream)
0091 {
0092 }
0093
0094 static struct sctp_sched_ops sctp_sched_fcfs = {
0095 .set = sctp_sched_fcfs_set,
0096 .get = sctp_sched_fcfs_get,
0097 .init = sctp_sched_fcfs_init,
0098 .init_sid = sctp_sched_fcfs_init_sid,
0099 .free = sctp_sched_fcfs_free,
0100 .enqueue = sctp_sched_fcfs_enqueue,
0101 .dequeue = sctp_sched_fcfs_dequeue,
0102 .dequeue_done = sctp_sched_fcfs_dequeue_done,
0103 .sched_all = sctp_sched_fcfs_sched_all,
0104 .unsched_all = sctp_sched_fcfs_unsched_all,
0105 };
0106
0107 static void sctp_sched_ops_fcfs_init(void)
0108 {
0109 sctp_sched_ops_register(SCTP_SS_FCFS, &sctp_sched_fcfs);
0110 }
0111
0112
0113
0114 static struct sctp_sched_ops *sctp_sched_ops[SCTP_SS_MAX + 1];
0115
0116 void sctp_sched_ops_register(enum sctp_sched_type sched,
0117 struct sctp_sched_ops *sched_ops)
0118 {
0119 sctp_sched_ops[sched] = sched_ops;
0120 }
0121
0122 void sctp_sched_ops_init(void)
0123 {
0124 sctp_sched_ops_fcfs_init();
0125 sctp_sched_ops_prio_init();
0126 sctp_sched_ops_rr_init();
0127 }
0128
0129 int sctp_sched_set_sched(struct sctp_association *asoc,
0130 enum sctp_sched_type sched)
0131 {
0132 struct sctp_sched_ops *n = sctp_sched_ops[sched];
0133 struct sctp_sched_ops *old = asoc->outqueue.sched;
0134 struct sctp_datamsg *msg = NULL;
0135 struct sctp_chunk *ch;
0136 int i, ret = 0;
0137
0138 if (old == n)
0139 return ret;
0140
0141 if (sched > SCTP_SS_MAX)
0142 return -EINVAL;
0143
0144 if (old) {
0145 old->free(&asoc->stream);
0146
0147
0148 for (i = 0; i < asoc->stream.outcnt; i++) {
0149 struct sctp_stream_out_ext *ext = SCTP_SO(&asoc->stream, i)->ext;
0150
0151 if (!ext)
0152 continue;
0153 memset_after(ext, 0, outq);
0154 }
0155 }
0156
0157 asoc->outqueue.sched = n;
0158 n->init(&asoc->stream);
0159 for (i = 0; i < asoc->stream.outcnt; i++) {
0160 if (!SCTP_SO(&asoc->stream, i)->ext)
0161 continue;
0162
0163 ret = n->init_sid(&asoc->stream, i, GFP_ATOMIC);
0164 if (ret)
0165 goto err;
0166 }
0167
0168
0169 list_for_each_entry(ch, &asoc->outqueue.out_chunk_list, list) {
0170 if (ch->msg == msg)
0171 continue;
0172 msg = ch->msg;
0173 n->enqueue(&asoc->outqueue, msg);
0174 }
0175
0176 return ret;
0177
0178 err:
0179 n->free(&asoc->stream);
0180 asoc->outqueue.sched = &sctp_sched_fcfs;
0181
0182 return ret;
0183 }
0184
0185 int sctp_sched_get_sched(struct sctp_association *asoc)
0186 {
0187 int i;
0188
0189 for (i = 0; i <= SCTP_SS_MAX; i++)
0190 if (asoc->outqueue.sched == sctp_sched_ops[i])
0191 return i;
0192
0193 return 0;
0194 }
0195
0196 int sctp_sched_set_value(struct sctp_association *asoc, __u16 sid,
0197 __u16 value, gfp_t gfp)
0198 {
0199 if (sid >= asoc->stream.outcnt)
0200 return -EINVAL;
0201
0202 if (!SCTP_SO(&asoc->stream, sid)->ext) {
0203 int ret;
0204
0205 ret = sctp_stream_init_ext(&asoc->stream, sid);
0206 if (ret)
0207 return ret;
0208 }
0209
0210 return asoc->outqueue.sched->set(&asoc->stream, sid, value, gfp);
0211 }
0212
0213 int sctp_sched_get_value(struct sctp_association *asoc, __u16 sid,
0214 __u16 *value)
0215 {
0216 if (sid >= asoc->stream.outcnt)
0217 return -EINVAL;
0218
0219 if (!SCTP_SO(&asoc->stream, sid)->ext)
0220 return 0;
0221
0222 return asoc->outqueue.sched->get(&asoc->stream, sid, value);
0223 }
0224
0225 void sctp_sched_dequeue_done(struct sctp_outq *q, struct sctp_chunk *ch)
0226 {
0227 if (!list_is_last(&ch->frag_list, &ch->msg->chunks) &&
0228 !q->asoc->peer.intl_capable) {
0229 struct sctp_stream_out *sout;
0230 __u16 sid;
0231
0232
0233
0234
0235
0236 sid = sctp_chunk_stream_no(ch);
0237 sout = SCTP_SO(&q->asoc->stream, sid);
0238 q->asoc->stream.out_curr = sout;
0239 return;
0240 }
0241
0242 q->asoc->stream.out_curr = NULL;
0243 q->sched->dequeue_done(q, ch);
0244 }
0245
0246
0247 void sctp_sched_dequeue_common(struct sctp_outq *q, struct sctp_chunk *ch)
0248 {
0249 list_del_init(&ch->list);
0250 list_del_init(&ch->stream_list);
0251 q->out_qlen -= ch->skb->len;
0252 }
0253
0254 int sctp_sched_init_sid(struct sctp_stream *stream, __u16 sid, gfp_t gfp)
0255 {
0256 struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
0257 struct sctp_stream_out_ext *ext = SCTP_SO(stream, sid)->ext;
0258
0259 INIT_LIST_HEAD(&ext->outq);
0260 return sched->init_sid(stream, sid, gfp);
0261 }
0262
0263 struct sctp_sched_ops *sctp_sched_ops_from_stream(struct sctp_stream *stream)
0264 {
0265 struct sctp_association *asoc;
0266
0267 asoc = container_of(stream, struct sctp_association, stream);
0268
0269 return asoc->outqueue.sched;
0270 }