sa.c

来自「xen 3.2.2 源码」· C语言 代码 · 共 757 行 · 第 1/2 页

C
757
字号
SAState * sa_table_lookup_spi(u32 spi, u32 protocol, u32 addr){    SAState *state = NULL;    Hashcode h;    SAIdent id = {        .spi      = spi,        .protocol = protocol,        .addr     = addr };    TableArg arg = { .ptr = &id };    HTEntry *entry = NULL;    h = sa_table_hash_spi(spi, protocol, addr);    entry = HashTable_find_entry(sa_table, h, sa_table_spi_fn, arg);    if(entry){        state = entry->value;        SAState_incref(state);    }    return state;}/** Find an SA by unique id. * Increments the SA refcount on success. * * @param id id * @return SA or NULL */SAState * sa_table_lookup_id(u32 id){    Hashcode h;    TableArg arg = { .ul = id };    HTEntry *entry = NULL;    SAState *state = NULL;    dprintf("> id=%u\n", id);    h = sa_table_hash_id(id);    entry = HashTable_find_entry(sa_table, h, sa_table_id_fn, arg);    if(entry){        state = entry->value;        SAState_incref(state);    }    dprintf("< state=%p\n", state);    return state;}/** Replace an existing SA by another in the table. * The existing SA is not removed if the new one cannot be added. * * @param existing SA to replace * @param state new SA * @return 0 on success, error code otherwise */static int sa_table_replace(SAState *existing, SAState *state){    int err = 0;    // Need check for in-use?        dprintf(">\n");    if(existing->keying.state != SA_STATE_ACQUIRE){        err = -EINVAL;        goto exit;    }    // replace it.    err = sa_table_add(state);    if(err) goto exit;    sa_table_delete(existing);  exit:    dprintf("< err=%d\n", err);    return err;}/** Allocate an SA. * * @return SA or NULL */SAState *SAState_alloc(void){    SAState *state;        dprintf(">\n");    state = kmalloc(sizeof(SAState), GFP_ATOMIC);    if(!state) goto exit;    *state = (SAState){};    atomic_set(&state->refcount, 1);    state->lock = SPIN_LOCK_UNLOCKED;  exit:    dprintf("< state=%p\n", state);    return state;}/** Create an SA in initial state. * It has no spi and its keying state is acquire. * It must have a unique id, protocol and address. * At some point it should get updated with a complete SA. * * @param ident SA identifier * @param statep return parameter for new SA * @return 0 on success, error code otherwise */int SAState_init(SAIdent *ident, SAState **statep){    int err = 0;    SAState *state = NULL;       if(ident->spi || !ident->id){        err = -EINVAL;        goto exit;    }    state = SAState_alloc();    if (!state){        err = -ENOMEM;        goto exit;    }    state->ident = *ident;    state->keying.state = SA_STATE_ACQUIRE;  exit:    return err;}/** Create a complete SA, with spi and cipher suite. * * @param info SA parameters * @param statep return parameter for new SA * @return 0 on success, error code otherwise */int SAState_create(SAInfo *info, SAState **statep){    int err = 0;    SAState *state = NULL;    dprintf(">\n");    state = SAState_alloc();    if (!state){        err = -ENOMEM;        goto exit;    }    state->ident = info->ident;    state->limits = info->limits;    state->digest = info->digest;    state->cipher = info->cipher;    state->compress = info->compress;    state->security = info->security;    err = SAType_get(state->ident.protocol, &state->type);    if (err) goto exit;    err = state->type->init(state, NULL);    if (err) goto exit;    state->keying.state = SA_STATE_VALID;  exit:    if(err){        SAState_decref(state);        state = NULL;    }    *statep = state;    dprintf("< err=%d\n", err);    return err;}/** Create an SA for the given spi etc. * For now we fix the cipher suite and the keys. * Digest is SHA1 HMAC with a 128-bit key. * Cipher is AES (Rijndael) in CBC mode with a 128-bit key. * * The cipher suite and keys should really come from policy, with the * possibility of negotiating them with the peer (using IKE). * Negotiation creates difficulties though - because the SA cannot * be created immediately we have to be able to queue packets * while the SA is being negotiated. * * @param spi spi * @param protocol protocol * @param addr address * @param sa return parameter for SA * @return 0 on success, error code otherwise */int sa_create(int security, u32 spi, u32 protocol, u32 addr, SAState **sa){    int err = 0;    SAInfo info = {};    char *digest_name = "sha1";    char *digest_key = "0123456789abcdef";    int digest_key_n = strlen(digest_key);    char *cipher_name= "aes";    char *cipher_key = "0123456789ABCDEF";    int cipher_key_n = strlen(cipher_key);    dprintf("> security=%d spi=%u protocol=%u addr=" IPFMT "\n",            security, spi, protocol, NIPQUAD(addr));    if(!spi){        spi = generate_spi(0, 0, protocol, addr);    }    dprintf("> info...\n");    info.ident.id = sa_id++;    info.ident.spi = spi;    info.ident.protocol = protocol;    info.ident.addr = addr;    info.security = security;    //sa_algorithm_probe_all();    dprintf("> digest name=%s key_n=%d\n", digest_name, digest_key_n);    strcpy(info.digest.name, digest_name);    info.digest.bits = digest_key_n * 8;    memcpy(info.digest.key, digest_key, digest_key_n);    if(security & SA_CONF){        dprintf("> cipher name=%s key_n=%d\n", cipher_name, cipher_key_n);        strcpy(info.cipher.name, cipher_name);        info.cipher.bits = cipher_key_n * 8;        memcpy(info.cipher.key, cipher_key, cipher_key_n);    } else {        dprintf("> cipher name=%s key_n=%d\n", "cipher_null", 0);        strcpy(info.cipher.name, "cipher_null");        info.cipher.bits = 0;        memset(info.cipher.key, 0, sizeof(info.cipher.key));    }    err = sa_set(&info, 0, sa);    dprintf("< err=%d\n", err);    return err;}/** Create or update an SA. * The SA is added to the table. * * @param info SA parameters * @param update create if zero, update otherwise * @return 0 on success, error code otherwise */int sa_set(SAInfo *info, int update, SAState **val){    int err = 0;    SAState *state = NULL;    SAState *existing = NULL;    dprintf("> info=%p update=%d val=%p\n", info, update, val);    existing = sa_table_lookup_id(info->ident.id);    if(update && !existing){        err = -ENOENT;    } else if(!update && existing){        err = -EINVAL;    }    if(err) goto exit;    err = SAState_create(info, &state);    if (err) goto exit;    if(existing){        err = sa_table_replace(existing, state);    } else {        err = sa_table_add(state);    }  exit:    if(existing) SAState_decref(existing);    if(val && !err){        *val = state;    } else {        SAState_decref(state);    }    dprintf("< err=%d\n", err);    return err;}/** Delete an SA. Removes it from the SA table. * It is an error if no SA with the given id exists. * * @param id SA id * @return 0 on success, error code otherwise */int sa_delete(int id){    int err = 0;    SAState *state;    state = sa_table_lookup_id(id);    if (!state){        err = -ENOENT;        goto exit;    }    sa_table_delete(state);    SAState_decref(state);  exit:    return err;}/** Determine ESP security mode for a new SA. * * @param spi incoming spi * @param protocol incoming protocol * @param addr source address * @return security level or negative error code * * @todo Need to check spi, and do some lookup for security params. */int vnet_sa_security(u32 spi, int protocol, u32 addr){    extern int vnet_security_default;    int security = vnet_security_default;    dprintf("< security=%x\n", security);    return security;}/** Create a new SA for incoming traffic. * * @param spi incoming spi * @param protocol incoming protocol * @param addr source address * @param sa return parameter for SA * @return 0 on success, error code otherwise */int vnet_sa_create(u32 spi, int protocol, u32 addr, SAState **sa){    int err = 0;    int security = vnet_sa_security(spi, protocol, addr);    if(security < 0){        err = security;        goto exit;    }    err = sa_create(security, spi, protocol, addr, sa);  exit:    return err;}/** Open function for SA tunnels. * * @param tunnel to open * @return 0 on success, error code otherwise */static int sa_tunnel_open(Tunnel *tunnel){    int err = 0;    //dprintf(">\n");    //dprintf("< err=%d\n", err);    return err;}/** Close function for SA tunnels. * * @param tunnel to close (OK if null) */static void sa_tunnel_close(Tunnel *tunnel){    SAState *sa;    if(!tunnel) return;    sa = tunnel->data;    if(!sa) return;    SAState_decref(sa);    tunnel->data = NULL;}/** Packet send function for SA tunnels. * * @param tunnel to send on * @param skb packet to send * @return 0 on success, negative error code on error */static int sa_tunnel_send(Tunnel *tunnel, struct sk_buff *skb){    int err = -EINVAL;    SAState *sa;    if(!tunnel){        wprintf("> Null tunnel!\n");        goto exit;    }    sa = tunnel->data;    if(!sa){        wprintf("> Null SA!\n");        goto exit;    }    err = SAState_send(sa, skb, tunnel->base);  exit:    return err;}/** Functions used by SA tunnels. */static TunnelType _sa_tunnel_type = {    .name	= "SA",    .open	= sa_tunnel_open,    .close	= sa_tunnel_close,    .send 	= sa_tunnel_send};/** Functions used by SA tunnels. */TunnelType *sa_tunnel_type = &_sa_tunnel_type;int sa_tunnel_create(Vnet *info, VarpAddr *addr, Tunnel *base, Tunnel **tunnel){    int err = 0;    SAState *sa = NULL;    //FIXME: Assuming IPv4 for now.    u32 ipaddr = addr->u.ip4.s_addr;    err = Tunnel_create(sa_tunnel_type, &info->vnet, addr, base, tunnel);    if(err) goto exit;    err = sa_create(info->security, 0, IPPROTO_ESP, ipaddr, &sa);    if(err) goto exit;    (*tunnel)->data = sa;  exit:    return err;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?