📄 ccid3.c
字号:
packet = dccp_rx_hist_find_data_packet(&hcrx->ccid3hcrx_hist); if (unlikely(packet == NULL)) { DCCP_WARN("%s(%p), no data packet in history!\n", dccp_role(sk), sk); return; } hcrx->ccid3hcrx_tstamp_last_feedback = now; hcrx->ccid3hcrx_ccval_last_counter = packet->dccphrx_ccval; hcrx->ccid3hcrx_bytes_recv = 0; /* Elapsed time information [RFC 4340, 13.2] in units of 10 * usecs */ delta = ktime_us_delta(now, packet->dccphrx_tstamp); DCCP_BUG_ON(delta < 0); hcrx->ccid3hcrx_elapsed_time = delta / 10; if (hcrx->ccid3hcrx_p == 0) hcrx->ccid3hcrx_pinv = ~0U; /* see RFC 4342, 8.5 */ else if (hcrx->ccid3hcrx_p > 1000000) { DCCP_WARN("p (%u) > 100%%\n", hcrx->ccid3hcrx_p); hcrx->ccid3hcrx_pinv = 1; /* use 100% in this case */ } else hcrx->ccid3hcrx_pinv = 1000000 / hcrx->ccid3hcrx_p; dp->dccps_hc_rx_insert_options = 1; dccp_send_ack(sk);}static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb){ const struct ccid3_hc_rx_sock *hcrx; __be32 x_recv, pinv; if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)) return 0; hcrx = ccid3_hc_rx_sk(sk); DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_ccval_last_counter; if (dccp_packet_without_ack(skb)) return 0; x_recv = htonl(hcrx->ccid3hcrx_x_recv); pinv = htonl(hcrx->ccid3hcrx_pinv); if ((hcrx->ccid3hcrx_elapsed_time != 0 && dccp_insert_option_elapsed_time(sk, skb, hcrx->ccid3hcrx_elapsed_time)) || dccp_insert_option_timestamp(sk, skb) || dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE, &pinv, sizeof(pinv)) || dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE, &x_recv, sizeof(x_recv))) return -1; return 0;}static int ccid3_hc_rx_detect_loss(struct sock *sk, struct dccp_rx_hist_entry *packet){ struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); struct dccp_rx_hist_entry *rx_hist = dccp_rx_hist_head(&hcrx->ccid3hcrx_hist); u64 seqno = packet->dccphrx_seqno; u64 tmp_seqno; int loss = 0; u8 ccval; tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss; if (!rx_hist || follows48(packet->dccphrx_seqno, hcrx->ccid3hcrx_seqno_nonloss)) { hcrx->ccid3hcrx_seqno_nonloss = seqno; hcrx->ccid3hcrx_ccval_nonloss = packet->dccphrx_ccval; goto detect_out; } while (dccp_delta_seqno(hcrx->ccid3hcrx_seqno_nonloss, seqno) > TFRC_RECV_NUM_LATE_LOSS) { loss = 1; dccp_li_update_li(sk, &hcrx->ccid3hcrx_li_hist, &hcrx->ccid3hcrx_hist, hcrx->ccid3hcrx_tstamp_last_feedback, hcrx->ccid3hcrx_s, hcrx->ccid3hcrx_bytes_recv, hcrx->ccid3hcrx_x_recv, hcrx->ccid3hcrx_seqno_nonloss, hcrx->ccid3hcrx_ccval_nonloss); tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss; dccp_inc_seqno(&tmp_seqno); hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno; dccp_inc_seqno(&tmp_seqno); while (dccp_rx_hist_find_entry(&hcrx->ccid3hcrx_hist, tmp_seqno, &ccval)) { hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno; hcrx->ccid3hcrx_ccval_nonloss = ccval; dccp_inc_seqno(&tmp_seqno); } } /* FIXME - this code could be simplified with above while */ /* but works at moment */ if (follows48(packet->dccphrx_seqno, hcrx->ccid3hcrx_seqno_nonloss)) { hcrx->ccid3hcrx_seqno_nonloss = seqno; hcrx->ccid3hcrx_ccval_nonloss = packet->dccphrx_ccval; }detect_out: dccp_rx_hist_add_packet(ccid3_rx_hist, &hcrx->ccid3hcrx_hist, &hcrx->ccid3hcrx_li_hist, packet, hcrx->ccid3hcrx_seqno_nonloss); return loss;}static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb){ struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); const struct dccp_options_received *opt_recv; struct dccp_rx_hist_entry *packet; u32 p_prev, r_sample, rtt_prev; int loss, payload_size; ktime_t now; opt_recv = &dccp_sk(sk)->dccps_options_received; switch (DCCP_SKB_CB(skb)->dccpd_type) { case DCCP_PKT_ACK: if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA) return; case DCCP_PKT_DATAACK: if (opt_recv->dccpor_timestamp_echo == 0) break; r_sample = dccp_timestamp() - opt_recv->dccpor_timestamp_echo; rtt_prev = hcrx->ccid3hcrx_rtt; r_sample = dccp_sample_rtt(sk, 10 * r_sample); if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA) hcrx->ccid3hcrx_rtt = r_sample; else hcrx->ccid3hcrx_rtt = (hcrx->ccid3hcrx_rtt * 9) / 10 + r_sample / 10; if (rtt_prev != hcrx->ccid3hcrx_rtt) ccid3_pr_debug("%s(%p), New RTT=%uus, elapsed time=%u\n", dccp_role(sk), sk, hcrx->ccid3hcrx_rtt, opt_recv->dccpor_elapsed_time); break; case DCCP_PKT_DATA: break; default: /* We're not interested in other packet types, move along */ return; } packet = dccp_rx_hist_entry_new(ccid3_rx_hist, opt_recv->dccpor_ndp, skb, GFP_ATOMIC); if (unlikely(packet == NULL)) { DCCP_WARN("%s(%p), Not enough mem to add rx packet " "to history, consider it lost!\n", dccp_role(sk), sk); return; } loss = ccid3_hc_rx_detect_loss(sk, packet); if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK) return; payload_size = skb->len - dccp_hdr(skb)->dccph_doff * 4; ccid3_hc_rx_update_s(hcrx, payload_size); switch (hcrx->ccid3hcrx_state) { case TFRC_RSTATE_NO_DATA: ccid3_pr_debug("%s(%p, state=%s), skb=%p, sending initial " "feedback\n", dccp_role(sk), sk, dccp_state_name(sk->sk_state), skb); ccid3_hc_rx_send_feedback(sk); ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA); return; case TFRC_RSTATE_DATA: hcrx->ccid3hcrx_bytes_recv += payload_size; if (loss) break; now = ktime_get_real(); if ((ktime_us_delta(now, hcrx->ccid3hcrx_tstamp_last_ack) - (s64)hcrx->ccid3hcrx_rtt) >= 0) { hcrx->ccid3hcrx_tstamp_last_ack = now; ccid3_hc_rx_send_feedback(sk); } return; case TFRC_RSTATE_TERM: DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk); return; } /* Dealing with packet loss */ ccid3_pr_debug("%s(%p, state=%s), data loss! Reacting...\n", dccp_role(sk), sk, dccp_state_name(sk->sk_state)); p_prev = hcrx->ccid3hcrx_p; /* Calculate loss event rate */ if (!list_empty(&hcrx->ccid3hcrx_li_hist)) { u32 i_mean = dccp_li_hist_calc_i_mean(&hcrx->ccid3hcrx_li_hist); /* Scaling up by 1000000 as fixed decimal */ if (i_mean != 0) hcrx->ccid3hcrx_p = 1000000 / i_mean; } else DCCP_BUG("empty loss history"); if (hcrx->ccid3hcrx_p > p_prev) { ccid3_hc_rx_send_feedback(sk); return; }}static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk){ struct ccid3_hc_rx_sock *hcrx = ccid_priv(ccid); ccid3_pr_debug("entry\n"); hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA; INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist); INIT_LIST_HEAD(&hcrx->ccid3hcrx_li_hist); hcrx->ccid3hcrx_tstamp_last_feedback = hcrx->ccid3hcrx_tstamp_last_ack = ktime_get_real(); return 0;}static void ccid3_hc_rx_exit(struct sock *sk){ struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM); /* Empty packet history */ dccp_rx_hist_purge(ccid3_rx_hist, &hcrx->ccid3hcrx_hist); /* Empty loss interval history */ dccp_li_hist_purge(&hcrx->ccid3hcrx_li_hist);}static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info){ const struct ccid3_hc_rx_sock *hcrx; /* Listen socks doesn't have a private CCID block */ if (sk->sk_state == DCCP_LISTEN) return; hcrx = ccid3_hc_rx_sk(sk); info->tcpi_ca_state = hcrx->ccid3hcrx_state; info->tcpi_options |= TCPI_OPT_TIMESTAMPS; info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt;}static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len, u32 __user *optval, int __user *optlen){ const struct ccid3_hc_rx_sock *hcrx; const void *val; /* Listen socks doesn't have a private CCID block */ if (sk->sk_state == DCCP_LISTEN) return -EINVAL; hcrx = ccid3_hc_rx_sk(sk); switch (optname) { case DCCP_SOCKOPT_CCID_RX_INFO: if (len < sizeof(hcrx->ccid3hcrx_tfrc)) return -EINVAL; len = sizeof(hcrx->ccid3hcrx_tfrc); val = &hcrx->ccid3hcrx_tfrc; break; default: return -ENOPROTOOPT; } if (put_user(len, optlen) || copy_to_user(optval, val, len)) return -EFAULT; return 0;}static struct ccid_operations ccid3 = { .ccid_id = DCCPC_CCID3, .ccid_name = "ccid3", .ccid_owner = THIS_MODULE, .ccid_hc_tx_obj_size = sizeof(struct ccid3_hc_tx_sock), .ccid_hc_tx_init = ccid3_hc_tx_init, .ccid_hc_tx_exit = ccid3_hc_tx_exit, .ccid_hc_tx_send_packet = ccid3_hc_tx_send_packet, .ccid_hc_tx_packet_sent = ccid3_hc_tx_packet_sent, .ccid_hc_tx_packet_recv = ccid3_hc_tx_packet_recv, .ccid_hc_tx_parse_options = ccid3_hc_tx_parse_options, .ccid_hc_rx_obj_size = sizeof(struct ccid3_hc_rx_sock), .ccid_hc_rx_init = ccid3_hc_rx_init, .ccid_hc_rx_exit = ccid3_hc_rx_exit, .ccid_hc_rx_insert_options = ccid3_hc_rx_insert_options, .ccid_hc_rx_packet_recv = ccid3_hc_rx_packet_recv, .ccid_hc_rx_get_info = ccid3_hc_rx_get_info, .ccid_hc_tx_get_info = ccid3_hc_tx_get_info, .ccid_hc_rx_getsockopt = ccid3_hc_rx_getsockopt, .ccid_hc_tx_getsockopt = ccid3_hc_tx_getsockopt,};#ifdef CONFIG_IP_DCCP_CCID3_DEBUGmodule_param(ccid3_debug, bool, 0444);MODULE_PARM_DESC(ccid3_debug, "Enable debug messages");#endifstatic __init int ccid3_module_init(void){ int rc = -ENOBUFS; ccid3_rx_hist = dccp_rx_hist_new("ccid3"); if (ccid3_rx_hist == NULL) goto out; ccid3_tx_hist = dccp_tx_hist_new("ccid3"); if (ccid3_tx_hist == NULL) goto out_free_rx; rc = ccid_register(&ccid3); if (rc != 0) goto out_free_tx;out: return rc;out_free_tx: dccp_tx_hist_delete(ccid3_tx_hist); ccid3_tx_hist = NULL;out_free_rx: dccp_rx_hist_delete(ccid3_rx_hist); ccid3_rx_hist = NULL; goto out;}module_init(ccid3_module_init);static __exit void ccid3_module_exit(void){ ccid_unregister(&ccid3); if (ccid3_tx_hist != NULL) { dccp_tx_hist_delete(ccid3_tx_hist); ccid3_tx_hist = NULL; } if (ccid3_rx_hist != NULL) { dccp_rx_hist_delete(ccid3_rx_hist); ccid3_rx_hist = NULL; }}module_exit(ccid3_module_exit);MODULE_AUTHOR("Ian McDonald <ian.mcdonald@jandi.co.nz>, " "Arnaldo Carvalho de Melo <acme@ghostprotocols.net>");MODULE_DESCRIPTION("DCCP TFRC CCID3 CCID");MODULE_LICENSE("GPL");MODULE_ALIAS("net-dccp-ccid-3");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -