int sadb_msg_send_expire(struct ipsec_sa *sa) { int i=0, error = 0; struct sadb_msg *msg = NULL; struct sadb_ext *ext_msgs[SADB_EXT_MAX+1]; struct socket_list *pfkey_socketsp = NULL; if (!sa) { PFKEY_DEBUG("sa is null\n"); return -EINVAL; } memset(ext_msgs, 0, sizeof(ext_msgs)); error = pfkey_msg_hdr_build(&ext_msgs[0], SADB_EXPIRE, sa->ipsec_proto, 0, 0, 0); if (error) { PFKEY_DEBUG("pfkey_msg_hdr_build is failed\n"); goto free_ext_finish; } error = pfkey_sa_build(&ext_msgs[SADB_EXT_SA], SADB_EXT_SA, sa->spi, 64, sa->state, sa->auth_algo.algo, sa->esp_algo.algo, 0); /* TODO: add pfs flag to struct ipsec_sa */ if (error) { PFKEY_DEBUG("pfkey_sa_build is failed\n"); goto free_ext_finish; } error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_CURRENT], SADB_EXT_LIFETIME_CURRENT, sa->lifetime_c.allocations, sa->lifetime_c.bytes, sa->lifetime_c.addtime, sa->lifetime_c.usetime); if (error) { PFKEY_DEBUG("pfkey_lifetime_build is failed\n"); goto free_ext_finish; } switch(sa->state) { case SADB_SASTATE_DEAD: error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_HARD], SADB_EXT_LIFETIME_HARD, sa->lifetime_h.allocations, sa->lifetime_h.bytes, sa->lifetime_h.addtime, sa->lifetime_h.usetime); if (error) { PFKEY_DEBUG("pfkey_liftime_build(hard) is failed\n"); goto free_ext_finish; } break; case SADB_SASTATE_DYING: error = pfkey_lifetime_build(&ext_msgs[SADB_EXT_LIFETIME_SOFT], SADB_EXT_LIFETIME_SOFT, sa->lifetime_s.allocations, sa->lifetime_s.bytes, sa->lifetime_s.addtime, sa->lifetime_s.usetime); if (error) { PFKEY_DEBUG("pfkey_lifetime_build(soft) is failed\n"); goto free_ext_finish; } break; case SADB_SASTATE_LARVAL: case SADB_SASTATE_MATURE: default: error = -EINVAL; goto free_ext_finish; } error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC], SADB_EXT_ADDRESS_SRC, sa->proto, sa->prefixlen_s, (struct sockaddr*)&sa->src); if (error) goto free_ext_finish; error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST], SADB_EXT_ADDRESS_DST, sa->proto, sa->prefixlen_d, (struct sockaddr*)&sa->dst); if (error) goto free_ext_finish; error = pfkey_msg_build(&msg, ext_msgs, EXT_BITS_OUT); write_lock(&pfkey_sk_lock); for (pfkey_socketsp = pfkey_open_sockets; pfkey_socketsp; pfkey_socketsp = pfkey_socketsp->next) { pfkey_upmsg(pfkey_socketsp->socketp, msg); } write_unlock(&pfkey_sk_lock); kfree(msg); free_ext_finish: for(i=0; i<SADB_MAX+1; i++) { if (ext_msgs[i]) { kfree(ext_msgs[i]); } } return 0; }
int sadb_msg_send_acquire(struct ipsec_sa *sa) { int i=0, error = 0; uint comb_num = 0; struct sadb_comb combs[4]; struct digest_implementation *di = NULL; struct cipher_implementation *ci = NULL; struct sadb_msg *msg = NULL; struct sadb_ext *ext_msgs[SADB_EXT_MAX+1]; struct socket_list *pfkey_socketsp = NULL; memset(ext_msgs, 0, sizeof(ext_msgs)); memset(combs, 0, sizeof(combs)); if (sa->ipsec_proto == SADB_SATYPE_AH || sa->ipsec_proto == SADB_SATYPE_ESP) { di = find_digest_by_name("md5", 0 /* atomic */); if (di) { combs[comb_num].sadb_comb_auth = SADB_AALG_MD5HMAC; combs[comb_num].sadb_comb_auth_minbits = AUTH_MD5HMAC_KEY_BITS; combs[comb_num].sadb_comb_auth_maxbits = AUTH_MD5HMAC_KEY_BITS; combs[comb_num].sadb_comb_reserved = 0; combs[comb_num].sadb_comb_soft_allocations = 0; combs[comb_num].sadb_comb_hard_allocations = 0; combs[comb_num].sadb_comb_soft_bytes = 0; combs[comb_num].sadb_comb_hard_bytes = 0; combs[comb_num].sadb_comb_soft_addtime = 57600; combs[comb_num].sadb_comb_hard_addtime = 86400; combs[comb_num].sadb_comb_soft_usetime = 57600; combs[comb_num].sadb_comb_hard_usetime = 86400; comb_num++; di = NULL; } di = find_digest_by_name("sha1", 0 /* atomic */); if (di) { combs[comb_num].sadb_comb_auth = SADB_AALG_SHA1HMAC; combs[comb_num].sadb_comb_auth_minbits = AUTH_SHA1HMAC_KEY_BITS; combs[comb_num].sadb_comb_auth_maxbits = AUTH_SHA1HMAC_KEY_BITS; combs[comb_num].sadb_comb_reserved = 0; combs[comb_num].sadb_comb_soft_allocations = 0; combs[comb_num].sadb_comb_hard_allocations = 0; combs[comb_num].sadb_comb_soft_bytes = 0; combs[comb_num].sadb_comb_hard_bytes = 0; combs[comb_num].sadb_comb_soft_addtime = 57600; combs[comb_num].sadb_comb_hard_addtime = 86400; combs[comb_num].sadb_comb_soft_usetime = 57600; combs[comb_num].sadb_comb_hard_usetime = 86400; comb_num++; di = NULL; } } if (sa->ipsec_proto == SADB_SATYPE_ESP) { ci = find_cipher_by_name("des-cbc", 1 /* atomic */); if (ci) { combs[comb_num].sadb_comb_encrypt = SADB_EALG_DESCBC; combs[comb_num].sadb_comb_encrypt_minbits = ESP_DES_KEY_BITS; combs[comb_num].sadb_comb_encrypt_maxbits = ESP_DES_KEY_BITS; combs[comb_num].sadb_comb_reserved = 0; combs[comb_num].sadb_comb_soft_allocations = 0; combs[comb_num].sadb_comb_hard_allocations = 0; combs[comb_num].sadb_comb_soft_bytes = 0; combs[comb_num].sadb_comb_hard_bytes = 0; combs[comb_num].sadb_comb_soft_addtime = 57600; combs[comb_num].sadb_comb_hard_addtime = 86400; combs[comb_num].sadb_comb_soft_usetime = 57600; combs[comb_num].sadb_comb_hard_usetime = 86400; comb_num++; ci = NULL; } ci = find_cipher_by_name("des_ede3-cbc", 1 /* atomic */); if (ci) { combs[comb_num].sadb_comb_encrypt = SADB_EALG_3DESCBC; combs[comb_num].sadb_comb_encrypt_minbits = ESP_3DES_KEY_BITS; combs[comb_num].sadb_comb_encrypt_maxbits = ESP_3DES_KEY_BITS; combs[comb_num].sadb_comb_reserved = 0; combs[comb_num].sadb_comb_soft_allocations = 0; combs[comb_num].sadb_comb_hard_allocations = 0; combs[comb_num].sadb_comb_soft_bytes = 0; combs[comb_num].sadb_comb_hard_bytes = 0; combs[comb_num].sadb_comb_soft_addtime = 57600; combs[comb_num].sadb_comb_hard_addtime = 86400; combs[comb_num].sadb_comb_soft_usetime = 57600; combs[comb_num].sadb_comb_hard_usetime = 86400; comb_num++; ci = NULL; } ci = find_cipher_by_name("aes-cbc", 1 /* atomic */); if (ci) { combs[comb_num].sadb_comb_encrypt = SADB_EALG_AES; combs[comb_num].sadb_comb_encrypt_minbits = ESP_AES_KEY_BITS; combs[comb_num].sadb_comb_encrypt_maxbits = ESP_AES_KEY_BITS; combs[comb_num].sadb_comb_reserved = 0; combs[comb_num].sadb_comb_soft_allocations = 0; combs[comb_num].sadb_comb_hard_allocations = 0; combs[comb_num].sadb_comb_soft_bytes = 0; combs[comb_num].sadb_comb_hard_bytes = 0; combs[comb_num].sadb_comb_soft_addtime = 57600; combs[comb_num].sadb_comb_hard_addtime = 86400; combs[comb_num].sadb_comb_soft_usetime = 57600; combs[comb_num].sadb_comb_hard_usetime = 86400; comb_num++; ci = NULL; } } error = pfkey_msg_hdr_build(&ext_msgs[0], SADB_ACQUIRE, sa->ipsec_proto, 0, 0, 0); if (error) { PFKEY_DEBUG("pfkey_msg_hdr_build is failed\n"); goto free_ext_finish; } error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_SRC], SADB_EXT_ADDRESS_SRC, sa->proto, sa->prefixlen_s, (struct sockaddr*)&sa->src); if (error) goto free_ext_finish; error = pfkey_address_build(&ext_msgs[SADB_EXT_ADDRESS_DST], SADB_EXT_ADDRESS_DST, sa->proto, sa->prefixlen_d, (struct sockaddr*)&sa->dst); if (error) goto free_ext_finish; error = pfkey_prop_build(&ext_msgs[SADB_EXT_PROPOSAL], 64, comb_num, combs); if (error) goto free_ext_finish; error = pfkey_msg_build(&msg, ext_msgs, EXT_BITS_OUT); write_lock(&pfkey_sk_lock); for (pfkey_socketsp = pfkey_registered_sockets[sa->ipsec_proto]; pfkey_socketsp; pfkey_socketsp = pfkey_socketsp->next) { pfkey_upmsg(pfkey_socketsp->socketp, msg); } write_unlock(&pfkey_sk_lock); kfree(msg); free_ext_finish: for(i=0; i<SADB_MAX+1; i++) { if (ext_msgs[i]) { kfree(ext_msgs[i]); } } return 0; }
/* derived from FreeS/WAN-1.9 pfkey_v2_parse.c (mk) */ int pfkey_msg_interp(struct sock *sk, struct sadb_msg *pfkey_msg) { int error = 0; struct sadb_msg *pfkey_reply = NULL; struct sadb_ext *reply_ext_msgs[SADB_EXT_MAX+1]; struct socket_list *pfkey_socketsp = 0; if (pfkey_msg->sadb_msg_satype > SADB_SATYPE_MAX) { return -EINVAL; } memset(reply_ext_msgs, 0, SADB_EXT_MAX+1); switch (pfkey_msg->sadb_msg_type) { case SADB_GETSPI: error = sadb_msg_add_parse(sk, pfkey_msg, &pfkey_reply); PFKEY_DEBUG("PF_KEY:interp: SADB_GETSPI\n"); break; case SADB_UPDATE: error = -EINVAL;/* XXX */ PFKEY_DEBUG("PF_KEY:interp: SADB_UPDATE\n"); break; case SADB_ADD: error = sadb_msg_add_parse(sk, pfkey_msg, &pfkey_reply); PFKEY_DEBUG("PF_KEY:interp: SADB_ADD\n"); break; case SADB_DELETE: error = sadb_msg_delete_parse(sk, pfkey_msg, &pfkey_reply); PFKEY_DEBUG("PF_KEY:interp: SADB_DELETE\n"); break; case SADB_FLUSH: error = sadb_msg_flush_parse(sk, pfkey_msg, &pfkey_reply); PFKEY_DEBUG("PF_KEY:interp: SADB_FLUSH\n"); break; case SADB_REGISTER: error = sadb_msg_register_parse(sk, pfkey_msg, &pfkey_reply); PFKEY_DEBUG("PF_KEY:interp: SADB_REGISTER\n"); break; case SADB_X_GRPSA: error = -EINVAL;/* XXX */ PFKEY_DEBUG("PF_KEY:interp: SADB_X_GRPSA\n"); break; case SADB_X_ADDFLOW: error = sadb_msg_addflow_parse(sk, pfkey_msg, &pfkey_reply); PFKEY_DEBUG("PF_KEY:interp: SADB_ADDFLOW\n"); break; case SADB_X_DELFLOW: error = sadb_msg_delflow_parse(sk, pfkey_msg, &pfkey_reply); PFKEY_DEBUG("PF_KEY:interp: SADB_DELFLOW\n"); break; case SADB_X_FLUSH_SP: error = sadb_msg_flush_sp_parse(sk, pfkey_msg, &pfkey_reply); PFKEY_DEBUG("PFKEY:interp: SADB_X_FLUSH_SP\n"); break; default: error = -EINVAL; break; } if (error) { PFKEY_DEBUG("PFKEY:interp: parse routine return error=%d\n", error); goto err; } switch (pfkey_msg->sadb_msg_type) { case SADB_GETSPI: case SADB_UPDATE: case SADB_ADD: case SADB_DELETE: case SADB_FLUSH: case SADB_X_ADDFLOW: case SADB_X_DELFLOW: case SADB_X_FLUSH_SP: write_lock_bh(&pfkey_sk_lock); for (pfkey_socketsp = pfkey_open_sockets; pfkey_socketsp; pfkey_socketsp = pfkey_socketsp->next) { pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply); } write_unlock_bh(&pfkey_sk_lock); break; case SADB_GET: case SADB_DUMP: case SADB_REGISTER: write_lock_bh(&pfkey_sk_lock); pfkey_upmsg(sk->socket, pfkey_reply); write_unlock_bh(&pfkey_sk_lock); break; case SADB_ACQUIRE: write_lock_bh(&pfkey_sk_lock); for (pfkey_socketsp = pfkey_registered_sockets[pfkey_msg->sadb_msg_satype]; pfkey_socketsp; pfkey_socketsp = pfkey_socketsp->next) { pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply); } write_unlock_bh(&pfkey_sk_lock); break; default: error = -EINVAL; goto err; } if (pfkey_reply) kfree(pfkey_reply); return 0; err: if (pfkey_reply) kfree(pfkey_reply); pfkey_reply = kmalloc(sizeof(struct sadb_msg), GFP_KERNEL); if (!pfkey_reply){ return -ENOMEM; } memcpy(pfkey_reply, pfkey_msg, sizeof(pfkey_reply)); pfkey_reply->sadb_msg_errno = error; write_lock_bh(&pfkey_sk_lock); pfkey_upmsg(sk->socket, pfkey_reply); for (pfkey_socketsp = pfkey_registered_sockets[pfkey_msg->sadb_msg_satype]; pfkey_socketsp; pfkey_socketsp = pfkey_socketsp->next) { pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply); } write_unlock_bh(&pfkey_sk_lock); if (pfkey_reply) { kfree(pfkey_reply); } return error; }