示例#1
0
void ssh_engine_pme_get_transform_stats(SshEngine engine,
					SshUInt32 transform_index,
					SshPmeTransformStatsCB callback,
					void *context)
{
  SshEngineTransformData d_trd;
  SshEngineTransformControl c_trd;
  SshEngineTransformStatsStruct stats;
  
  /* Copy the flow statistics to local storage to ensure that the flow
     does not disappear from under us while we are delivering the stats
     to the caller. */
  ssh_kernel_mutex_lock(engine->flow_control_table_lock);
  c_trd = SSH_ENGINE_GET_TRD(engine, transform_index);
  
  d_trd = FASTPATH_GET_READ_ONLY_TRD(engine->fastpath, transform_index);
  if (c_trd == NULL || d_trd->transform == 0)
    {
      FASTPATH_RELEASE_TRD(engine->fastpath, transform_index);
      
      ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
      (*callback)(engine->pm, NULL, context);
      return;
    }

  stats.control = c_trd->stats;
  stats.data = d_trd->stats;

  FASTPATH_RELEASE_TRD(engine->fastpath, transform_index);

  ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
  (*callback)(engine->pm, &stats, context);
}
示例#2
0
void ssh_engine_pme_get_rule_stats(SshEngine engine, SshUInt32 rule_index,
				   SshPmeRuleStatsCB callback, void *context)
{
  SshEnginePolicyRule rule;
  SshEngineRuleStatsStruct stats;

  if (rule_index >= engine->rule_table_size)
    {
      (*callback)(engine->pm, NULL, context);
      return;
    }

  /* Copy the flow statistics to local storage to ensure that the flow
     does not disappear from under us while we are delivering the stats
     to the caller. */
  ssh_kernel_mutex_lock(engine->flow_control_table_lock);
  rule = SSH_ENGINE_GET_RULE(engine, rule_index);
  if (rule->type == SSH_ENGINE_RULE_NONEXISTENT)
    {
      ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
      (*callback)(engine->pm, NULL, context);
      return;
    }
  stats = rule->stats;
  ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
  (*callback)(engine->pm, &stats, context);
}
Boolean ssh_engine_send(SshEngine engine, Boolean locked,
                        Boolean reliable, ...)
{
    va_list ap;
    unsigned char *ucp;
    size_t len;

    if (!locked)
        ssh_kernel_mutex_lock(engine->lock);
    if (!engine->ipm_open)
    {
        if (!locked)
            ssh_kernel_mutex_unlock(engine->lock);
        return FALSE;
    }
    if (!locked)
        ssh_kernel_mutex_unlock(engine->lock);

    /* WARNING: this function is called from ssh_debug callback, which
       means that no debug functions can be called here or we'll end up
       with infinite recursion. */

    /* Construct the final packet to send to ipm. */
    va_start(ap, reliable);
    len = ssh_encode_array_alloc_va(&ucp, ap);
    va_end(ap);
    SSH_ASSERT(len >= 5); /* must have at least len+type */

    /* Update the length of the packet. */
    SSH_PUT_32BIT(ucp, len - 4);

    /* Send and/or queue the packet to the ipm.  This will free the buffer. */
    return (*engine->send)(ucp, len, reliable, engine->machine_context);
}
void ssh_virtual_adapter_detach(SshInterceptor interceptor,
                                SshInterceptorIfnum adapter_ifnum,
                                SshVirtualAdapterStatusCB callback,
                                void *context)
{
  SshVirtualAdapter adapter;
  unsigned char adapter_name[SSH_INTERCEPTOR_IFNAME_SIZE];
  SshVirtualAdapterDetachCB detach_cb = NULL;
  void *adapter_context = NULL;

  local_bh_disable();
  ssh_kernel_mutex_lock(interceptor->interceptor_lock);
  adapter = ssh_virtual_adapter_ifnum_to_adapter(interceptor, adapter_ifnum);
  if (adapter == NULL)
    {
      ssh_kernel_mutex_unlock(interceptor->interceptor_lock);
      local_bh_enable();
      if (callback)
	(*callback)(SSH_VIRTUAL_ADAPTER_ERROR_NONEXISTENT,
		    adapter_ifnum, NULL, SSH_VIRTUAL_ADAPTER_STATE_UNDEFINED,
		    NULL, context);
      return;
    }

  if (adapter->detach_cb)
    {
      detach_cb = adapter->detach_cb;
      adapter_context = adapter->adapter_context;
    }

  ssh_virtual_adapter_clear(adapter);
  adapter->attached = 0;

  /* Gather info for callback. */
  if (callback)
    {
      snprintf(adapter_name, SSH_INTERCEPTOR_IFNAME_SIZE,
	       "%s", adapter->dev->name);
    }
  
  ssh_kernel_mutex_unlock(interceptor->interceptor_lock);
  local_bh_enable();

  /* Destroy adapter_context. */
  if (detach_cb)
    (*detach_cb)(adapter_context);

  if (callback)
    (*callback)(SSH_VIRTUAL_ADAPTER_ERROR_OK,
		adapter_ifnum, adapter_name,
		SSH_VIRTUAL_ADAPTER_STATE_UNDEFINED, 
		NULL, context);
}
示例#5
0
/* Auditing of global events (non-packet related) */
void
engine_audit_event(SshEngine engine, SshAuditEvent event)
{
  SshEngineAuditEvent c;
  SshUInt32 index;

  ssh_kernel_mutex_lock(engine->flow_control_table_lock);

  /* Index to the audit queue to which this audit event should be placed. */
  index = SSH_ENGINE_AUDIT_LEVEL_INFORMATIONAL;
  SSH_ASSERT(index < SSH_ENGINE_NUM_AUDIT_LEVELS);

  if (ssh_engine_audit_rate_limit(engine, index) == TRUE)
    {
      SSH_DEBUG(SSH_D_HIGHOK,
		("Not auditing this event due to rate limiting"));
      engine->audit_flags |= SSH_ENGINE_AUDIT_RATE_LIMITED_EVENT;
      ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
      return;
    }

  /* Check if we have space to audit this event, if not we return without
     auditing it. */
  if (engine->audit_table_head[index] ==
      SSH_ENGINE_AUDIT_RING_INC(engine, engine->audit_table_tail[index]))
    {
      SSH_DEBUG(SSH_D_HIGHOK, ("Not auditing this event due to resource "
			       "shortages"));
      engine_audit_busy(engine);
      ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
      return;
    }
  c = &engine->audit_table[index][engine->audit_table_tail[index]];

  engine->audit_event_id++;

  memset(c, 0, sizeof(*c));
  c->audit_id = engine->audit_event_id;
  c->engine = engine;
  c->event = event;

  /* Move tail pointer ahead one slot. The actual auditing is done when
     the policymanager requests the engine to send it the available audit
     messages. */
  engine->audit_table_tail[index] =
    SSH_ENGINE_AUDIT_RING_INC(engine, engine->audit_table_tail[index]);

  engine_audit_new_event(engine);
  ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
  return;
}
static inline SshInterceptorInternalPacket
ssh_freelist_packet_get(SshInterceptor interceptor,
			Boolean may_borrow)
{
  SshInterceptorInternalPacket p;
  unsigned int cpu;

  icept_preempt_disable();

  cpu = smp_processor_id();

  p = ssh_packet_freelist_head[cpu];
  if (p)
    {
      p->cpu = cpu;

      ssh_packet_freelist_head[p->cpu] =
	(SshInterceptorInternalPacket) p->packet.next;
    }
  else
    {
      /* Try getting a packet from the shared freelist */
      ssh_kernel_mutex_lock(interceptor->packet_lock);

      p = ssh_packet_freelist_head[SSH_LINUX_INTERCEPTOR_NR_CPUS];
      if (p)
	{
	  p->cpu = cpu;

	  ssh_packet_freelist_head[SSH_LINUX_INTERCEPTOR_NR_CPUS] =
	    (SshInterceptorInternalPacket) p->packet.next;

	  ssh_kernel_mutex_unlock(interceptor->packet_lock);
	  goto done;
	}
      ssh_kernel_mutex_unlock(interceptor->packet_lock);

      p = ssh_malloc(sizeof(*p));
      if (!p)
	goto done;

      p->cpu = cpu;
    }

 done:
  icept_preempt_enable();

  return p;
}
Boolean
ssh_interceptor_stop(SshInterceptor interceptor)
{
  SSH_DEBUG(2, ("interceptor stopping"));

  /* 'interceptor_lock protects the 'interfaces_callback'
     and 'num_interface_callbacks'. */
  ssh_kernel_mutex_lock(interceptor->interceptor_lock);

  if (interceptor->num_interface_callbacks)
    {
      ssh_kernel_mutex_unlock(interceptor->interceptor_lock);
      SSH_DEBUG(SSH_D_ERROR,
                ("%d interface callbacks pending, can't stop",
                 interceptor->num_interface_callbacks));
      return FALSE;
    }

  /* No more interfaces are delivered to the engine after this. */
  interceptor->interfaces_callback = ssh_interceptor_dummy_interface_cb;

  /* Route callback is currently not used. */
  interceptor->route_callback = NULL_FNPTR;

  ssh_kernel_mutex_unlock(interceptor->interceptor_lock);

  /* After this the engine will receive no more packets from
     the interceptor, although the netfilter hooks are still
     installed. */

  /* Set packet_callback to point to our dummy_db */
  rcu_assign_pointer(interceptor->packet_callback,
		     ssh_interceptor_dummy_packet_cb);
  
  /* Wait for state synchronization. */
  local_bh_enable();
  synchronize_rcu();
  local_bh_disable();

  /* Callback context can now be safely zeroed, as both
     the interface_callback and the packet_callback point to
     our dummy_cb, and all kernel threads have returned from
     the engine. */
  interceptor->callback_context = NULL;

  SSH_DEBUG(2, ("interceptor stopped"));

  return TRUE;
}
void fastpath_fragmagic_uninit(SshFastpath fastpath)
{
  SshFastpathFragEntry frag;

  ssh_kernel_mutex_lock(fastpath->frag_lock);
  if (fastpath->frag_timeout_scheduled)
    {
      ssh_kernel_timeout_cancel(ssh_fastpath_fragmagic_timeout, 
				(void *)fastpath);
      fastpath->frag_timeout_scheduled = 0;
    }
  ssh_kernel_mutex_unlock(fastpath->frag_lock);

  /* Free fragments. */
  for (frag = fastpath->frag_data_lru_head; frag; frag = frag->data_lru_next)
    {
      SshInterceptorPacket pp, pp_next;

      for (pp = frag->pp_chain; pp; pp = pp_next)
        {
          pp_next = pp->next;

	  /* An exeption for using ssh_fastpath_fragmagic_packet_free. 
	     We are uninitialising here and we don't receive any more
	     packets. */
          ssh_interceptor_packet_free(pp);
        }
    }
}
void
ssh_interceptor_packet_freelist_uninit(SshInterceptor interceptor)
{
  SshInterceptorInternalPacket p;
  unsigned int i;

  ssh_kernel_mutex_lock(interceptor->packet_lock);

  for (i = 0; i < SSH_LINUX_INTERCEPTOR_NR_CPUS + 1; i++)
    {
      /* Traverse freelist and free allocated all packets. */
      p = ssh_packet_freelist_head[i];
      while (p != NULL)
	{
	  ssh_packet_freelist_head[i] =
	    (SshInterceptorInternalPacket) p->packet.next;

	  ssh_free(p);

	  p = ssh_packet_freelist_head[i];
	}
    }

  ssh_kernel_mutex_unlock(interceptor->packet_lock);
}
示例#10
0
void ssh_engine_audit_uninit(SshEngine engine)
{
  SshEngineAuditEvent event;
  SshUInt32 i;

  ssh_kernel_mutex_lock(engine->flow_control_table_lock);

  for (i = 0; i < SSH_ENGINE_NUM_AUDIT_LEVELS; i++)
    {
      while (engine->audit_table_head[i] != engine->audit_table_tail[i])
	{
	  event = &engine->audit_table[i][engine->audit_table_head[i]];
	  
	  /* Free any packet data associated to this audit event. */
	  if (event->packet)
	    {
	      ssh_free(event->packet);
	      event->packet = NULL;
	    }
	  
	  /* Move ahead in the list. */
	  engine->audit_table_head[i]
	    = SSH_ENGINE_AUDIT_RING_INC(engine, engine->audit_table_head[i]);
	}      
    } 
  ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
}
/* ssh_virtual_adapter_connect_retry_timeout_cb()
 *
 * This function gets never invoked on Win9x platforms
 */
