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); }
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); }
/* 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); }
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); }
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(); }
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; }
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; }
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); }
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); }
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); }
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); }
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 */ }