int
olsr_process_hysteresis(struct link_entry *entry)
{
  //printf("PROCESSING QUALITY: %f\n", entry->L_link_quality);
  if (entry->L_link_quality > hhigh) {
    if (entry->L_link_pending == 1) {
      struct ipaddr_str buf;
      OLSR_PRINTF(1, "HYST[%s] link set to NOT pending!\n", olsr_ip_to_string(&buf, &entry->neighbor_iface_addr));
      changes_neighborhood = true;
    }

    /* Pending = false */
    entry->L_link_pending = 0;

    if (!TIMED_OUT(entry->L_LOST_LINK_time))
      changes_neighborhood = true;

    /* time = now -1 */
    entry->L_LOST_LINK_time = now_times - 1;

    return 1;
  }

  if (entry->L_link_quality < hlow) {
    if (entry->L_link_pending == 0) {
      struct ipaddr_str buf;
      OLSR_PRINTF(1, "HYST[%s] link set to pending!\n", olsr_ip_to_string(&buf, &entry->neighbor_iface_addr));
      changes_neighborhood = true;
    }

    /* Pending = true */
    entry->L_link_pending = 1;

    if (TIMED_OUT(entry->L_LOST_LINK_time))
      changes_neighborhood = true;

    /* Timer = min (L_time, current time + NEIGHB_HOLD_TIME) */
    entry->L_LOST_LINK_time = MIN(GET_TIMESTAMP(NEIGHB_HOLD_TIME * MSEC_PER_SEC), entry->link_timer->timer_clock);

    /* (the link is then considered as lost according to section
       8.5 and this may produce a neighbor loss).
       WTF?
     */
    return -1;
  }

  /*
   *If we get here then:
   *(HYST_THRESHOLD_LOW <= entry->L_link_quality <= HYST_THRESHOLD_HIGH)
   */

  /* L_link_pending and L_LOST_LINK_time remain unchanged. */
  return 0;

}
static bool
serialize_tc6(struct tc_message *message, struct interface *ifp)
{
#ifdef DEBUG
  struct ipaddr_str buf;
#endif
  uint16_t remainsize, curr_size;
  struct tc_mpr_addr *mprs;
  union olsr_message *m;
  struct olsr_tcmsg6 *tc6;
  struct neigh_info6 *mprsaddr6;
  bool found = false, partial_sent = false;

  if ((!message) || (!ifp) || (olsr_cnf->ip_version != AF_INET6))
    return false;

  remainsize = net_outbuffer_bytes_left(ifp);

  m = (union olsr_message *)msg_buffer;

  tc6 = &m->v6.message.tc;

  mprsaddr6 = tc6->neigh;
  curr_size = OLSR_TC_IPV6_HDRSIZE;

  /* Send pending packet if not room in buffer */
  if (curr_size > remainsize) {
    net_output(ifp);
    remainsize = net_outbuffer_bytes_left(ifp);
  }
  check_buffspace(curr_size, remainsize, "TC");

  /* Fill header */
  m->v6.olsr_vtime = ifp->valtimes.tc;
  m->v6.olsr_msgtype = TC_MESSAGE;
  m->v6.hopcnt = message->hop_count;
  m->v6.ttl = message->ttl;
  m->v6.originator = message->originator.v6;

  /* Fill TC header */
  tc6->ansn = htons(message->ansn);
  tc6->reserved = 0;

  /*Looping trough MPR selectors */
  for (mprs = message->multipoint_relay_selector_address; mprs != NULL; mprs = mprs->next) {

    /*If packet is to be chomped */
    if ((curr_size + olsr_cnf->ipsize) > remainsize) {
      /* Only add TC message if it contains data */
      if (curr_size > OLSR_TC_IPV6_HDRSIZE) {
#ifdef DEBUG
        OLSR_PRINTF(BMSG_DBGLVL, "Sending partial(size: %d, buff left:%d)\n", curr_size, remainsize);
#endif
        m->v6.olsr_msgsize = htons(curr_size);
        m->v6.seqno = htons(get_msg_seqno());

        net_outbuffer_push(ifp, msg_buffer, curr_size);
        mprsaddr6 = tc6->neigh;
        curr_size = OLSR_TC_IPV6_HDRSIZE;
        found = false;
        partial_sent = true;
      }
      net_output(ifp);
      remainsize = net_outbuffer_bytes_left(ifp);
      check_buffspace(curr_size + olsr_cnf->ipsize, remainsize, "TC2");

    }
    found = true;
#ifdef DEBUG
    OLSR_PRINTF(BMSG_DBGLVL, "\t%s\n", olsr_ip_to_string(&buf, &mprs->address));
#endif
    mprsaddr6->addr = mprs->address.v6;
    curr_size += olsr_cnf->ipsize;

    mprsaddr6++;
  }

  if (found) {
    m->v6.olsr_msgsize = htons(curr_size);
    m->v6.seqno = htons(get_msg_seqno());

    net_outbuffer_push(ifp, msg_buffer, curr_size);

  } else {
    if ((!partial_sent) && (!TIMED_OUT(send_empty_tc))) {
      OLSR_PRINTF(1, "TC: Sending empty package\n");

      m->v6.olsr_msgsize = htons(curr_size);
      m->v6.seqno = htons(get_msg_seqno());

      net_outbuffer_push(ifp, msg_buffer, curr_size);

      found = true;
    }
  }

  return found;
}
Exemple #3
0
/**
 * Walk through the timer list and check if any timer is ready to fire.
 * Callback the provided function with the context pointer.
 */