static void
ssh_virtual_adapter_connect_retry_timeout_cb(SshVirtualAdapter va)
{
  Boolean aborted;
  SSH_DEBUG(SSH_D_MIDSTART,
	    ("ssh_virtual_adapter_connect_retry_timeout_cb()"));

  SSH_ASSERT(va != NULL);
  SSH_ASSERT(va->interceptor != NULL);

  ssh_kernel_mutex_lock(&va->connect_lock);
  SSH_ASSERT(va->va_connected == 0);
  aborted = va->va_connect_aborted;
  ssh_kernel_mutex_unlock(&va->connect_lock);

  if (aborted)
    {
      SSH_DEBUG(SSH_D_MIDSTART,
                ("Virtual adapter connect aborted."));

      ssh_virtual_adapter_release(va);
    }
  else
    {
      /* force execution in passive level */
      ssh_ndis_wrkqueue_queue_item(va->interceptor->work_queue,
                                   ssh_virtual_adapter_connect, va);
    }
}
/* ssh_virtual_adapter_deregister()
 *
 *
 *
 */
void
ssh_virtual_adapter_deregister(SshVirtualAdapter va)
{
  SshInterceptor interceptor = va->interceptor;
  Boolean was_connected = FALSE;

  SSH_DEBUG(SSH_D_HIGHSTART, ("ssh_virtual_adapter_deregister(0x%p)", va));

  ssh_kernel_mutex_lock(&va->connect_lock);
  was_connected = va->va_connected;
  va->va_connect_aborted = TRUE;
  ssh_kernel_mutex_unlock(&va->connect_lock);

  SSH_ASSERT(va->interceptor != NULL);
  SSH_ASSERT(va != NULL);
  SSH_ASSERT(va->adapter != NULL);

  if (was_connected)
    {
      SSH_ASSERT(va->vnic_disable_cb != NULL_FNPTR);
      SSH_ASSERT(va->vnic_cb_context != NULL);
      
      /* disable adapter - this 'unplugs the cable' */
      (*va->vnic_disable_cb)(va->vnic_cb_context);

      /* Disconnect from underlying virtual NIC */
      ssh_virtual_adapter_disconnect(va);
    }

  /* Decrement the count of virtual adapters */
  InterlockedDecrement(&interceptor->va_interface_cnt);

  /* release the virtual adapter. */
  ssh_virtual_adapter_release(va);
}
/* Workhorse for destroy_all and error handler for create. `adapter' must 
   not be in the adapter table when this function is called. */
