void ssh_virtual_adapter_ip_ether_address(SshIpAddr ip, unsigned char *buffer) { memset(buffer, 0, SSH_ETHERH_ADDRLEN); if (SSH_IP_IS4(ip)) { buffer[1] = 2; SSH_IP4_ENCODE(ip, buffer + 2); } #if defined (WITH_IPV6) else { SshUInt32 value; value = SSH_IP6_WORD0_TO_INT(ip); value ^= SSH_IP6_WORD1_TO_INT(ip); value ^= SSH_IP6_WORD2_TO_INT(ip); value ^= SSH_IP6_WORD3_TO_INT(ip); buffer[1] = 2; SSH_PUT_32BIT(buffer + 2, value); } #endif /* WITH_IPV6 */ }
SshOperationHandle ssh_pm_cfgmode_client_store_register(SshPm pm, SshPmTunnel tunnel, SshPmActiveCfgModeClient client, SshIpAddr address, void *address_context, SshPmRemoteAccessAttrsFreeCB free_cb, void *free_cb_context, SshPmStatusCB status_cb, void *status_cb_context) { SSH_DEBUG(SSH_D_LOWOK, ("Registering address `%@'", ssh_ipaddr_render, address)); SSH_ASSERT(client->status_cb == NULL_FNPTR); if (client->flags & SSH_PM_CFGMODE_CLIENT_ADDING_ARP) goto error; if (!SSH_IP_DEFINED(address)) goto error; if (SSH_IP_IS4(address)) { SSH_ASSERT(client->ip4 == NULL); client->ip4 = ssh_memdup(address, sizeof(*address)); if (client->ip4 == NULL) goto error; client->ip4_address_context = address_context; } else { SSH_ASSERT(client->ip6 == NULL); client->ip6 = ssh_memdup(address, sizeof(*address)); if (client->ip6 == NULL) goto error; client->ip6_address_context = address_context; } client->free_cb = free_cb; client->free_cb_context = free_cb_context; /* Check if we should add a proxy ARP entry for the remote access client. */ if (tunnel->flags & SSH_PM_TR_PROXY_ARP) { unsigned char media_addr[SSH_ETHERH_ADDRLEN]; SshUInt32 flags; /* Create a fake ethernet address. */ memset(media_addr, 0, sizeof(media_addr)); if (SSH_IP_IS4(address)) { media_addr[1] = 2; SSH_IP4_ENCODE(address, media_addr + 2); client->flags |= SSH_PM_CFGMODE_CLIENT_IPV4_PROXY_ARP; } else { SshUInt32 value; value = SSH_IP6_WORD0_TO_INT(address); value ^= SSH_IP6_WORD1_TO_INT(address); value ^= SSH_IP6_WORD2_TO_INT(address); value ^= SSH_IP6_WORD3_TO_INT(address); media_addr[1] = 2; SSH_PUT_32BIT(media_addr + 2, value); client->flags |= SSH_PM_CFGMODE_CLIENT_IPV6_PROXY_ARP; } /* Flags for ARP entry. */ flags = SSH_PME_ARP_PERMANENT | SSH_PME_ARP_GLOBAL | SSH_PME_ARP_PROXY; /* Store status_cb. */ client->status_cb = status_cb; client->status_cb_context = status_cb_context; if (SSH_IP_IS4(address)) client->flags |= SSH_PM_CFGMODE_CLIENT_IPV4_REGISTERING; else client->flags |= SSH_PM_CFGMODE_CLIENT_IPV6_REGISTERING; /* Register an abort callback for the engine operation. */ ssh_operation_register_no_alloc(&client->operation, pm_cfgmode_client_store_arp_abort, client); /* Take a reference to the client and mark ARP ongoing. */ ssh_pm_cfgmode_client_store_take_reference(pm, client); client->flags |= SSH_PM_CFGMODE_CLIENT_ADDING_ARP; /* Add ARP entry. */ SSH_DEBUG(SSH_D_LOWSTART, ("Adding ARP entry")); ssh_pme_arp_add(pm->engine, address, 0, media_addr, sizeof(media_addr), flags, pm_cfgmode_client_store_arp_cb, client); return &client->operation; } if (status_cb) (*status_cb)(pm, TRUE, status_cb_context); return NULL; error: if (status_cb) (*status_cb)(pm, FALSE, status_cb_context); return NULL; }