| 5364 | } |
| 5365 | |
| 5366 | static void |
| 5367 | sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t *freed_so_far, int hold_rlock, |
| 5368 | uint32_t rwnd_req) |
| 5369 | { |
| 5370 | /* User pulled some data, do we need a rwnd update? */ |
| 5371 | struct epoch_tracker et; |
| 5372 | int r_unlocked = 0; |
| 5373 | uint32_t dif, rwnd; |
| 5374 | struct socket *so = NULL; |
| 5375 | |
| 5376 | if (stcb == NULL) |
| 5377 | return; |
| 5378 | |
| 5379 | atomic_add_int(&stcb->asoc.refcnt, 1); |
| 5380 | |
| 5381 | if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) || |
| 5382 | (stcb->asoc.state & (SCTP_STATE_ABOUT_TO_BE_FREED | SCTP_STATE_SHUTDOWN_RECEIVED))) { |
| 5383 | /* Pre-check If we are freeing no update */ |
| 5384 | goto no_lock; |
| 5385 | } |
| 5386 | SCTP_INP_INCR_REF(stcb->sctp_ep); |
| 5387 | if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || |
| 5388 | (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { |
| 5389 | goto out; |
| 5390 | } |
| 5391 | so = stcb->sctp_socket; |
| 5392 | if (so == NULL) { |
| 5393 | goto out; |
| 5394 | } |
| 5395 | atomic_add_int(&stcb->freed_by_sorcv_sincelast, *freed_so_far); |
| 5396 | /* Have you have freed enough to look */ |
| 5397 | *freed_so_far = 0; |
| 5398 | /* Yep, its worth a look and the lock overhead */ |
| 5399 | |
| 5400 | /* Figure out what the rwnd would be */ |
| 5401 | rwnd = sctp_calc_rwnd(stcb, &stcb->asoc); |
| 5402 | if (rwnd >= stcb->asoc.my_last_reported_rwnd) { |
| 5403 | dif = rwnd - stcb->asoc.my_last_reported_rwnd; |
| 5404 | } else { |
| 5405 | dif = 0; |
| 5406 | } |
| 5407 | if (dif >= rwnd_req) { |
| 5408 | if (hold_rlock) { |
| 5409 | SCTP_INP_READ_UNLOCK(stcb->sctp_ep); |
| 5410 | r_unlocked = 1; |
| 5411 | } |
| 5412 | if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { |
| 5413 | /* |
| 5414 | * One last check before we allow the guy possibly |
| 5415 | * to get in. There is a race, where the guy has not |
| 5416 | * reached the gate. In that case |
| 5417 | */ |
| 5418 | goto out; |
| 5419 | } |
| 5420 | SCTP_TCB_LOCK(stcb); |
| 5421 | if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { |
| 5422 | /* No reports here */ |
| 5423 | SCTP_TCB_UNLOCK(stcb); |
no test coverage detected