===================================================================
@@ -350,6 +350,206 @@
h->ecn_nonce_sum = !h->ecn_nonce_sum;
}
+/*
+ * tfrc_sp_check_ecn_sum - check received ecn sum parsed from
+ * loss interval option
+ * li_data: data parsed from options
+ * optval: data from option
+ * optlen: option data length
+ * skb: last received packet
+ */
+bool tfrc_sp_check_ecn_sum(struct tfrc_tx_li_data *li_data, u8 *optval,
+ u8 optlen, struct sk_buff *skb)
+{
+ u8 skip_length;
+ u32 data_length;
+ u8 sum0, sum1, li_sum;
+ struct tfrc_ecn_echo_sum_entry *entry;
+ u64 seqn;
+
+ if ((optlen < 10) || ((optlen - 1)%3 != 0))
+ return false;
+
+ if (li_data == NULL)
+ return true;
+
+ entry = li_data->ecn_sums_head;
+
+ if (entry == NULL)
+ return true;
+
+ seqn = dccp_hdr_ack_seq(skb);
+
+ while (entry->seq_num != seqn) {
+ entry = entry->previous;
+
+ if (entry == NULL)
+ return true;
+ }
+
+ skip_length = *optval;
+ optval++;
+ optlen--;
+
+ while (skip_length--) {
+ entry = entry->previous;
+
+ if (entry == NULL)
+ return false;
+ }
+
+ optval += 3;
+ optlen -= 3;
+
+ do {
+ sum0 = entry->ecn_echo_sum;
+
+ li_sum = (*((u32 *)optval)&0x80000000) ? 1 : 0;
+
+ optval += 3;
+ optlen -= 3;
+
+ data_length = ntohl((*((u32 *)optval) & 0xFFFFFF00) >> 8);
+
+ while (--data_length) {
+ entry = entry->previous;
+
+ if (entry == NULL)
+ return true;
+ }
+
+ sum1 = entry->ecn_echo_sum;
+
+ if (((sum0+sum1) & 0x1) != li_sum)
+ return false;
+
+ optval += 6;
+ optlen -= 6;
+
+ } while (optlen >= 9);
+
+ if (entry != NULL)
+ tfrc_sp_tx_ld_cleanup(&entry->previous);
+
+ return true;
+}
+
+static struct tfrc_tx_hist_entry*
+ tfrc_sp_seek_tx_entry(struct tfrc_tx_hist_entry *head,
+ u64 seqno, u32 backward)
+{
+ if (head == NULL)
+ return NULL;
+
+ while (head->seqno != seqno) {
+ head = head->next;
+
+ if (head == NULL)
+ return NULL;
+ }
+
+ while (backward-- > 0) {
+ head = head->next;
+
+ if (head == NULL)
+ return NULL;
+ }
+
+ return head;
+}
+
+/*
+ * tfrc_sp_p_from_loss_intervals_opt - calcs p from loss interval option
+ * li_data: data parsed from options
+ * head: contains ccval info
+ * curr_ccval: current ccval
+ * seqno: last acked seqno
+ */
+u32 tfrc_sp_p_from_loss_intervals_opt(struct tfrc_tx_li_data *li_data,
+ struct tfrc_tx_hist_entry *head,
+ u8 curr_ccval, u64 seqno)
+{
+ int i, k;
+ u8 ccval;
+ u32 i_i, i_tot0, i_tot1, w_tot, i_totl, losses, mean;
+ i_tot0 = i_tot1 = w_tot = i_totl = 0;
+
+ if (li_data->loss_interval_data[0] == 0)
+ return 0;
+
+ if (li_data->loss_interval_data[0] < li_data->dropped_packets_data[0])
+ return 0;
+
+ k = li_data->loss_interval_data[0];
+
+ for (i = 1; i <= k; i++) {
+ i_i = li_data->loss_interval_data[i];
+ i_totl += i_i;
+ ccval = tfrc_sp_seek_tx_entry(head, seqno, i_totl - 1)->ccval;
+
+ if (SUB16(curr_ccval, ccval) <= 8) {
+ losses = li_data->dropped_packets_data[i];
+
+ if (losses > 0)
+ i_i = div64_u64(i_i, losses);
+ }
+
+ if (i != k) {
+ i_tot0 += i_i * tfrc_lh_weights[i-1];
+ w_tot += tfrc_lh_weights[i-1];
+ }
+
+ if (i > 1)
+ i_tot1 += i_i * tfrc_lh_weights[i-2];
+ }
+
+ ccval = tfrc_sp_seek_tx_entry(head, seqno,
+ li_data->loss_interval_data[1] - 1)->ccval;
+
+ if (SUB16(curr_ccval, ccval) > 8)
+ mean = max(i_tot0, i_tot1) / w_tot;
+ else
+ mean = i_tot1 / w_tot;
+
+ return tfrc_sp_invert_loss_event_rate(mean);
+
+ return 0;
+}
+
+/*
+ * tfrc_sp_parse_dropped_packets_opt - parses received dropped packets option
+ * li_data: used to store parsed data
+ * optval: option data
+ * optlen: option length
+ */
+void tfrc_sp_parse_dropped_packets_opt(struct tfrc_tx_li_data *li_data,
+ u8 *optval, u8 optlen)
+{
+ u8 pos;
+ u32 dropped;
+
+ if ((optlen%3) != 0) {
+ li_data->dropped_packets_data[0] = 0;
+ return;
+ }
+
+ pos = 0;
+
+ while (pos < optlen) {
+ dropped = ntohl(((*((u32 *)(optval + pos))) & 0xFFFFFF00) >> 8);
+ li_data->dropped_packets_data[1 + (pos/3)] = dropped;
+
+ if ((pos/3) == 9) {
+ li_data->dropped_packets_data[0] = 9;
+ return;
+ }
+
+ pos += 3;
+ }
+
+ li_data->dropped_packets_data[0] = optlen/3;
+}
+
static void tfrc_sp_lh_calc_i_mean(struct tfrc_loss_hist *lh, __u8 curr_ccval)
{
u32 i_i, i_tot0 = 0, i_tot1 = 0, w_tot = 0;
@@ -400,7 +600,10 @@
if (cur == NULL) /* not initialised */
return;
- /* FIXME: should probably also count non-data packets (RFC 4342, 6.1) */
+ /*
+ * FIXME: should probably also count non-data packets
+ * (RFC 4342, 6.1)
+ */
if (!dccp_data_packet(skb))
return;
===================================================================
@@ -169,6 +169,14 @@
extern void tfrc_sp_ld_cleanup(struct tfrc_loss_data *ld);
extern void tfrc_sp_ld_prepare_data(u8 loss_count, struct tfrc_loss_data *ld);
extern int tfrc_sp_get_random_ect(struct tfrc_tx_li_data *li_data, u64 seqn);
+extern bool tfrc_sp_check_ecn_sum(struct tfrc_tx_li_data *li_data, u8 *optval,
+ u8 optlen, struct sk_buff *skb);
+struct tfrc_tx_hist_entry;
+extern u32 tfrc_sp_p_from_loss_intervals_opt(struct tfrc_tx_li_data *li_data,
+ struct tfrc_tx_hist_entry *head,
+ u8 curr_ccval, u64 seqno);
+extern void tfrc_sp_parse_dropped_packets_opt(struct tfrc_tx_li_data *li_data,
+ u8 *optval, u8 optlen);
extern void tfrc_sp_tx_ld_cleanup(struct tfrc_ecn_echo_sum_entry **);
#endif /* _DCCP_LI_HIST_SP_ */