static Boolean
ssh_virtual_adapter_destroy(SshInterceptor interceptor,
                            SshVirtualAdapter adapter)
{
  SSH_ASSERT(adapter != NULL);

  ssh_kernel_mutex_assert_is_locked(interceptor->interceptor_lock);
  
  SSH_DEBUG(SSH_D_HIGHOK,
	    ("Destroying virtual adapter %d [%s]", 
	     (adapter->dev ? adapter->dev->ifindex : -1),
	     (adapter->dev ? adapter->dev->name : "unknown")));
  
  if (adapter->dev)
    {
      /* Detach and destroy net_device. */ 
      ssh_kernel_mutex_unlock(interceptor->interceptor_lock);
      local_bh_enable();
      
      /* This call will produce an interface event. */
      ssh_virtual_adapter_detach_low_level(adapter);
      
      local_bh_disable();
      ssh_kernel_mutex_lock(interceptor->interceptor_lock);
      adapter->dev = NULL;
    }
  
  /* Free adapter */
  ssh_free(adapter);
  
  /* All ok. */
  return TRUE;
}
/* This function is called during module unload. */
static void
ssh_virtual_adapter_destroy_all(SshInterceptor interceptor)
{
  SshVirtualAdapter adapter;
  Boolean check_again;
  SshUInt32 i;

 restart:
  local_bh_disable();
  ssh_kernel_mutex_lock(interceptor->interceptor_lock);

  check_again = FALSE;
  for (i = 0; i < SSH_LINUX_MAX_VIRTUAL_ADAPTERS; i++)
    {
      adapter = interceptor->virtual_adapters[i];
      if (adapter == NULL)
	continue;

      if (!adapter->initialized)
	{
	  /* Initialization is underway, mark adapter to be destroyed. */
	  adapter->destroyed = 1;
	  check_again = TRUE;
	  continue;
	}
      
      /* Remove adapter from table. */
      interceptor->virtual_adapters[i] = NULL;

      /* Detach and destroy adapter. */
      ssh_virtual_adapter_destroy(interceptor, adapter);

      /* Unlock and restart. */
      ssh_kernel_mutex_unlock(interceptor->interceptor_lock);
      local_bh_enable();
      goto restart;
    }

  ssh_kernel_mutex_unlock(interceptor->interceptor_lock);
  local_bh_enable();

  if (check_again)
    goto restart;
}
void ssh_engine_notify_ipm_open(SshEngine engine)
{
    SSH_DEBUG(1, ("User level module opened connection."));

    /* Update state information about the policy manager connection. */
    ssh_kernel_mutex_lock(engine->lock);
    SSH_ASSERT(!engine->ipm_open);
    engine->ipm_open = TRUE;
    ssh_kernel_mutex_unlock(engine->lock);
}
void
ssh_interceptor_dst_entry_cache_flush(SshInterceptor interceptor)
{
  SshUInt32 slot;
  SshDstEntry tmp;

  SSH_DEBUG(SSH_D_MIDOK, ("Dst entry cache flush, %lu items in cache",
			  (unsigned long)interceptor->dst_entry_cached_items));

  ssh_kernel_mutex_lock(interceptor->dst_entry_cache_lock);
  if (interceptor->dst_entry_cache_timeout_registered == TRUE)
    {
      ssh_kernel_mutex_unlock(interceptor->dst_entry_cache_lock);
      del_timer_sync(&interceptor->dst_cache_timer);
      ssh_kernel_mutex_lock(interceptor->dst_entry_cache_lock);
    }

  interceptor->dst_entry_cache_timeout_registered = FALSE;

  /* Free all entries that are left in the table. */
  for (slot = 0; slot < SSH_DST_ENTRY_TBL_SIZE; slot++)
    {
    restart:
      for (tmp = interceptor->dst_entry_table[slot];
	   tmp != NULL;
	   tmp = tmp->next)
	{
	  interceptor->dst_entry_table[slot] = tmp->next;

	  interceptor->dst_entry_cached_items--;

	  SSH_DEBUG(SSH_D_NICETOKNOW, ("Releasing dst cache entry"));

	  dst_release(tmp->dst_entry);
	  ssh_free(tmp);

	  goto restart;
	}
    }
  SSH_ASSERT(interceptor->dst_entry_cached_items == 0);
  ssh_kernel_mutex_unlock(interceptor->dst_entry_cache_lock);
}
示例#17
0
void ssh_engine_pme_disable_policy_lookup(SshEngine engine,
                                          SshPmeStatusCB callback,
                                          void *context)
{
  ssh_kernel_mutex_lock(engine->flow_control_table_lock);
  engine->policy_lookups_disabled = TRUE;
  ssh_kernel_mutex_unlock(engine->flow_control_table_lock);

  if (callback)
    (*callback)(engine->pm, FALSE, context);
}
void ssh_virtual_adapter_detach_all(SshInterceptor interceptor)
{
  SshVirtualAdapter adapter;
  SshUInt32 i = 0;
  SshVirtualAdapterDetachCB detach_cb;
  void *adapter_context;

 restart:
  local_bh_disable();
  ssh_kernel_mutex_lock(interceptor->interceptor_lock);
  for (; i < SSH_LINUX_MAX_VIRTUAL_ADAPTERS; i++)
    {
      adapter = interceptor->virtual_adapters[i];
      if (adapter == NULL)
	continue;
      
      detach_cb = NULL;
      adapter_context = NULL;
      if (adapter->detach_cb != NULL)
	{
	  detach_cb = adapter->detach_cb;
	  adapter_context = adapter->adapter_context;
	}

      ssh_virtual_adapter_clear(adapter);
      adapter->attached = 0;

      if (detach_cb != NULL)
	{
	  ssh_kernel_mutex_unlock(interceptor->interceptor_lock);
	  local_bh_enable();
	  
	  /* Destroy adapter_context. */
	  (*detach_cb)(adapter_context);
	  
	  goto restart;
	}
    }
  ssh_kernel_mutex_unlock(interceptor->interceptor_lock);
  local_bh_enable();
}
示例#19
0
static void engine_audit_request_poll_with_lock(void *context)
{
  SshEngine engine = context;

  engine->audit_timeout_scheduled = 0;

  if (engine->ipm_open == FALSE)
    return;

  ssh_kernel_mutex_lock(engine->flow_control_table_lock);
  engine_audit_busy(engine);
  ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
}
void ssh_engine_notify_ipm_close(SshEngine engine)
{
    SSH_DEBUG(1, ("User level module closed connection."));

    /* Lock the engine. */
    ssh_kernel_mutex_lock(engine->lock);

    /* Mark the policy interface not open. */
    engine->ipm_open = FALSE;

    /* Unlock the engine. */
    ssh_kernel_mutex_unlock(engine->lock);
}
void ssh_fastpath_fragmagic_timeout(void *context)
{
  SshFastpath fastpath = (SshFastpath)context;
  SshFastpathFragEntry fe;
  SshUInt32 num_frags;
  SshTime now;
  SshInterceptorPacket frag_free_list = NULL;

  ssh_interceptor_get_time(&now, NULL);

  SSH_DEBUG(SSH_D_MIDOK, ("Fragmagic timer; tick at %ld",
			  (long) now));

  ssh_kernel_mutex_lock(fastpath->frag_lock);

  fastpath->frag_timeout_scheduled = 0;
  num_frags = fastpath->frag_num_fragments;

  /* Keep looping as long as the last packet on the data LRU has expired.
     Note that it might not be strictly the oldest, but soon will be. */
  for (;;)
    {
      fe = fastpath->frag_data_lru_tail;
      if (!fe || fe->expiration > now)
        break;
      /* Drop the oldest packet on the data LRU.  We now know that it has
         already expired. */
      ssh_fastpath_fragmagic_drop_data(fastpath, &frag_free_list);
    }
  num_frags -= fastpath->frag_num_fragments;

  /* Possibly reschedule a timeout to this function. */
  if (fastpath->frag_num_fragments)
    {
      SSH_DEBUG(SSH_D_MIDOK, ("Fragmagic timer; %d frags left - reschedule",
			      (int) fastpath->frag_num_fragments));
      fastpath->frag_timeout_scheduled = 1;
      ssh_kernel_timeout_register(5, 0,
				  ssh_fastpath_fragmagic_timeout, fastpath);
    }
  ssh_kernel_mutex_unlock(fastpath->frag_lock);

#ifdef SSH_IPSEC_STATISTICS
  ssh_kernel_critical_section_start(fastpath->stats_critical_section);
  fastpath->stats[ssh_kernel_get_cpu()].counters[SSH_ENGINE_STAT_FRAGDROP]
    += num_frags;
  ssh_kernel_critical_section_end(fastpath->stats_critical_section);
#endif /* SSH_IPSEC_STATISTICS */

  ssh_fastpath_fragmagic_free_packet_list(frag_free_list);
}
void
engine_rule_packet_handler(SshEngine engine, SshEnginePacketContext pc)
{
  SshEngineActionRet ret;

  SSH_INTERCEPTOR_STACK_MARK();

#ifndef SSH_IPSEC_IP_ONLY_INTERCEPTOR
  /* We do not want packets with headers prepended to them. */
  SSH_ASSERT(pc->protocol_offset == 0);
#endif /* SSH_IPSEC_IP_ONLY_INTERCEPTOR */

  ssh_kernel_mutex_lock(engine->flow_control_table_lock);

  /* Perform PMTU processing */
  ret = engine_packet_handle_pmtu(engine, pc);

  /* Handle trigger/dangling flows */
  if (ret == SSH_ENGINE_RET_OK && pc->flow_index != SSH_IPSEC_INVALID_INDEX)
    ret = engine_packet_handle_flow(engine, pc);

  /* Verify packet selectors against SA selectors if the packet
     has been decapsulated from a tunnel. */
  if (ret == SSH_ENGINE_RET_OK && pc->tunnel_id > 1)
    {
      ret = engine_packet_handler_verify_sa_selectors(engine, pc);
      pc->flags |= SSH_ENGINE_PC_SKIP_TRD_VERIFY;
    }

  /* Perform Rule lookup */
  if (ret == SSH_ENGINE_RET_OK)
    ret = engine_packet_handler_rule_lookup(engine, pc);

  ssh_kernel_mutex_unlock(engine->flow_control_table_lock);

  if (ret == SSH_ENGINE_RET_OK && pc->rule != NULL)
    {
      /* Found a rule.  Process the packet according to the rule.  This will
	 eventually call engine_packet_continue again, which will decrement
	 the reference count of the rule when it sees pc->rule non-NULL. */
      ret = ssh_engine_execute_rule(pc);
    }

  if (ret == SSH_ENGINE_RET_OK)
    ret = SSH_ENGINE_RET_RESTART_FLOW_LOOKUP;

  /* Pass the packet back to fastpath */
  if (ret != SSH_ENGINE_RET_ASYNC)
    engine_packet_continue(pc, ret);
  return;
}
示例#23
0
int ssh_interceptor_packet_freelist_stats(SshInterceptor interceptor,
					  char *buf, int maxsize)
{
  int len;

  ssh_kernel_mutex_lock(interceptor->packet_lock);
  len = ssh_snprintf(buf, maxsize,
                     "Freelist list - "
                     "reused:%d allocated:%d\n",
                     freelist_reused,
                     freelist_alloc);

  ssh_kernel_mutex_unlock(interceptor->packet_lock);
  return len;
}
示例#24
0
void ssh_engine_pme_enable_policy_lookup(SshEngine engine,
                                         SshPmeStatusCB callback,
                                         void *context)
{
  ssh_kernel_mutex_lock(engine->flow_control_table_lock);
  engine->policy_lookups_disabled = FALSE;
#ifndef SSH_IPSEC_SMALL
  ssh_engine_rule_lookup_flush(engine, engine->policy_rule_set);
#endif /* SSH_IPSEC_SMALL */
  ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
  ssh_engine_flow_undangle_all(engine);

  if (callback)
    (*callback)(engine->pm, TRUE, context);
}
示例#25
0
void ssh_engine_pme_get_flow_stats(SshEngine engine, SshUInt32 orig_flow_index,
				   SshPmeFlowStatsCB callback, void *context)
{
  SshEngineFlowControl c_flow;
  SshEngineFlowData d_flow;
  SshEngineFlowStatsStruct stats;
  SshUInt32 flow_index;
  
  flow_index = SSH_ENGINE_FLOW_UNWRAP_INDEX(orig_flow_index);

  if (flow_index >= engine->flow_table_size
      || orig_flow_index == SSH_IPSEC_INVALID_INDEX)
    {
      (*callback)(engine->pm, NULL, context);
      return;
    }

  /* Copy the flow statistics to local storage to ensure that the flow
     does not disappear from under us while we are delivering the stats
     to the caller. */
  ssh_kernel_mutex_lock(engine->flow_control_table_lock);
  c_flow = SSH_ENGINE_GET_FLOW(engine, flow_index);
  if (!(c_flow->control_flags & SSH_ENGINE_FLOW_C_VALID))
    {
      ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
      (*callback)(engine->pm, NULL, context);
      return;
    }

  d_flow = FASTPATH_GET_READ_ONLY_FLOW(engine->fastpath, flow_index);
  stats = d_flow->stats;
  FASTPATH_RELEASE_FLOW(engine->fastpath, flow_index);

  ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
  (*callback)(engine->pm, &stats, context);
}
Boolean 
ssh_engine_packet_start(SshEngine engine, SshInterceptorPacket pp,
			SshUInt32 tunnel_id, SshUInt32 prev_transform_index,
			SshUInt32 pc_flags)
{
  SshEnginePacketContext pc;
  SshEngineTransformData trd;
    
  SSH_DEBUG(SSH_D_LOWOK, ("Sending packet to the fastpath pp=%p, "
			  "tunnel_id=%d, prev_transform_index=%x",
			  pp, (int) tunnel_id,
			  (unsigned int) prev_transform_index));

  if (pp->flags & SSH_PACKET_FROMADAPTER)
    pp->flags |= SSH_ENGINE_P_FROMADAPTER;

  /* Allocate a packet context for the new packet. */  
  if ((pc = ssh_engine_alloc_pc(engine)) == NULL)
    {
      ssh_interceptor_packet_free(pp);
      return FALSE;
    }

  /* Initialize the new pc. */
  ssh_engine_init_pc(pc, engine, pp, tunnel_id, NULL);
  pc->flags = pc_flags;
  pc->prev_transform_index = prev_transform_index;

  /* Initialize transform_counter for outbound nested tunnel packets. */
  if (pc->flags & SSH_ENGINE_PC_RESTARTED_OUT
      && pc->prev_transform_index != SSH_IPSEC_INVALID_INDEX)
    {
      ssh_kernel_mutex_lock(engine->flow_control_table_lock);
      trd = FASTPATH_GET_READ_ONLY_TRD(engine->fastpath, 
				       pc->prev_transform_index);
      SSH_ASSERT(trd != NULL);
      SSH_ASSERT(trd->nesting_level > 0);
      pc->transform_counter = trd->nesting_level - 1;
      FASTPATH_RELEASE_TRD(engine->fastpath, pc->prev_transform_index);
      ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
    }
  
  /* Send the packet to the fastpath. This will handle the packet as if
     it had just been received from the network. */
  engine_packet_continue(pc, SSH_ENGINE_RET_RESTART);
  return TRUE;
}
void
engine_packet_continue(SshEnginePacketContext pc, SshEngineActionRet ret)
{
  SshEngine engine = pc->engine;
  
   /* If we have a rule referenced from the pc, that means a previous
     rule execution has completed.  Decrement the reference count of the
     rule.  */
  if (pc->rule != NULL)
    {
      ssh_kernel_mutex_lock(engine->flow_control_table_lock);
      ssh_engine_decrement_rule_refcnt(engine, pc->rule);
      ssh_kernel_mutex_unlock(engine->flow_control_table_lock);
      pc->rule = NULL;
    }
  fastpath_packet_continue(engine->fastpath, pc, ret);
}
示例#28
0
void ssh_engine_pme_get_next_transform_index(SshEngine engine,
					     SshUInt32 transform_index,
					     SshPmeIndexCB callback,
					     void *context)
{
  SshUInt32 i;
  SshEngineTransformData d_trd = NULL;
  SshEngineTransformControl c_trd = NULL;

  if (transform_index == SSH_IPSEC_INVALID_INDEX)
    i = 0;
  else
    i = SSH_ENGINE_UNWRAP_TRD_INDEX(transform_index) + 1;

  /* Lookup the next valid transform. */
  ssh_kernel_mutex_lock(engine->flow_control_table_lock);

  for (; i < engine->transform_table_size; i++)
    {
      c_trd = SSH_ENGINE_GET_TR_UNWRAPPED(engine, i);
      SSH_ASSERT(c_trd != NULL);

      d_trd = FASTPATH_GET_READ_ONLY_TRD(engine->fastpath, i);
      if (d_trd->transform != 0)
	{
	  FASTPATH_RELEASE_TRD(engine->fastpath, i);
	  /* Found it. */
	  break;
	}
      FASTPATH_RELEASE_TRD(engine->fastpath, i);
    }

  if (i < engine->transform_table_size)
    /* Found the next transform.  Wrap index and generation into
       `transform_index'. */
    transform_index = SSH_ENGINE_WRAP_TRD_INDEX(i, c_trd->generation);
  else
    /* No more transforms available. */
    transform_index = SSH_IPSEC_INVALID_INDEX;

  ssh_kernel_mutex_unlock(engine->flow_control_table_lock);

  /* Return the result. */
  (*callback)(engine->pm, transform_index, context);
}
示例#29
0
void ssh_engine_pme_arp_add(SshEngine engine,
			    const SshIpAddr ip,
			    SshUInt32 ifnum,
			    const unsigned char *media_addr,
			    size_t media_addr_len,
			    SshUInt32 flags,
			    SshPmeStatusCB callback, void *context)
{
  Boolean success = TRUE;
  SshEngineIfnum eng_ifnum = SSH_INTERCEPTOR_INVALID_IFNUM;

  if (ifnum != SSH_INVALID_IFNUM)
    eng_ifnum = (SshEngineIfnum) ifnum;

  if (media_addr_len != SSH_ETHERH_ADDRLEN)
    {
      SSH_DEBUG(SSH_D_FAIL,
                ("Invalid media address length: %u vs. expected %u",
                 media_addr_len, SSH_ETHERH_ADDRLEN));
      goto error;
    }

#ifndef SSH_IPSEC_IP_ONLY_INTERCEPTOR
  /* The interface_lock protects ARP cache. */
  ssh_kernel_mutex_lock(engine->interface_lock);

  /* Add a new entry to the ARP cache. */
  success = ssh_engine_arp_add(engine, ip, eng_ifnum, media_addr,
                               (flags & SSH_PME_ARP_PERMANENT) ? TRUE : FALSE,
                               (flags & SSH_PME_ARP_PROXY) ? TRUE : FALSE,
			       (flags & SSH_PME_ARP_GLOBAL) ? TRUE : FALSE);

  ssh_kernel_mutex_unlock(engine->interface_lock);
#endif /* SSH_IPSEC_IP_ONLY_INTERCEPTOR */

  /* All done. */
  (*callback)(engine->pm, success, context);
  return;

  /* Error handling. */
 error:
  (*callback)(engine->pm, FALSE, context);
}
示例#30
0
void ssh_engine_pme_arp_remove(SshEngine engine,
			       const SshIpAddr ip,
			       SshUInt32 ifnum)
{
  SshEngineIfnum eng_ifnum = SSH_INTERCEPTOR_INVALID_IFNUM;

  if (ifnum != SSH_INVALID_IFNUM)
    eng_ifnum = (SshEngineIfnum) ifnum;

#ifndef SSH_IPSEC_IP_ONLY_INTERCEPTOR
  /* The interface_lock protects the ARP cache. */
  ssh_kernel_mutex_lock(engine->interface_lock);

  /* Remove the ARP entry from the ARP cache. */
  ssh_engine_arp_delete(engine, ip, eng_ifnum);

  ssh_kernel_mutex_unlock(engine->interface_lock);
#endif /* SSH_IPSEC_IP_ONLY_INTERCEPTOR */
}