- {
- u32 bi0;
- vlib_buffer_t * b0;
- u32 next0 = IKEV2_NEXT_ERROR_DROP;
- u32 sw_if_index0;
- ip4_header_t * ip40;
- udp_header_t * udp0;
- ike_header_t * ike0;
- ikev2_sa_t * sa0 = 0;
- int len = 0;
- int r;
-
- /* speculatively enqueue b0 to the current next frame */
- bi0 = from[0];
- to_next[0] = bi0;
- from += 1;
- to_next += 1;
- n_left_from -= 1;
- n_left_to_next -= 1;
-
- b0 = vlib_get_buffer (vm, bi0);
- ike0 = vlib_buffer_get_current (b0);
- vlib_buffer_advance(b0, - sizeof(*udp0));
- udp0 = vlib_buffer_get_current (b0);
- vlib_buffer_advance(b0, - sizeof(*ip40));
- ip40 = vlib_buffer_get_current (b0);
-
- if (ike0->version != IKE_VERSION_2)
- {
- vlib_node_increment_counter(vm, ikev2_node.index,
- IKEV2_ERROR_NOT_IKEV2, 1);
- goto dispatch0;
- }
-
- if (ike0->exchange == IKEV2_EXCHANGE_SA_INIT)
- {
- ikev2_sa_t sa; /* temporary store for SA */
- sa0 = &sa;
- memset (sa0, 0, sizeof (*sa0));
-
- if (ike0->rspi == 0)
- {
- sa0->raddr.as_u32 = ip40->dst_address.as_u32;
- sa0->iaddr.as_u32 = ip40->src_address.as_u32;
-
- r = ikev2_retransmit_sa_init(ike0, sa0->iaddr, sa0->raddr);
- if (r == 1)
- {
- vlib_node_increment_counter(vm, ikev2_node.index,
- IKEV2_ERROR_IKE_SA_INIT_RETRANSMIT,
- 1);
- len = clib_net_to_host_u32(ike0->length);
- goto dispatch0;
- }
- else if (r == -1)
- {
- vlib_node_increment_counter(vm, ikev2_node.index,
- IKEV2_ERROR_IKE_SA_INIT_IGNORE,
- 1);
- goto dispatch0;
- }
-
- ikev2_process_sa_init_req(vm, sa0, ike0);
-
- if (sa0->state == IKEV2_STATE_SA_INIT)
- {
- ikev2_sa_free_proposal_vector(&sa0->r_proposals);
- sa0->r_proposals = ikev2_select_proposal(sa0->i_proposals,
- IKEV2_PROTOCOL_IKE);
- ikev2_generate_sa_init_data(sa0);
- }
-
- if (sa0->state == IKEV2_STATE_SA_INIT ||
- sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE)
- {
- len = ikev2_generate_resp(sa0, ike0);
- }
-
- if (sa0->state == IKEV2_STATE_SA_INIT)
- {
- /* add SA to the pool */
- pool_get (km->per_thread_data[cpu_index].sas, sa0);
- clib_memcpy(sa0, &sa, sizeof(*sa0));
- hash_set (km->per_thread_data[cpu_index].sa_by_rspi,
- sa0->rspi,
- sa0 - km->per_thread_data[cpu_index].sas);
- }
- else
- {
- ikev2_sa_free_all_vec(sa0);
- }
- }
- }
- else if (ike0->exchange == IKEV2_EXCHANGE_IKE_AUTH)
- {
- uword * p;
- p = hash_get(km->per_thread_data[cpu_index].sa_by_rspi,
- clib_net_to_host_u64(ike0->rspi));
- if (p)
- {
- sa0 = pool_elt_at_index (km->per_thread_data[cpu_index].sas,
- p[0]);
-
- r = ikev2_retransmit_resp(sa0, ike0);
- if (r == 1)
- {
- vlib_node_increment_counter(vm, ikev2_node.index,
- IKEV2_ERROR_IKE_REQ_RETRANSMIT,
- 1);
- len = clib_net_to_host_u32(ike0->length);
- goto dispatch0;
- }
- else if (r == -1)
- {
- vlib_node_increment_counter(vm, ikev2_node.index,
- IKEV2_ERROR_IKE_REQ_IGNORE,
- 1);
- goto dispatch0;
- }
-
- ikev2_process_auth_req(vm, sa0, ike0);
- ikev2_sa_auth(sa0);
- if (sa0->state == IKEV2_STATE_AUTHENTICATED)
- {
- ikev2_initial_contact_cleanup(sa0);
- ikev2_sa_match_ts(sa0);
- if (sa0->state != IKEV2_STATE_TS_UNACCEPTABLE)
- ikev2_create_tunnel_interface(km->vnet_main, sa0,
- &sa0->childs[0]);
- }
- len = ikev2_generate_resp(sa0, ike0);
- }
- }
- else if (ike0->exchange == IKEV2_EXCHANGE_INFORMATIONAL)
- {
- uword * p;
- p = hash_get(km->per_thread_data[cpu_index].sa_by_rspi,
- clib_net_to_host_u64(ike0->rspi));
- if (p)
- {
- sa0 = pool_elt_at_index (km->per_thread_data[cpu_index].sas,
- p[0]);
-
- r = ikev2_retransmit_resp(sa0, ike0);
- if (r == 1)
- {
- vlib_node_increment_counter(vm, ikev2_node.index,
- IKEV2_ERROR_IKE_REQ_RETRANSMIT,
- 1);
- len = clib_net_to_host_u32(ike0->length);
- goto dispatch0;
- }
- else if (r == -1)
- {
- vlib_node_increment_counter(vm, ikev2_node.index,
- IKEV2_ERROR_IKE_REQ_IGNORE,
- 1);
- goto dispatch0;
- }
-
- ikev2_process_informational_req(vm, sa0, ike0);
- if (sa0->del)
- {
- if (sa0->del[0].protocol_id != IKEV2_PROTOCOL_IKE)
- {
- ikev2_delete_t * d, * tmp, * resp = 0;
- vec_foreach(d, sa0->del)
- {
- ikev2_child_sa_t * ch_sa;
- ch_sa = ikev2_sa_get_child(sa0, d->spi,
- d->protocol_id);
- if (ch_sa)
- {
- ikev2_delete_tunnel_interface(km->vnet_main,
- sa0, ch_sa);
- vec_add2(resp, tmp, 1);
- tmp->protocol_id = d->protocol_id;
- tmp->spi = ch_sa->r_proposals[0].spi;
- ikev2_sa_del_child_sa(sa0, ch_sa);
- }
- }
- vec_free(sa0->del);
- sa0->del = resp;
- }
- }
- len = ikev2_generate_resp(sa0, ike0);
- }
- }
- else if (ike0->exchange == IKEV2_EXCHANGE_CREATE_CHILD_SA)
- {
- uword * p;
- p = hash_get(km->per_thread_data[cpu_index].sa_by_rspi,
- clib_net_to_host_u64(ike0->rspi));
- if (p)
- {
- sa0 = pool_elt_at_index (km->per_thread_data[cpu_index].sas,
- p[0]);
-
- r = ikev2_retransmit_resp(sa0, ike0);
- if (r == 1)
- {
- vlib_node_increment_counter(vm, ikev2_node.index,
- IKEV2_ERROR_IKE_REQ_RETRANSMIT,
- 1);
- len = clib_net_to_host_u32(ike0->length);
- goto dispatch0;
- }
- else if (r == -1)
- {
- vlib_node_increment_counter(vm, ikev2_node.index,
- IKEV2_ERROR_IKE_REQ_IGNORE,
- 1);
- goto dispatch0;
- }
-
- ikev2_process_create_child_sa_req(vm, sa0, ike0);
- if (sa0->rekey)
- {
- if (sa0->rekey[0].protocol_id != IKEV2_PROTOCOL_IKE)
- {
- ikev2_child_sa_t * child;
- vec_add2(sa0->childs, child, 1);
- child->r_proposals = sa0->rekey[0].r_proposal;
- child->i_proposals = sa0->rekey[0].i_proposal;
- child->tsi = sa0->rekey[0].tsi;
- child->tsr = sa0->rekey[0].tsr;
- ikev2_create_tunnel_interface(km->vnet_main, sa0,
- child);
- }
- len = ikev2_generate_resp(sa0, ike0);
- }
- }
- }
- else
- {
- clib_warning("IKEv2 exchange %u packet received from %U to %U",
- ike0->exchange,
- format_ip4_address, ip40->src_address.as_u8,
- format_ip4_address, ip40->dst_address.as_u8);
- }
-
-dispatch0:
- /* if we are sending packet back, rewrite headers */
- if (len)
- {
- next0 = IKEV2_NEXT_IP4_LOOKUP;
- ip40->dst_address.as_u32 = sa0->iaddr.as_u32;
- ip40->src_address.as_u32 = sa0->raddr.as_u32;
- udp0->length = clib_host_to_net_u16(len + sizeof(udp_header_t));
- udp0->checksum = 0;
- b0->current_length = len + sizeof(ip4_header_t) + sizeof(udp_header_t);
- ip40->length = clib_host_to_net_u16(b0->current_length);
- ip40->checksum = ip4_header_checksum (ip40);
- }
- /* delete sa */
- if (sa0 && (sa0->state == IKEV2_STATE_DELETED ||
- sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE))
- {
- ikev2_child_sa_t * c;
-
- vec_foreach(c, sa0->childs)
- ikev2_delete_tunnel_interface(km->vnet_main, sa0, c);
-
- ikev2_delete_sa(sa0);
- }
- sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
-
- if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
- && (b0->flags & VLIB_BUFFER_IS_TRACED)))
- {
- ikev2_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
- t->sw_if_index = sw_if_index0;
- t->next_index = next0;
- }
-
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
- n_left_to_next, bi0, next0);
- }
+ {
+ u32 bi0;
+ vlib_buffer_t *b0;
+ u32 next0 = IKEV2_NEXT_ERROR_DROP;
+ u32 sw_if_index0;
+ ip4_header_t *ip40;
+ udp_header_t *udp0;
+ ike_header_t *ike0;
+ ikev2_sa_t *sa0 = 0;
+ int len = 0;
+ int r;
+
+ /* speculatively enqueue b0 to the current next frame */
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ ike0 = vlib_buffer_get_current (b0);
+ vlib_buffer_advance (b0, -sizeof (*udp0));
+ udp0 = vlib_buffer_get_current (b0);
+ vlib_buffer_advance (b0, -sizeof (*ip40));
+ ip40 = vlib_buffer_get_current (b0);
+
+ if (ike0->version != IKE_VERSION_2)
+ {
+ vlib_node_increment_counter (vm, ikev2_node.index,
+ IKEV2_ERROR_NOT_IKEV2, 1);
+ goto dispatch0;
+ }
+
+ if (ike0->exchange == IKEV2_EXCHANGE_SA_INIT)
+ {
+ ikev2_sa_t sa; /* temporary store for SA */
+ sa0 = &sa;
+ memset (sa0, 0, sizeof (*sa0));
+
+ if (ike0->rspi == 0)
+ {
+ sa0->raddr.as_u32 = ip40->dst_address.as_u32;
+ sa0->iaddr.as_u32 = ip40->src_address.as_u32;
+
+ r = ikev2_retransmit_sa_init (ike0, sa0->iaddr, sa0->raddr);
+ if (r == 1)
+ {
+ vlib_node_increment_counter (vm, ikev2_node.index,
+ IKEV2_ERROR_IKE_SA_INIT_RETRANSMIT,
+ 1);
+ len = clib_net_to_host_u32 (ike0->length);
+ goto dispatch0;
+ }
+ else if (r == -1)
+ {
+ vlib_node_increment_counter (vm, ikev2_node.index,
+ IKEV2_ERROR_IKE_SA_INIT_IGNORE,
+ 1);
+ goto dispatch0;
+ }
+
+ ikev2_process_sa_init_req (vm, sa0, ike0);
+
+ if (sa0->state == IKEV2_STATE_SA_INIT)
+ {
+ ikev2_sa_free_proposal_vector (&sa0->r_proposals);
+ sa0->r_proposals =
+ ikev2_select_proposal (sa0->i_proposals,
+ IKEV2_PROTOCOL_IKE);
+ ikev2_generate_sa_init_data (sa0);
+ }
+
+ if (sa0->state == IKEV2_STATE_SA_INIT ||
+ sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE)
+ {
+ len = ikev2_generate_resp (sa0, ike0);
+ }
+
+ if (sa0->state == IKEV2_STATE_SA_INIT)
+ {
+ /* add SA to the pool */
+ pool_get (km->per_thread_data[cpu_index].sas, sa0);
+ clib_memcpy (sa0, &sa, sizeof (*sa0));
+ hash_set (km->per_thread_data[cpu_index].sa_by_rspi,
+ sa0->rspi,
+ sa0 - km->per_thread_data[cpu_index].sas);
+ }
+ else
+ {
+ ikev2_sa_free_all_vec (sa0);
+ }
+ }
+ }
+ else if (ike0->exchange == IKEV2_EXCHANGE_IKE_AUTH)
+ {
+ uword *p;
+ p = hash_get (km->per_thread_data[cpu_index].sa_by_rspi,
+ clib_net_to_host_u64 (ike0->rspi));
+ if (p)
+ {
+ sa0 = pool_elt_at_index (km->per_thread_data[cpu_index].sas,
+ p[0]);
+
+ r = ikev2_retransmit_resp (sa0, ike0);
+ if (r == 1)
+ {
+ vlib_node_increment_counter (vm, ikev2_node.index,
+ IKEV2_ERROR_IKE_REQ_RETRANSMIT,
+ 1);
+ len = clib_net_to_host_u32 (ike0->length);
+ goto dispatch0;
+ }
+ else if (r == -1)
+ {
+ vlib_node_increment_counter (vm, ikev2_node.index,
+ IKEV2_ERROR_IKE_REQ_IGNORE,
+ 1);
+ goto dispatch0;
+ }
+
+ ikev2_process_auth_req (vm, sa0, ike0);
+ ikev2_sa_auth (sa0);
+ if (sa0->state == IKEV2_STATE_AUTHENTICATED)
+ {
+ ikev2_initial_contact_cleanup (sa0);
+ ikev2_sa_match_ts (sa0);
+ if (sa0->state != IKEV2_STATE_TS_UNACCEPTABLE)
+ ikev2_create_tunnel_interface (km->vnet_main, sa0,
+ &sa0->childs[0]);
+ }
+ len = ikev2_generate_resp (sa0, ike0);
+ }
+ }
+ else if (ike0->exchange == IKEV2_EXCHANGE_INFORMATIONAL)
+ {
+ uword *p;
+ p = hash_get (km->per_thread_data[cpu_index].sa_by_rspi,
+ clib_net_to_host_u64 (ike0->rspi));
+ if (p)
+ {
+ sa0 = pool_elt_at_index (km->per_thread_data[cpu_index].sas,
+ p[0]);
+
+ r = ikev2_retransmit_resp (sa0, ike0);
+ if (r == 1)
+ {
+ vlib_node_increment_counter (vm, ikev2_node.index,
+ IKEV2_ERROR_IKE_REQ_RETRANSMIT,
+ 1);
+ len = clib_net_to_host_u32 (ike0->length);
+ goto dispatch0;
+ }
+ else if (r == -1)
+ {
+ vlib_node_increment_counter (vm, ikev2_node.index,
+ IKEV2_ERROR_IKE_REQ_IGNORE,
+ 1);
+ goto dispatch0;
+ }
+
+ ikev2_process_informational_req (vm, sa0, ike0);
+ if (sa0->del)
+ {
+ if (sa0->del[0].protocol_id != IKEV2_PROTOCOL_IKE)
+ {
+ ikev2_delete_t *d, *tmp, *resp = 0;
+ vec_foreach (d, sa0->del)
+ {
+ ikev2_child_sa_t *ch_sa;
+ ch_sa = ikev2_sa_get_child (sa0, d->spi,
+ d->protocol_id);
+ if (ch_sa)
+ {
+ ikev2_delete_tunnel_interface (km->vnet_main,
+ sa0, ch_sa);
+ vec_add2 (resp, tmp, 1);
+ tmp->protocol_id = d->protocol_id;
+ tmp->spi = ch_sa->r_proposals[0].spi;
+ ikev2_sa_del_child_sa (sa0, ch_sa);
+ }
+ }
+ vec_free (sa0->del);
+ sa0->del = resp;
+ }
+ }
+ len = ikev2_generate_resp (sa0, ike0);
+ }
+ }
+ else if (ike0->exchange == IKEV2_EXCHANGE_CREATE_CHILD_SA)
+ {
+ uword *p;
+ p = hash_get (km->per_thread_data[cpu_index].sa_by_rspi,
+ clib_net_to_host_u64 (ike0->rspi));
+ if (p)
+ {
+ sa0 = pool_elt_at_index (km->per_thread_data[cpu_index].sas,
+ p[0]);
+
+ r = ikev2_retransmit_resp (sa0, ike0);
+ if (r == 1)
+ {
+ vlib_node_increment_counter (vm, ikev2_node.index,
+ IKEV2_ERROR_IKE_REQ_RETRANSMIT,
+ 1);
+ len = clib_net_to_host_u32 (ike0->length);
+ goto dispatch0;
+ }
+ else if (r == -1)
+ {
+ vlib_node_increment_counter (vm, ikev2_node.index,
+ IKEV2_ERROR_IKE_REQ_IGNORE,
+ 1);
+ goto dispatch0;
+ }
+
+ ikev2_process_create_child_sa_req (vm, sa0, ike0);
+ if (sa0->rekey)
+ {
+ if (sa0->rekey[0].protocol_id != IKEV2_PROTOCOL_IKE)
+ {
+ ikev2_child_sa_t *child;
+ vec_add2 (sa0->childs, child, 1);
+ child->r_proposals = sa0->rekey[0].r_proposal;
+ child->i_proposals = sa0->rekey[0].i_proposal;
+ child->tsi = sa0->rekey[0].tsi;
+ child->tsr = sa0->rekey[0].tsr;
+ ikev2_create_tunnel_interface (km->vnet_main, sa0,
+ child);
+ }
+ len = ikev2_generate_resp (sa0, ike0);
+ }
+ }
+ }
+ else
+ {
+ clib_warning ("IKEv2 exchange %u packet received from %U to %U",
+ ike0->exchange,
+ format_ip4_address, ip40->src_address.as_u8,
+ format_ip4_address, ip40->dst_address.as_u8);
+ }
+
+ dispatch0:
+ /* if we are sending packet back, rewrite headers */
+ if (len)
+ {
+ next0 = IKEV2_NEXT_IP4_LOOKUP;
+ ip40->dst_address.as_u32 = sa0->iaddr.as_u32;
+ ip40->src_address.as_u32 = sa0->raddr.as_u32;
+ udp0->length =
+ clib_host_to_net_u16 (len + sizeof (udp_header_t));
+ udp0->checksum = 0;
+ b0->current_length =
+ len + sizeof (ip4_header_t) + sizeof (udp_header_t);
+ ip40->length = clib_host_to_net_u16 (b0->current_length);
+ ip40->checksum = ip4_header_checksum (ip40);
+ }
+ /* delete sa */
+ if (sa0 && (sa0->state == IKEV2_STATE_DELETED ||
+ sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE))
+ {
+ ikev2_child_sa_t *c;
+
+ vec_foreach (c, sa0->childs)
+ ikev2_delete_tunnel_interface (km->vnet_main, sa0, c);
+
+ ikev2_delete_sa (sa0);
+ }
+ sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+
+ if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
+ && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+ {
+ ikev2_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->sw_if_index = sw_if_index0;
+ t->next_index = next0;
+ }
+
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+ n_left_to_next, bi0, next0);
+ }