static void
walk_timers(uint32_t * last_run)
{
  unsigned int total_timers_walked = 0, total_timers_fired = 0;
  unsigned int wheel_slot_walks = 0;

  /*
   * Check the required wheel slots since the last time a timer walk was invoked,
   * or check *all* the wheel slots, whatever is less work.
   * The latter is meant as a safety belt if the scheduler falls behind.
   */
  while ((*last_run <= now_times) && (wheel_slot_walks < TIMER_WHEEL_SLOTS)) {
    struct list_node tmp_head_node;
    /* keep some statistics */
    unsigned int timers_walked = 0, timers_fired = 0;

    /* Get the hash slot for this clocktick */
    struct list_node *const timer_head_node = &timer_wheel[*last_run & TIMER_WHEEL_MASK];

    /* Walk all entries hanging off this hash bucket. We treat this basically as a stack
     * so that we always know if and where the next element is.
     */
    list_head_init(&tmp_head_node);
    while (!list_is_empty(timer_head_node)) {
      /* the top element */
      struct list_node *const timer_node = timer_head_node->next;
      struct timer_entry *const timer = list2timer(timer_node);

      /*
       * Dequeue and insert to a temporary list.
       * We do this to avoid loosing our walking context when
       * multiple timers fire.
       */
      list_remove(timer_node);
      list_add_after(&tmp_head_node, timer_node);
      timers_walked++;

      /* Ready to fire ? */
      if (TIMED_OUT(timer->timer_clock)) {

        OLSR_PRINTF(7, "TIMER: fire %s timer %p, ctx %p, "
                   "at clocktick %u (%s)\n",
                   timer->timer_cookie->ci_name,
                   timer, timer->timer_cb_context, (unsigned int)*last_run, olsr_wallclock_string());

        /* This timer is expired, call into the provided callback function */
        timer->timer_cb(timer->timer_cb_context);

        /* Only act on actually running timers */
        if (timer->timer_flags & OLSR_TIMER_RUNNING) {
          /*
           * Don't restart the periodic timer if the callback function has
           * stopped the timer.
           */
          if (timer->timer_period) {
            /* For periodical timers, rehash the random number and restart */
            timer->timer_random = random();
            olsr_change_timer(timer, timer->timer_period, timer->timer_jitter_pct, OLSR_TIMER_PERIODIC);
          } else {
            /* Singleshot timers are stopped */
            olsr_stop_timer(timer);
          }
        }

        timers_fired++;
      }
    }

    /*
     * Now merge the temporary list back to the old bucket.
     */
    list_merge(timer_head_node, &tmp_head_node);

    /* keep some statistics */
    total_timers_walked += timers_walked;
    total_timers_fired += timers_fired;

    /* Increment the time slot and wheel slot walk iteration */
    (*last_run)++;
    wheel_slot_walks++;
  }

  OLSR_PRINTF(7, "TIMER: processed %4u/%d clockwheel slots, "
             "timers walked %4u/%u, timers fired %u\n",
             wheel_slot_walks, TIMER_WHEEL_SLOTS, total_timers_walked, timer_mem_cookie->ci_usage, total_timers_fired);

  /*
   * If the scheduler has slipped and we have walked all wheel slots,
   * reset the last timer run.
   */
  *last_run = now_times;
}