0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <linux/slab.h>
0025 #include <linux/types.h>
0026 #include <linux/skbuff.h>
0027 #include <net/sctp/structs.h>
0028 #include <net/sctp/sctp.h>
0029 #include <net/sctp/sm.h>
0030
0031 static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
0032 struct sctp_association *asoc);
0033 static void sctp_ulpevent_release_data(struct sctp_ulpevent *event);
0034 static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event);
0035
0036
0037
0038 static void sctp_ulpevent_init(struct sctp_ulpevent *event,
0039 __u16 msg_flags,
0040 unsigned int len)
0041 {
0042 memset(event, 0, sizeof(struct sctp_ulpevent));
0043 event->msg_flags = msg_flags;
0044 event->rmem_len = len;
0045 }
0046
0047
0048 static struct sctp_ulpevent *sctp_ulpevent_new(int size, __u16 msg_flags,
0049 gfp_t gfp)
0050 {
0051 struct sctp_ulpevent *event;
0052 struct sk_buff *skb;
0053
0054 skb = alloc_skb(size, gfp);
0055 if (!skb)
0056 goto fail;
0057
0058 event = sctp_skb2event(skb);
0059 sctp_ulpevent_init(event, msg_flags, skb->truesize);
0060
0061 return event;
0062
0063 fail:
0064 return NULL;
0065 }
0066
0067
0068 int sctp_ulpevent_is_notification(const struct sctp_ulpevent *event)
0069 {
0070 return MSG_NOTIFICATION == (event->msg_flags & MSG_NOTIFICATION);
0071 }
0072
0073
0074
0075
0076 static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event,
0077 const struct sctp_association *asoc)
0078 {
0079 struct sctp_chunk *chunk = event->chunk;
0080 struct sk_buff *skb;
0081
0082
0083
0084
0085 sctp_association_hold((struct sctp_association *)asoc);
0086 skb = sctp_event2skb(event);
0087 event->asoc = (struct sctp_association *)asoc;
0088 atomic_add(event->rmem_len, &event->asoc->rmem_alloc);
0089 sctp_skb_set_owner_r(skb, asoc->base.sk);
0090 if (chunk && chunk->head_skb && !chunk->head_skb->sk)
0091 chunk->head_skb->sk = asoc->base.sk;
0092 }
0093
0094
0095 static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
0096 {
0097 struct sctp_association *asoc = event->asoc;
0098
0099 atomic_sub(event->rmem_len, &asoc->rmem_alloc);
0100 sctp_association_put(asoc);
0101 }
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114 struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
0115 const struct sctp_association *asoc,
0116 __u16 flags, __u16 state, __u16 error, __u16 outbound,
0117 __u16 inbound, struct sctp_chunk *chunk, gfp_t gfp)
0118 {
0119 struct sctp_ulpevent *event;
0120 struct sctp_assoc_change *sac;
0121 struct sk_buff *skb;
0122
0123
0124
0125
0126 if (chunk) {
0127
0128
0129
0130 skb = skb_copy_expand(chunk->skb,
0131 sizeof(struct sctp_assoc_change), 0, gfp);
0132
0133 if (!skb)
0134 goto fail;
0135
0136
0137 event = sctp_skb2event(skb);
0138 sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
0139
0140
0141 sac = skb_push(skb, sizeof(struct sctp_assoc_change));
0142
0143
0144 skb_trim(skb, sizeof(struct sctp_assoc_change) +
0145 ntohs(chunk->chunk_hdr->length) -
0146 sizeof(struct sctp_chunkhdr));
0147 } else {
0148 event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
0149 MSG_NOTIFICATION, gfp);
0150 if (!event)
0151 goto fail;
0152
0153 skb = sctp_event2skb(event);
0154 sac = skb_put(skb, sizeof(struct sctp_assoc_change));
0155 }
0156
0157
0158
0159
0160
0161
0162
0163 sac->sac_type = SCTP_ASSOC_CHANGE;
0164
0165
0166
0167
0168
0169
0170
0171
0172 sac->sac_state = state;
0173
0174
0175
0176
0177
0178
0179
0180 sac->sac_flags = 0;
0181
0182
0183
0184
0185
0186
0187
0188
0189 sac->sac_length = skb->len;
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201 sac->sac_error = error;
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212 sac->sac_outbound_streams = outbound;
0213 sac->sac_inbound_streams = inbound;
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224 sctp_ulpevent_set_owner(event, asoc);
0225 sac->sac_assoc_id = sctp_assoc2id(asoc);
0226
0227 return event;
0228
0229 fail:
0230 return NULL;
0231 }
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241 static struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
0242 const struct sctp_association *asoc,
0243 const struct sockaddr_storage *aaddr,
0244 int flags, int state, int error, gfp_t gfp)
0245 {
0246 struct sctp_ulpevent *event;
0247 struct sctp_paddr_change *spc;
0248 struct sk_buff *skb;
0249
0250 event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change),
0251 MSG_NOTIFICATION, gfp);
0252 if (!event)
0253 goto fail;
0254
0255 skb = sctp_event2skb(event);
0256 spc = skb_put(skb, sizeof(struct sctp_paddr_change));
0257
0258
0259
0260
0261
0262
0263
0264
0265 spc->spc_type = SCTP_PEER_ADDR_CHANGE;
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275 spc->spc_length = sizeof(struct sctp_paddr_change);
0276
0277
0278
0279
0280
0281
0282
0283 spc->spc_flags = 0;
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293 spc->spc_state = state;
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304 spc->spc_error = error;
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315 sctp_ulpevent_set_owner(event, asoc);
0316 spc->spc_assoc_id = sctp_assoc2id(asoc);
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326 memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage));
0327
0328
0329 sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_to_user(
0330 sctp_sk(asoc->base.sk),
0331 (union sctp_addr *)&spc->spc_aaddr);
0332
0333 return event;
0334
0335 fail:
0336 return NULL;
0337 }
0338
0339 void sctp_ulpevent_notify_peer_addr_change(struct sctp_transport *transport,
0340 int state, int error)
0341 {
0342 struct sctp_association *asoc = transport->asoc;
0343 struct sockaddr_storage addr;
0344 struct sctp_ulpevent *event;
0345
0346 if (asoc->state < SCTP_STATE_ESTABLISHED)
0347 return;
0348
0349 memset(&addr, 0, sizeof(struct sockaddr_storage));
0350 memcpy(&addr, &transport->ipaddr, transport->af_specific->sockaddr_len);
0351
0352 event = sctp_ulpevent_make_peer_addr_change(asoc, &addr, 0, state,
0353 error, GFP_ATOMIC);
0354 if (event)
0355 asoc->stream.si->enqueue_event(&asoc->ulpq, event);
0356 }
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373 struct sctp_ulpevent *
0374 sctp_ulpevent_make_remote_error(const struct sctp_association *asoc,
0375 struct sctp_chunk *chunk, __u16 flags,
0376 gfp_t gfp)
0377 {
0378 struct sctp_remote_error *sre;
0379 struct sctp_ulpevent *event;
0380 struct sctp_errhdr *ch;
0381 struct sk_buff *skb;
0382 __be16 cause;
0383 int elen;
0384
0385 ch = (struct sctp_errhdr *)(chunk->skb->data);
0386 cause = ch->cause;
0387 elen = SCTP_PAD4(ntohs(ch->length)) - sizeof(*ch);
0388
0389
0390 skb_pull(chunk->skb, sizeof(*ch));
0391
0392
0393
0394
0395 skb = skb_copy_expand(chunk->skb, sizeof(*sre), 0, gfp);
0396
0397
0398 skb_pull(chunk->skb, elen);
0399 if (!skb)
0400 goto fail;
0401
0402
0403 event = sctp_skb2event(skb);
0404 sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
0405
0406 sre = skb_push(skb, sizeof(*sre));
0407
0408
0409 skb_trim(skb, sizeof(*sre) + elen);
0410
0411
0412 memset(sre, 0, sizeof(*sre));
0413 sre->sre_type = SCTP_REMOTE_ERROR;
0414 sre->sre_flags = 0;
0415 sre->sre_length = skb->len;
0416 sre->sre_error = cause;
0417 sctp_ulpevent_set_owner(event, asoc);
0418 sre->sre_assoc_id = sctp_assoc2id(asoc);
0419
0420 return event;
0421 fail:
0422 return NULL;
0423 }
0424
0425
0426
0427
0428
0429
0430 struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
0431 const struct sctp_association *asoc, struct sctp_chunk *chunk,
0432 __u16 flags, __u32 error, gfp_t gfp)
0433 {
0434 struct sctp_ulpevent *event;
0435 struct sctp_send_failed *ssf;
0436 struct sk_buff *skb;
0437
0438
0439 int len = ntohs(chunk->chunk_hdr->length);
0440
0441
0442 skb = skb_copy_expand(chunk->skb,
0443 sizeof(struct sctp_send_failed),
0444 0,
0445 gfp);
0446 if (!skb)
0447 goto fail;
0448
0449
0450 skb_pull(skb, sctp_datachk_len(&asoc->stream));
0451 len -= sctp_datachk_len(&asoc->stream);
0452
0453
0454 event = sctp_skb2event(skb);
0455 sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
0456
0457 ssf = skb_push(skb, sizeof(struct sctp_send_failed));
0458
0459
0460
0461
0462
0463
0464
0465 ssf->ssf_type = SCTP_SEND_FAILED;
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480 ssf->ssf_flags = flags;
0481
0482
0483
0484
0485
0486
0487
0488
0489 ssf->ssf_length = sizeof(struct sctp_send_failed) + len;
0490 skb_trim(skb, ssf->ssf_length);
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500 ssf->ssf_error = error;
0501
0502
0503
0504
0505
0506
0507
0508
0509 memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));
0510
0511
0512
0513
0514 ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags;
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525 sctp_ulpevent_set_owner(event, asoc);
0526 ssf->ssf_assoc_id = sctp_assoc2id(asoc);
0527 return event;
0528
0529 fail:
0530 return NULL;
0531 }
0532
0533 struct sctp_ulpevent *sctp_ulpevent_make_send_failed_event(
0534 const struct sctp_association *asoc, struct sctp_chunk *chunk,
0535 __u16 flags, __u32 error, gfp_t gfp)
0536 {
0537 struct sctp_send_failed_event *ssf;
0538 struct sctp_ulpevent *event;
0539 struct sk_buff *skb;
0540 int len;
0541
0542 skb = skb_copy_expand(chunk->skb, sizeof(*ssf), 0, gfp);
0543 if (!skb)
0544 return NULL;
0545
0546 len = ntohs(chunk->chunk_hdr->length);
0547 len -= sctp_datachk_len(&asoc->stream);
0548
0549 skb_pull(skb, sctp_datachk_len(&asoc->stream));
0550 event = sctp_skb2event(skb);
0551 sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
0552
0553 ssf = skb_push(skb, sizeof(*ssf));
0554 ssf->ssf_type = SCTP_SEND_FAILED_EVENT;
0555 ssf->ssf_flags = flags;
0556 ssf->ssf_length = sizeof(*ssf) + len;
0557 skb_trim(skb, ssf->ssf_length);
0558 ssf->ssf_error = error;
0559
0560 ssf->ssfe_info.snd_sid = chunk->sinfo.sinfo_stream;
0561 ssf->ssfe_info.snd_ppid = chunk->sinfo.sinfo_ppid;
0562 ssf->ssfe_info.snd_context = chunk->sinfo.sinfo_context;
0563 ssf->ssfe_info.snd_assoc_id = chunk->sinfo.sinfo_assoc_id;
0564 ssf->ssfe_info.snd_flags = chunk->chunk_hdr->flags;
0565
0566 sctp_ulpevent_set_owner(event, asoc);
0567 ssf->ssf_assoc_id = sctp_assoc2id(asoc);
0568
0569 return event;
0570 }
0571
0572
0573
0574
0575
0576
0577 struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
0578 const struct sctp_association *asoc,
0579 __u16 flags, gfp_t gfp)
0580 {
0581 struct sctp_ulpevent *event;
0582 struct sctp_shutdown_event *sse;
0583 struct sk_buff *skb;
0584
0585 event = sctp_ulpevent_new(sizeof(struct sctp_shutdown_event),
0586 MSG_NOTIFICATION, gfp);
0587 if (!event)
0588 goto fail;
0589
0590 skb = sctp_event2skb(event);
0591 sse = skb_put(skb, sizeof(struct sctp_shutdown_event));
0592
0593
0594
0595
0596
0597
0598
0599 sse->sse_type = SCTP_SHUTDOWN_EVENT;
0600
0601
0602
0603
0604
0605
0606
0607 sse->sse_flags = 0;
0608
0609
0610
0611
0612
0613
0614
0615
0616 sse->sse_length = sizeof(struct sctp_shutdown_event);
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626 sctp_ulpevent_set_owner(event, asoc);
0627 sse->sse_assoc_id = sctp_assoc2id(asoc);
0628
0629 return event;
0630
0631 fail:
0632 return NULL;
0633 }
0634
0635
0636
0637
0638
0639
0640 struct sctp_ulpevent *sctp_ulpevent_make_adaptation_indication(
0641 const struct sctp_association *asoc, gfp_t gfp)
0642 {
0643 struct sctp_ulpevent *event;
0644 struct sctp_adaptation_event *sai;
0645 struct sk_buff *skb;
0646
0647 event = sctp_ulpevent_new(sizeof(struct sctp_adaptation_event),
0648 MSG_NOTIFICATION, gfp);
0649 if (!event)
0650 goto fail;
0651
0652 skb = sctp_event2skb(event);
0653 sai = skb_put(skb, sizeof(struct sctp_adaptation_event));
0654
0655 sai->sai_type = SCTP_ADAPTATION_INDICATION;
0656 sai->sai_flags = 0;
0657 sai->sai_length = sizeof(struct sctp_adaptation_event);
0658 sai->sai_adaptation_ind = asoc->peer.adaptation_ind;
0659 sctp_ulpevent_set_owner(event, asoc);
0660 sai->sai_assoc_id = sctp_assoc2id(asoc);
0661
0662 return event;
0663
0664 fail:
0665 return NULL;
0666 }
0667
0668
0669
0670
0671
0672
0673
0674
0675 struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
0676 struct sctp_chunk *chunk,
0677 gfp_t gfp)
0678 {
0679 struct sctp_ulpevent *event = NULL;
0680 struct sk_buff *skb = chunk->skb;
0681 struct sock *sk = asoc->base.sk;
0682 size_t padding, datalen;
0683 int rx_count;
0684
0685
0686
0687
0688
0689
0690 if (asoc->ep->rcvbuf_policy)
0691 rx_count = atomic_read(&asoc->rmem_alloc);
0692 else
0693 rx_count = atomic_read(&sk->sk_rmem_alloc);
0694
0695 datalen = ntohs(chunk->chunk_hdr->length);
0696
0697 if (rx_count >= sk->sk_rcvbuf || !sk_rmem_schedule(sk, skb, datalen))
0698 goto fail;
0699
0700
0701 skb = skb_clone(chunk->skb, gfp);
0702 if (!skb)
0703 goto fail;
0704
0705
0706
0707
0708 if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
0709 ntohl(chunk->subh.data_hdr->tsn),
0710 chunk->transport))
0711 goto fail_mark;
0712
0713
0714
0715
0716
0717
0718
0719
0720
0721
0722
0723
0724
0725 padding = SCTP_PAD4(datalen) - datalen;
0726
0727
0728 skb_trim(skb, chunk->chunk_end - padding - skb->data);
0729
0730
0731 event = sctp_skb2event(skb);
0732
0733
0734
0735
0736
0737 sctp_ulpevent_init(event, 0, skb->len + sizeof(struct sk_buff));
0738
0739
0740
0741
0742 sctp_chunk_hold(chunk);
0743 event->chunk = chunk;
0744
0745 sctp_ulpevent_receive_data(event, asoc);
0746
0747 event->stream = ntohs(chunk->subh.data_hdr->stream);
0748 if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
0749 event->flags |= SCTP_UNORDERED;
0750 event->cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
0751 }
0752 event->tsn = ntohl(chunk->subh.data_hdr->tsn);
0753 event->msg_flags |= chunk->chunk_hdr->flags;
0754
0755 return event;
0756
0757 fail_mark:
0758 kfree_skb(skb);
0759 fail:
0760 return NULL;
0761 }
0762
0763
0764
0765
0766
0767
0768
0769
0770
0771 struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
0772 const struct sctp_association *asoc,
0773 __u32 indication, __u32 sid, __u32 seq,
0774 __u32 flags, gfp_t gfp)
0775 {
0776 struct sctp_ulpevent *event;
0777 struct sctp_pdapi_event *pd;
0778 struct sk_buff *skb;
0779
0780 event = sctp_ulpevent_new(sizeof(struct sctp_pdapi_event),
0781 MSG_NOTIFICATION, gfp);
0782 if (!event)
0783 goto fail;
0784
0785 skb = sctp_event2skb(event);
0786 pd = skb_put(skb, sizeof(struct sctp_pdapi_event));
0787
0788
0789
0790
0791
0792
0793
0794 pd->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT;
0795 pd->pdapi_flags = flags;
0796 pd->pdapi_stream = sid;
0797 pd->pdapi_seq = seq;
0798
0799
0800
0801
0802
0803
0804
0805 pd->pdapi_length = sizeof(struct sctp_pdapi_event);
0806
0807
0808
0809
0810
0811 pd->pdapi_indication = indication;
0812
0813
0814
0815
0816
0817 sctp_ulpevent_set_owner(event, asoc);
0818 pd->pdapi_assoc_id = sctp_assoc2id(asoc);
0819
0820 return event;
0821 fail:
0822 return NULL;
0823 }
0824
0825 struct sctp_ulpevent *sctp_ulpevent_make_authkey(
0826 const struct sctp_association *asoc, __u16 key_id,
0827 __u32 indication, gfp_t gfp)
0828 {
0829 struct sctp_ulpevent *event;
0830 struct sctp_authkey_event *ak;
0831 struct sk_buff *skb;
0832
0833 event = sctp_ulpevent_new(sizeof(struct sctp_authkey_event),
0834 MSG_NOTIFICATION, gfp);
0835 if (!event)
0836 goto fail;
0837
0838 skb = sctp_event2skb(event);
0839 ak = skb_put(skb, sizeof(struct sctp_authkey_event));
0840
0841 ak->auth_type = SCTP_AUTHENTICATION_EVENT;
0842 ak->auth_flags = 0;
0843 ak->auth_length = sizeof(struct sctp_authkey_event);
0844
0845 ak->auth_keynumber = key_id;
0846 ak->auth_altkeynumber = 0;
0847 ak->auth_indication = indication;
0848
0849
0850
0851
0852 sctp_ulpevent_set_owner(event, asoc);
0853 ak->auth_assoc_id = sctp_assoc2id(asoc);
0854
0855 return event;
0856 fail:
0857 return NULL;
0858 }
0859
0860
0861
0862
0863
0864 struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event(
0865 const struct sctp_association *asoc, gfp_t gfp)
0866 {
0867 struct sctp_ulpevent *event;
0868 struct sctp_sender_dry_event *sdry;
0869 struct sk_buff *skb;
0870
0871 event = sctp_ulpevent_new(sizeof(struct sctp_sender_dry_event),
0872 MSG_NOTIFICATION, gfp);
0873 if (!event)
0874 return NULL;
0875
0876 skb = sctp_event2skb(event);
0877 sdry = skb_put(skb, sizeof(struct sctp_sender_dry_event));
0878
0879 sdry->sender_dry_type = SCTP_SENDER_DRY_EVENT;
0880 sdry->sender_dry_flags = 0;
0881 sdry->sender_dry_length = sizeof(struct sctp_sender_dry_event);
0882 sctp_ulpevent_set_owner(event, asoc);
0883 sdry->sender_dry_assoc_id = sctp_assoc2id(asoc);
0884
0885 return event;
0886 }
0887
0888 struct sctp_ulpevent *sctp_ulpevent_make_stream_reset_event(
0889 const struct sctp_association *asoc, __u16 flags, __u16 stream_num,
0890 __be16 *stream_list, gfp_t gfp)
0891 {
0892 struct sctp_stream_reset_event *sreset;
0893 struct sctp_ulpevent *event;
0894 struct sk_buff *skb;
0895 int length, i;
0896
0897 length = sizeof(struct sctp_stream_reset_event) + 2 * stream_num;
0898 event = sctp_ulpevent_new(length, MSG_NOTIFICATION, gfp);
0899 if (!event)
0900 return NULL;
0901
0902 skb = sctp_event2skb(event);
0903 sreset = skb_put(skb, length);
0904
0905 sreset->strreset_type = SCTP_STREAM_RESET_EVENT;
0906 sreset->strreset_flags = flags;
0907 sreset->strreset_length = length;
0908 sctp_ulpevent_set_owner(event, asoc);
0909 sreset->strreset_assoc_id = sctp_assoc2id(asoc);
0910
0911 for (i = 0; i < stream_num; i++)
0912 sreset->strreset_stream_list[i] = ntohs(stream_list[i]);
0913
0914 return event;
0915 }
0916
0917 struct sctp_ulpevent *sctp_ulpevent_make_assoc_reset_event(
0918 const struct sctp_association *asoc, __u16 flags, __u32 local_tsn,
0919 __u32 remote_tsn, gfp_t gfp)
0920 {
0921 struct sctp_assoc_reset_event *areset;
0922 struct sctp_ulpevent *event;
0923 struct sk_buff *skb;
0924
0925 event = sctp_ulpevent_new(sizeof(struct sctp_assoc_reset_event),
0926 MSG_NOTIFICATION, gfp);
0927 if (!event)
0928 return NULL;
0929
0930 skb = sctp_event2skb(event);
0931 areset = skb_put(skb, sizeof(struct sctp_assoc_reset_event));
0932
0933 areset->assocreset_type = SCTP_ASSOC_RESET_EVENT;
0934 areset->assocreset_flags = flags;
0935 areset->assocreset_length = sizeof(struct sctp_assoc_reset_event);
0936 sctp_ulpevent_set_owner(event, asoc);
0937 areset->assocreset_assoc_id = sctp_assoc2id(asoc);
0938 areset->assocreset_local_tsn = local_tsn;
0939 areset->assocreset_remote_tsn = remote_tsn;
0940
0941 return event;
0942 }
0943
0944 struct sctp_ulpevent *sctp_ulpevent_make_stream_change_event(
0945 const struct sctp_association *asoc, __u16 flags,
0946 __u32 strchange_instrms, __u32 strchange_outstrms, gfp_t gfp)
0947 {
0948 struct sctp_stream_change_event *schange;
0949 struct sctp_ulpevent *event;
0950 struct sk_buff *skb;
0951
0952 event = sctp_ulpevent_new(sizeof(struct sctp_stream_change_event),
0953 MSG_NOTIFICATION, gfp);
0954 if (!event)
0955 return NULL;
0956
0957 skb = sctp_event2skb(event);
0958 schange = skb_put(skb, sizeof(struct sctp_stream_change_event));
0959
0960 schange->strchange_type = SCTP_STREAM_CHANGE_EVENT;
0961 schange->strchange_flags = flags;
0962 schange->strchange_length = sizeof(struct sctp_stream_change_event);
0963 sctp_ulpevent_set_owner(event, asoc);
0964 schange->strchange_assoc_id = sctp_assoc2id(asoc);
0965 schange->strchange_instrms = strchange_instrms;
0966 schange->strchange_outstrms = strchange_outstrms;
0967
0968 return event;
0969 }
0970
0971
0972
0973
0974 __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event)
0975 {
0976 union sctp_notification *notification;
0977 struct sk_buff *skb;
0978
0979 skb = sctp_event2skb(event);
0980 notification = (union sctp_notification *) skb->data;
0981 return notification->sn_header.sn_type;
0982 }
0983
0984
0985
0986
0987 void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
0988 struct msghdr *msghdr)
0989 {
0990 struct sctp_sndrcvinfo sinfo;
0991
0992 if (sctp_ulpevent_is_notification(event))
0993 return;
0994
0995 memset(&sinfo, 0, sizeof(sinfo));
0996 sinfo.sinfo_stream = event->stream;
0997 sinfo.sinfo_ssn = event->ssn;
0998 sinfo.sinfo_ppid = event->ppid;
0999 sinfo.sinfo_flags = event->flags;
1000 sinfo.sinfo_tsn = event->tsn;
1001 sinfo.sinfo_cumtsn = event->cumtsn;
1002 sinfo.sinfo_assoc_id = sctp_assoc2id(event->asoc);
1003
1004 sinfo.sinfo_context = event->asoc->default_rcv_context;
1005
1006 sinfo.sinfo_timetolive = 0;
1007
1008 put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
1009 sizeof(sinfo), &sinfo);
1010 }
1011
1012
1013
1014
1015 void sctp_ulpevent_read_rcvinfo(const struct sctp_ulpevent *event,
1016 struct msghdr *msghdr)
1017 {
1018 struct sctp_rcvinfo rinfo;
1019
1020 if (sctp_ulpevent_is_notification(event))
1021 return;
1022
1023 memset(&rinfo, 0, sizeof(struct sctp_rcvinfo));
1024 rinfo.rcv_sid = event->stream;
1025 rinfo.rcv_ssn = event->ssn;
1026 rinfo.rcv_ppid = event->ppid;
1027 rinfo.rcv_flags = event->flags;
1028 rinfo.rcv_tsn = event->tsn;
1029 rinfo.rcv_cumtsn = event->cumtsn;
1030 rinfo.rcv_assoc_id = sctp_assoc2id(event->asoc);
1031 rinfo.rcv_context = event->asoc->default_rcv_context;
1032
1033 put_cmsg(msghdr, IPPROTO_SCTP, SCTP_RCVINFO,
1034 sizeof(rinfo), &rinfo);
1035 }
1036
1037
1038
1039
1040 static void __sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event,
1041 struct msghdr *msghdr,
1042 const struct sk_buff *skb)
1043 {
1044 struct sctp_nxtinfo nxtinfo;
1045
1046 memset(&nxtinfo, 0, sizeof(nxtinfo));
1047 nxtinfo.nxt_sid = event->stream;
1048 nxtinfo.nxt_ppid = event->ppid;
1049 nxtinfo.nxt_flags = event->flags;
1050 if (sctp_ulpevent_is_notification(event))
1051 nxtinfo.nxt_flags |= SCTP_NOTIFICATION;
1052 nxtinfo.nxt_length = skb->len;
1053 nxtinfo.nxt_assoc_id = sctp_assoc2id(event->asoc);
1054
1055 put_cmsg(msghdr, IPPROTO_SCTP, SCTP_NXTINFO,
1056 sizeof(nxtinfo), &nxtinfo);
1057 }
1058
1059 void sctp_ulpevent_read_nxtinfo(const struct sctp_ulpevent *event,
1060 struct msghdr *msghdr,
1061 struct sock *sk)
1062 {
1063 struct sk_buff *skb;
1064 int err;
1065
1066 skb = sctp_skb_recv_datagram(sk, MSG_PEEK | MSG_DONTWAIT, &err);
1067 if (skb != NULL) {
1068 __sctp_ulpevent_read_nxtinfo(sctp_skb2event(skb),
1069 msghdr, skb);
1070
1071 kfree_skb(skb);
1072 }
1073 }
1074
1075
1076
1077
1078 static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
1079 struct sctp_association *asoc)
1080 {
1081 struct sk_buff *skb, *frag;
1082
1083 skb = sctp_event2skb(event);
1084
1085 sctp_ulpevent_set_owner(event, asoc);
1086 sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb));
1087
1088 if (!skb->data_len)
1089 return;
1090
1091
1092
1093
1094
1095
1096
1097 skb_walk_frags(skb, frag)
1098 sctp_ulpevent_receive_data(sctp_skb2event(frag), asoc);
1099 }
1100
1101
1102
1103
1104 static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
1105 {
1106 struct sk_buff *skb, *frag;
1107 unsigned int len;
1108
1109
1110
1111
1112
1113
1114
1115
1116 skb = sctp_event2skb(event);
1117 len = skb->len;
1118
1119 if (!skb->data_len)
1120 goto done;
1121
1122
1123 skb_walk_frags(skb, frag) {
1124
1125
1126
1127
1128 sctp_ulpevent_release_frag_data(sctp_skb2event(frag));
1129 }
1130
1131 done:
1132 sctp_assoc_rwnd_increase(event->asoc, len);
1133 sctp_chunk_put(event->chunk);
1134 sctp_ulpevent_release_owner(event);
1135 }
1136
1137 static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event)
1138 {
1139 struct sk_buff *skb, *frag;
1140
1141 skb = sctp_event2skb(event);
1142
1143 if (!skb->data_len)
1144 goto done;
1145
1146
1147 skb_walk_frags(skb, frag) {
1148
1149
1150
1151
1152 sctp_ulpevent_release_frag_data(sctp_skb2event(frag));
1153 }
1154
1155 done:
1156 sctp_chunk_put(event->chunk);
1157 sctp_ulpevent_release_owner(event);
1158 }
1159
1160
1161
1162
1163
1164 void sctp_ulpevent_free(struct sctp_ulpevent *event)
1165 {
1166 if (sctp_ulpevent_is_notification(event))
1167 sctp_ulpevent_release_owner(event);
1168 else
1169 sctp_ulpevent_release_data(event);
1170
1171 kfree_skb(sctp_event2skb(event));
1172 }
1173
1174
1175 unsigned int sctp_queue_purge_ulpevents(struct sk_buff_head *list)
1176 {
1177 struct sk_buff *skb;
1178 unsigned int data_unread = 0;
1179
1180 while ((skb = skb_dequeue(list)) != NULL) {
1181 struct sctp_ulpevent *event = sctp_skb2event(skb);
1182
1183 if (!sctp_ulpevent_is_notification(event))
1184 data_unread += skb->len;
1185
1186 sctp_ulpevent_free(event);
1187 }
1188
1189 return data_unread;
1190 }