Example #1
0
int ampe_close_peer_link(unsigned char *peer_mac) {
  struct candidate *cand;

  assert(peer_mac);

  if ((cand = find_peer(peer_mac, 0)) == NULL) {
    sae_debug(
        AMPE_DEBUG_FSM,
        "Mesh plink: Attempt to close link with non-existent peer\n");
    return -EPERM;
  }

  if (!cand->conf) {
    /*
     * This can happen if we get a delete event for a station but they
     * haven't yet advanced to link establishment phase.  No need to send
     * a close then.
     */
    sae_debug(
        AMPE_DEBUG_FSM,
        "Mesh plink: not sending close to uninitialized peer " MACSTR "\n",
        MAC2STR(peer_mac));
    return -EPERM;
  }

  sae_debug(
      AMPE_DEBUG_FSM,
      "Mesh plink: closing link with " MACSTR "\n",
      MAC2STR(peer_mac));

  return plink_frame_tx(cand, PLINK_CLOSE, MESH_LINK_CANCELLED);
}
Example #2
0
/**
 * ampe_open_peer_link - attempt to establish a peer link
 * @peer:      MAC address of the candidate peer
 * @cookie:    Opaque cookie that will be returned to the caller along with
 *             frames to be transmitted.
 *
 * Returns 0 or a negative error.
 */
int ampe_open_peer_link(unsigned char *peer_mac, void *cookie) {
  struct candidate *cand;

  assert(peer_mac);

  if ((cand = find_peer(peer_mac, 0)) == NULL) {
    sae_debug(
        AMPE_DEBUG_FSM,
        "Mesh plink: Attempt to peer with "
        " non-authed peer\n");
    return -EPERM;
  }

  peer_ampe_init(&ampe_conf, cand, cookie);
  set_link_state(cand, PLINK_OPN_SNT);
  cb->evl->rem_timeout(cand->t2);
  cand->t2 = cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand);

  sae_debug(
      AMPE_DEBUG_FSM,
      "Mesh plink: starting establishment "
      "with " MACSTR "\n",
      MAC2STR(peer_mac));

  return plink_frame_tx(cand, PLINK_OPEN, 0);
}
Example #3
0
static void fsm_step(struct candidate *cand, enum plink_event event)
{
    struct ampe_config *aconf = cand->conf;
    unsigned short reason = 0;
    uint32_t changed = 0;

	switch (cand->link_state) {
	case PLINK_LISTEN:
		switch (event) {
		case CLS_ACPT:
			fsm_restart(cand);
			break;
		case OPN_ACPT:
            cand->timeout = aconf->retry_timeout_ms;
            cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand);
			plink_frame_tx(cand, PLINK_OPEN, 0);
			plink_frame_tx(cand, PLINK_CONFIRM, 0);
			break;
		default:
			break;
		}
		break;

	case PLINK_OPN_SNT:
		switch (event) {
		case OPN_RJCT:
		case CNF_RJCT:
			reason = htole16(MESH_CAPABILITY_POLICY_VIOLATION);
		case CLS_ACPT:
			if (!reason)
				reason = htole16(MESH_CLOSE_RCVD);
			cand->reason = reason;
			set_link_state(cand, PLINK_HOLDING);
            cand->timeout = aconf->holding_timeout_ms;
            cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand);
			plink_frame_tx(cand, PLINK_CLOSE, reason);
			break;
		case OPN_ACPT:
			/* retry timer is left untouched */
			set_link_state(cand, PLINK_OPN_RCVD);
			plink_frame_tx(cand, PLINK_CONFIRM, 0);
			break;
		case CNF_ACPT:
			set_link_state(cand, PLINK_CNF_RCVD);
            cand->timeout = aconf->confirm_timeout_ms;
            cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand);
			break;
		default:
			break;
		}
		break;

	case PLINK_OPN_RCVD:
		switch (event) {
		case OPN_RJCT:
		case CNF_RJCT:
			reason = htole16(MESH_CAPABILITY_POLICY_VIOLATION);
		case CLS_ACPT:
			if (!reason)
				reason = htole16(MESH_CLOSE_RCVD);
			cand->reason = reason;
			set_link_state(cand, PLINK_HOLDING);
            cand->timeout = aconf->holding_timeout_ms;
            cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand);
			plink_frame_tx(cand, PLINK_CLOSE, reason);
			break;
		case OPN_ACPT:
			plink_frame_tx(cand, PLINK_CONFIRM, 0);
			break;
		case CNF_ACPT:
			//del_timer(&cand->plink_timer);
			set_link_state(cand, PLINK_ESTAB);
			//mesh_plink_inc_estab_count(sdata);
			//ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
            derive_mtk(cand);
            estab_peer_link(cand->peer_mac,
                    cand->mtk, sizeof(cand->mtk),
                    cand->mgtk, sizeof(cand->mgtk),
                    cand->mgtk_expiration,
                    cand->sup_rates,
                    cand->sup_rates_len,
                    cand->cookie);
            changed |= mesh_set_ht_op_mode(cand->conf->mesh);
            sae_debug(AMPE_DEBUG_FSM, "mesh plink with "
                    MACSTR " established\n", MAC2STR(cand->peer_mac));
			break;
		default:
			break;
		}
		break;

	case PLINK_CNF_RCVD:
		switch (event) {
		case OPN_RJCT:
		case CNF_RJCT:
			reason = htole16(MESH_CAPABILITY_POLICY_VIOLATION);
		case CLS_ACPT:
			if (!reason)
				reason = htole16(MESH_CLOSE_RCVD);
			cand->reason = reason;
			set_link_state(cand, PLINK_HOLDING);
            cand->timeout = aconf->holding_timeout_ms;
            cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand);
			plink_frame_tx(cand, PLINK_CLOSE, reason);
			break;
		case OPN_ACPT:
			set_link_state(cand, PLINK_ESTAB);
            estab_peer_link(cand->peer_mac,
                    cand->mtk, sizeof(cand->mtk),
                    cand->mgtk, sizeof(cand->mgtk),
                    cand->mgtk_expiration, cand->sup_rates,
                    cand->sup_rates_len,
                    cand->cookie);
            changed |= mesh_set_ht_op_mode(cand->conf->mesh);
            //TODO: update the number of available peer "slots" in mesh config
			//mesh_plink_inc_estab_count(sdata);
			//ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
			sae_debug(AMPE_DEBUG_FSM, "Mesh plink with "
                    MACSTR " ESTABLISHED\n", MAC2STR(cand->peer_mac));
			plink_frame_tx(cand, PLINK_CONFIRM, 0);
			break;
		default:
			break;
		}
		break;

	case PLINK_ESTAB:
		switch (event) {
		case CLS_ACPT:
			reason = htole16(MESH_CLOSE_RCVD);
			cand->reason = reason;
			set_link_state(cand, PLINK_HOLDING);
            cand->timeout = aconf->holding_timeout_ms;
            cand->t2 = srv_add_timeout(srvctx, SRV_MSEC(cand->timeout), plink_timer, cand);
            changed |= mesh_set_ht_op_mode(cand->conf->mesh);
            //TODO: update the number of available peer "slots" in mesh config
			//if (deactivated)
		    //	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
			plink_frame_tx(cand, PLINK_CLOSE, reason);
			break;
		case OPN_ACPT:
			plink_frame_tx(cand, PLINK_CONFIRM, 0);
			break;
		default:
			break;
		}
		break;
	case PLINK_HOLDING:
		switch (event) {
		case CLS_ACPT:
			//if (del_timer(&cand->plink_timer))
			//	cand->ignore_plink_timer = 1;
			fsm_restart(cand);
			break;
		case OPN_ACPT:
		case CNF_ACPT:
		case OPN_RJCT:
		case CNF_RJCT:
			reason = cand->reason;
			plink_frame_tx(cand, PLINK_CLOSE, reason);
			break;
		default:
            break;
		}
		break;
	default:
        sae_debug(AMPE_DEBUG_FSM, "Unsupported event transition %d", event);
		break;
	}

    if (changed)
        meshd_set_mesh_conf(cand->conf->mesh, changed);
}
Example #4
0
static void plink_timer(timerid id, void *data)
{
	__le16 reason;
    struct candidate *cand;

	cand = (struct candidate *)data;

    assert(cand);

    sae_debug(AMPE_DEBUG_FSM, "Mesh plink timer for " MACSTR
            " fired on state %s\n", MAC2STR(cand->peer_mac),
		    mplstates[(cand->link_state > PLINK_BLOCKED) ? PLINK_UNDEFINED : cand->link_state]);

	reason = 0;

	switch (cand->link_state) {
	case PLINK_OPN_RCVD:
	case PLINK_OPN_SNT:
		/* retry timer */
        sae_debug(AMPE_DEBUG_FSM, "Mesh plink:retries %d of %d\n", cand->retries,
                  cand->conf->max_retries);
		if (cand->retries < cand->conf->max_retries) {
			unsigned int rand;
            sae_debug(AMPE_DEBUG_FSM, "Mesh plink for " MACSTR
                    " (retry, timeout): %d %d\n", MAC2STR(cand->peer_mac),
                    cand->retries, cand->timeout);
			RAND_bytes((unsigned char *) &rand, sizeof(rand));
            if (!cand->timeout) {
                cand->timeout = cand->conf->retry_timeout_ms;
                sae_debug(AMPE_DEBUG_ERR, "WARN: cand " MACSTR
                    " had a timeout of 0ms.  Reset to %d\n",
                    MAC2STR(cand->peer_mac),cand->timeout);
            }
            cand->timeout += rand % cand->timeout;
			++cand->retries;
            cand->t2 = srv_add_timeout(srvctx,
                    SRV_MSEC(cand->timeout), plink_timer,
                    cand);
			plink_frame_tx(cand, PLINK_OPEN, 0);
			break;
		}
		reason = htole16(MESH_MAX_RETRIES);
		/* fall through on else */
	case PLINK_CNF_RCVD:
		/* confirm timer */
		if (!reason)
			reason = htole16(MESH_CONFIRM_TIMEOUT);
		set_link_state(cand, PLINK_HOLDING);
        cand->t2 = srv_add_timeout(srvctx,
                    SRV_MSEC(cand->conf->holding_timeout_ms), plink_timer,
                    cand);
		plink_frame_tx(cand, PLINK_CLOSE, reason);
		break;
	case PLINK_HOLDING:
		/* holding timer */
		fsm_restart(cand);
		break;
	case PLINK_ESTAB:
		/* nothing to do */
		break;
	default:
        sae_debug(AMPE_DEBUG_FSM, "Timeout for peer " MACSTR
                " in state %d\n", MAC2STR(cand->peer_mac),
                cand->link_state);
		break;
	}
}
Example #5
0
static void fsm_step(struct candidate *cand, enum plink_event event) {
  struct ampe_config *aconf = cand->conf;
  unsigned short reason = 0;
  uint32_t changed = 0;

  switch (cand->link_state) {
    case PLINK_LISTEN:
      switch (event) {
        case CLS_ACPT:
          fsm_restart(cand);
          break;
        case OPN_ACPT:
          cand->timeout = aconf->retry_timeout_ms;
          cb->evl->rem_timeout(cand->t2);
          cand->t2 =
              cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand);
          set_link_state(cand, PLINK_OPN_RCVD);
          plink_frame_tx(cand, PLINK_OPEN, 0);
          plink_frame_tx(cand, PLINK_CONFIRM, 0);
          break;
        default:
          break;
      }
      break;

    case PLINK_OPN_SNT:
      switch (event) {
        case OPN_RJCT:
        case CNF_RJCT:
        case REQ_RJCT:
          reason = MESH_CAPABILITY_POLICY_VIOLATION;
        /* no break */
        case CLS_ACPT:
          if (!reason)
            reason = MESH_CLOSE_RCVD;
          set_link_state(cand, PLINK_HOLDING);
          cand->timeout = aconf->holding_timeout_ms;
          cb->evl->rem_timeout(cand->t2);
          cand->t2 =
              cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand);
          plink_frame_tx(cand, PLINK_CLOSE, reason);
          break;
        case OPN_ACPT:
          /* retry timer is left untouched */
          set_link_state(cand, PLINK_OPN_RCVD);
          plink_frame_tx(cand, PLINK_CONFIRM, 0);
          break;
        case CNF_ACPT:
          set_link_state(cand, PLINK_CNF_RCVD);
          cand->timeout = aconf->confirm_timeout_ms;
          cb->evl->rem_timeout(cand->t2);
          cand->t2 =
              cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand);
          break;
        default:
          break;
      }
      break;

    case PLINK_OPN_RCVD:
      switch (event) {
        case OPN_RJCT:
        case CNF_RJCT:
        case REQ_RJCT:
          reason = MESH_CAPABILITY_POLICY_VIOLATION;
        /* no break */
        case CLS_ACPT:
          if (!reason)
            reason = MESH_CLOSE_RCVD;
          set_link_state(cand, PLINK_HOLDING);
          cand->timeout = aconf->holding_timeout_ms;
          cb->evl->rem_timeout(cand->t2);
          cand->t2 =
              cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand);
          plink_frame_tx(cand, PLINK_CLOSE, reason);
          break;
        case OPN_ACPT:
          plink_frame_tx(cand, PLINK_CONFIRM, 0);
          break;
        case CNF_ACPT:
          changed |= do_estab_peer_link(cand);
          break;
        default:
          break;
      }
      break;

    case PLINK_CNF_RCVD:
      switch (event) {
        case OPN_RJCT:
        case CNF_RJCT:
        case REQ_RJCT:
          reason = MESH_CAPABILITY_POLICY_VIOLATION;
        /* no break */
        case CLS_ACPT:
          if (!reason)
            reason = MESH_CLOSE_RCVD;
          set_link_state(cand, PLINK_HOLDING);
          cand->timeout = aconf->holding_timeout_ms;
          cb->evl->rem_timeout(cand->t2);
          cand->t2 =
              cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand);
          plink_frame_tx(cand, PLINK_CLOSE, reason);
          break;
        case OPN_ACPT:
          changed |= do_estab_peer_link(cand);
          plink_frame_tx(cand, PLINK_CONFIRM, 0);
          break;
        default:
          break;
      }
      break;

    case PLINK_ESTAB:
      switch (event) {
        case OPN_RJCT:
        case CNF_RJCT:
        case REQ_RJCT:
          reason = MESH_CAPABILITY_POLICY_VIOLATION;
        case CLS_ACPT:
          if (!reason)
            reason = MESH_CLOSE_RCVD;
          set_link_state(cand, PLINK_HOLDING);
          cand->timeout = aconf->holding_timeout_ms;
          cb->evl->rem_timeout(cand->t2);
          cand->t2 =
              cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand);
          changed |= mesh_set_ht_op_mode(cand->conf->mesh);
          plink_frame_tx(cand, PLINK_CLOSE, reason);
          break;
        case OPN_ACPT:
          plink_frame_tx(cand, PLINK_CONFIRM, 0);
          break;
        default:
          break;
      }
      break;
    case PLINK_HOLDING:
      switch (event) {
        case CLS_ACPT:
          fsm_restart(cand);
          break;
        case OPN_ACPT:
        case CNF_ACPT:
        case OPN_RJCT:
        case CNF_RJCT:
        case REQ_RJCT:
          plink_frame_tx(cand, PLINK_CLOSE, reason);
          break;
        default:
          break;
      }
      break;
    default:
      sae_debug(AMPE_DEBUG_FSM, "Unsupported event transition %d", event);
      break;
  }

  if (changed)
    cb->meshd_set_mesh_conf(cand->conf->mesh, changed);
}
Example #6
0
static void plink_timer(void *data) {
  le16 reason;
  struct candidate *cand;

  cand = (struct candidate *)data;

  assert(cand);

  sae_debug(
      AMPE_DEBUG_FSM,
      "Mesh plink timer for " MACSTR " fired on state %s\n",
      MAC2STR(cand->peer_mac),
      mpl_states[(cand->link_state > PLINK_BLOCKED) ? PLINK_UNDEFINED
                                                    : cand->link_state]);

  reason = 0;

  switch (cand->link_state) {
    case PLINK_OPN_RCVD:
    case PLINK_OPN_SNT:
      /* retry timer */
      sae_debug(
          AMPE_DEBUG_FSM,
          "Mesh plink:retries %d of %d\n",
          cand->retries,
          cand->conf->max_retries);
      if (cand->retries < cand->conf->max_retries) {
        cand->timeout = cand->conf->retry_timeout_ms;
        sae_debug(
            AMPE_DEBUG_FSM,
            "Mesh plink for " MACSTR " (retry, timeout): %d %d\n",
            MAC2STR(cand->peer_mac),
            cand->retries,
            cand->timeout);
        ++cand->retries;
        cb->evl->rem_timeout(cand->t2);
        cand->t2 =
            cb->evl->add_timeout(SRV_MSEC(cand->timeout), plink_timer, cand);
        plink_frame_tx(cand, PLINK_OPEN, 0);
        break;
      }
      reason = MESH_MAX_RETRIES;
    /* no break / fall through on else */
    case PLINK_CNF_RCVD:
      /* confirm timer */
      if (!reason)
        reason = MESH_CONFIRM_TIMEOUT;
      set_link_state(cand, PLINK_HOLDING);
      cb->evl->rem_timeout(cand->t2);
      cand->t2 = cb->evl->add_timeout(
          SRV_MSEC(cand->conf->holding_timeout_ms), plink_timer, cand);
      plink_frame_tx(cand, PLINK_CLOSE, reason);
      break;
    case PLINK_HOLDING:
      /* holding timer */
      fsm_restart(cand);
      break;
    case PLINK_ESTAB:
      /* nothing to do */
      break;
    default:
      sae_debug(
          AMPE_DEBUG_FSM,
          "Timeout for peer " MACSTR " in state %d\n",
          MAC2STR(cand->peer_mac),
          cand->link_state);
      break;
  }
}