Fabio Ludovici <fabio.ludovici at yahoo.it>
 */
 
+struct disttable {
+       u32  size;
+       s16 table[0];
+};
+
 struct netem_sched_data {
        /* internal t(ime)fifo qdisc uses t_root and sch->limit */
        struct rb_root t_root;
                u32 rho;
        } delay_cor, loss_cor, dup_cor, reorder_cor, corrupt_cor;
 
-       struct disttable {
-               u32  size;
-               s16 table[0];
-       } *delay_dist;
+       struct disttable *delay_dist;
 
        enum  {
                CLG_RANDOM,
                s32 bytes_left;
        } slot;
 
+       struct disttable *slot_dist;
 };
 
 /* Time stamp put into socket buffer control block
        u64 value, rho;
        unsigned long answer;
 
-       if (state->rho == 0)    /* no correlation */
+       if (!state || state->rho == 0)  /* no correlation */
                return prandom_u32();
 
        value = prandom_u32();
 
 static void get_slot_next(struct netem_sched_data *q, u64 now)
 {
-       q->slot.slot_next = now + q->slot_config.min_delay +
-               (prandom_u32() *
-                       (q->slot_config.max_delay -
-                               q->slot_config.min_delay) >> 32);
+       s64 next_delay;
+
+       if (!q->slot_dist)
+               next_delay = q->slot_config.min_delay +
+                               (prandom_u32() *
+                                (q->slot_config.max_delay -
+                                 q->slot_config.min_delay) >> 32);
+       else
+               next_delay = tabledist(q->slot_config.dist_delay,
+                                      (s32)(q->slot_config.dist_jitter),
+                                      NULL, q->slot_dist);
+
+       q->slot.slot_next = now + next_delay;
        q->slot.packets_left = q->slot_config.max_packets;
        q->slot.bytes_left = q->slot_config.max_bytes;
 }
  * signed 16 bit values.
  */
 
-static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
+static int get_dist_table(struct Qdisc *sch, struct disttable **tbl,
+                         const struct nlattr *attr)
 {
-       struct netem_sched_data *q = qdisc_priv(sch);
        size_t n = nla_len(attr)/sizeof(__s16);
        const __s16 *data = nla_data(attr);
        spinlock_t *root_lock;
        root_lock = qdisc_root_sleeping_lock(sch);
 
        spin_lock_bh(root_lock);
-       swap(q->delay_dist, d);
+       swap(*tbl, d);
        spin_unlock_bh(root_lock);
 
        dist_free(d);
                q->slot_config.max_bytes = INT_MAX;
        q->slot.packets_left = q->slot_config.max_packets;
        q->slot.bytes_left = q->slot_config.max_bytes;
-       if (q->slot_config.min_delay | q->slot_config.max_delay)
+       if (q->slot_config.min_delay | q->slot_config.max_delay |
+           q->slot_config.dist_jitter)
                q->slot.slot_next = ktime_get_ns();
        else
                q->slot.slot_next = 0;
        }
 
        if (tb[TCA_NETEM_DELAY_DIST]) {
-               ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]);
-               if (ret) {
-                       /* recover clg and loss_model, in case of
-                        * q->clg and q->loss_model were modified
-                        * in get_loss_clg()
-                        */
-                       q->clg = old_clg;
-                       q->loss_model = old_loss_model;
-                       return ret;
-               }
+               ret = get_dist_table(sch, &q->delay_dist,
+                                    tb[TCA_NETEM_DELAY_DIST]);
+               if (ret)
+                       goto get_table_failure;
+       }
+
+       if (tb[TCA_NETEM_SLOT_DIST]) {
+               ret = get_dist_table(sch, &q->slot_dist,
+                                    tb[TCA_NETEM_SLOT_DIST]);
+               if (ret)
+                       goto get_table_failure;
        }
 
        sch->limit = qopt->limit;
                get_slot(q, tb[TCA_NETEM_SLOT]);
 
        return ret;
+
+get_table_failure:
+       /* recover clg and loss_model, in case of
+        * q->clg and q->loss_model were modified
+        * in get_loss_clg()
+        */
+       q->clg = old_clg;
+       q->loss_model = old_loss_model;
+       return ret;
 }
 
 static int netem_init(struct Qdisc *sch, struct nlattr *opt,
        if (q->qdisc)
                qdisc_destroy(q->qdisc);
        dist_free(q->delay_dist);
+       dist_free(q->slot_dist);
 }
 
 static int dump_loss_model(const struct netem_sched_data *q,
        if (dump_loss_model(q, skb) != 0)
                goto nla_put_failure;
 
-       if (q->slot_config.min_delay | q->slot_config.max_delay) {
+       if (q->slot_config.min_delay | q->slot_config.max_delay |
+           q->slot_config.dist_jitter) {
                slot = q->slot_config;
                if (slot.max_packets == INT_MAX)
                        slot.max_packets = 0;