pf_key_v2_mask6_to_bits (ip6_sa->sin6_addr.in6_addr);
pf_key_v2_mask6_to_bits (&ip6_sa->sin6_addr.s6_addr[0]);
pf_key_v2_flow (struct sockaddr *laddr, struct sockaddr *lmask,		struct sockaddr *raddr,	struct sockaddr *rmask, 		u_int8_t tproto, u_int16_t sport, u_int16_t dport, 		u_int8_t *spi, u_int8_t proto, struct sockaddr *dst, 		struct sockaddr *src, int delete, int ingress,		u_int8_t srcid_type, u_int8_t *srcid, int srcid_len,		u_int8_t dstid_type, u_int8_t *dstid, int dstid_len){#if defined (SADB_X_ADDFLOW) && defined (SADB_X_DELFLOW)  struct sadb_msg msg;#ifdef SADB_X_EXT_FLOW_TYPE  struct sadb_protocol flowtype;  struct sadb_ident *sid = 0;#else  struct sadb_sa ssa;#endif  struct sadb_address *addr = 0;  struct sadb_protocol tprotocol;  struct pf_key_v2_msg *flow = 0, *ret = 0;  size_t len;  int err;#ifdef USE_DEBUG  char *laddr_str, *lmask_str, *raddr_str, *rmask_str;#endif#if !defined (SADB_X_SAFLAGS_INGRESS_FLOW) && !defined (SADB_X_EXT_FLOW_TYPE)  if (ingress)    return 0;#endif  msg.sadb_msg_type = delete ? SADB_X_DELFLOW : SADB_X_ADDFLOW;  switch (proto)    {    case IPSEC_PROTO_IPSEC_ESP:      msg.sadb_msg_satype = SADB_SATYPE_ESP;      break;    case IPSEC_PROTO_IPSEC_AH:      msg.sadb_msg_satype = SADB_SATYPE_AH;      break;    default:      log_print ("pf_key_v2_flow: invalid proto %d", proto);      goto cleanup;    }  msg.sadb_msg_seq = 0;  flow = pf_key_v2_msg_new (&msg, 0);  if (!flow)    goto cleanup;#ifdef SADB_X_EXT_FLOW_TYPE  if (!delete)    {      /* Setup the source ID, if provided. */      if (srcid)        {	  sid = calloc (PF_KEY_V2_ROUND (srcid_len + 1) + sizeof *sid,			sizeof (u_int8_t));	  if (!sid)	    goto cleanup;	  sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK)	    + PF_KEY_V2_ROUND (srcid_len + 1) / PF_KEY_V2_CHUNK;	  sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;	  sid->sadb_ident_type = srcid_type;	  memcpy (sid + 1, srcid, srcid_len);	  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)sid,				 PF_KEY_V2_NODE_MALLOCED) == -1)	    goto cleanup;	  sid = 0;	}      /* Setup the destination ID, if provided. */      if (dstid)        {	  sid = calloc (PF_KEY_V2_ROUND (dstid_len + 1) + sizeof *sid,			sizeof (u_int8_t));	  if (!sid)	    goto cleanup;	  sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK)	    + PF_KEY_V2_ROUND (dstid_len + 1) / PF_KEY_V2_CHUNK;	  sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;	  sid->sadb_ident_type = dstid_type;	  memcpy (sid + 1, dstid, dstid_len);	  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)sid,				 PF_KEY_V2_NODE_MALLOCED) == -1)	    goto cleanup;	  sid = 0;	}    }  /* Setup the flow type extension.  */  bzero (&flowtype, sizeof flowtype);  flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE;  flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK;  flowtype.sadb_protocol_direction    = ingress ? IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT;  flowtype.sadb_protocol_proto    = ingress ? SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE;  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)&flowtype, 0) == -1)    goto cleanup;#else /* SADB_X_EXT_FLOW_TYPE */  /* Setup the SA extension.  */  ssa.sadb_sa_exttype = SADB_EXT_SA;  ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK;  memcpy (&ssa.sadb_sa_spi, spi, sizeof ssa.sadb_sa_spi);  ssa.sadb_sa_replay = 0;  ssa.sadb_sa_state = 0;  ssa.sadb_sa_auth = 0;  ssa.sadb_sa_encrypt = 0;  ssa.sadb_sa_flags = 0;#ifdef SADB_X_SAFLAGS_INGRESS_FLOW  if (ingress)    ssa.sadb_sa_flags |= SADB_X_SAFLAGS_INGRESS_FLOW;#endif#ifdef SADB_X_SAFLAGS_REPLACEFLOW  if (!delete && !ingress)    ssa.sadb_sa_flags |= SADB_X_SAFLAGS_REPLACEFLOW;#endif  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)&ssa, 0) == -1)    goto cleanup;#endif /* SADB_X_EXT_FLOW_TYPE */  /*   * Setup the ADDRESS extensions.   */  len = sizeof *addr + PF_KEY_V2_ROUND (src->sa_len);#ifndef SADB_X_EXT_FLOW_TYPE  if (!delete || ingress)#else  if (!delete)#endif /* SADB_X_EXT_FLOW_TYPE */    {      addr = calloc (1, len);      if (!addr)	goto cleanup;      addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;      addr->sadb_address_len = len / PF_KEY_V2_CHUNK;      addr->sadb_address_reserved = 0;#ifdef SADB_X_EXT_FLOW_TYPE      pf_key_v2_setup_sockaddr (addr + 1, src, dst, 0, ingress);#else      pf_key_v2_setup_sockaddr (addr + 1, dst, NULL, 0, 0);#endif      if (pf_key_v2_msg_add (flow, (struct sadb_ext *)addr,			     PF_KEY_V2_NODE_MALLOCED) == -1)	goto cleanup;      addr = 0;    }  addr = calloc (1, len);  if (!addr)    goto cleanup;  addr->sadb_address_exttype = SADB_X_EXT_SRC_FLOW;  addr->sadb_address_len = len / PF_KEY_V2_CHUNK;  addr->sadb_address_reserved = 0;  pf_key_v2_setup_sockaddr (addr + 1, laddr, NULL, sport, 0);  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)addr,			 PF_KEY_V2_NODE_MALLOCED) == -1)    goto cleanup;  addr = 0;  addr = calloc (1, len);  if (!addr)    goto cleanup;  addr->sadb_address_exttype = SADB_X_EXT_SRC_MASK;  addr->sadb_address_len = len / PF_KEY_V2_CHUNK;  addr->sadb_address_reserved = 0;  pf_key_v2_setup_sockaddr (addr + 1, lmask, NULL, sport ? 0xffff : 0, 0);  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)addr,			 PF_KEY_V2_NODE_MALLOCED) == -1)    goto cleanup;  addr = 0;  addr = calloc (1, len);  if (!addr)    goto cleanup;  addr->sadb_address_exttype = SADB_X_EXT_DST_FLOW;  addr->sadb_address_len = len / PF_KEY_V2_CHUNK;  addr->sadb_address_reserved = 0;  pf_key_v2_setup_sockaddr (addr + 1, raddr, NULL, sport, 0);  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)addr,			 PF_KEY_V2_NODE_MALLOCED) == -1)    goto cleanup;  addr = 0;  addr = calloc (1, len);  if (!addr)    goto cleanup;  addr->sadb_address_exttype = SADB_X_EXT_DST_MASK;  addr->sadb_address_len = len / PF_KEY_V2_CHUNK;  addr->sadb_address_reserved = 0;  pf_key_v2_setup_sockaddr (addr + 1, rmask, NULL, sport ? 0xffff : 0, 0);  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)addr,			 PF_KEY_V2_NODE_MALLOCED) == -1)    goto cleanup;  addr = 0;  /* Setup the protocol extension.  */  bzero (&tprotocol, sizeof tprotocol);  tprotocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;  tprotocol.sadb_protocol_len = sizeof tprotocol / PF_KEY_V2_CHUNK;  tprotocol.sadb_protocol_proto = tproto;  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)&tprotocol, 0) == -1)    goto cleanup;#ifdef USE_DEBUG  if (sockaddr2text (laddr, &laddr_str, 0))    laddr_str = 0;  if (sockaddr2text (lmask, &lmask_str, 0))    lmask_str = 0;  if (sockaddr2text (raddr, &raddr_str, 0))    raddr_str = 0;  if (sockaddr2text (rmask, &rmask_str, 0))    rmask_str = 0;  LOG_DBG ((LOG_SYSDEP, 50,	    "pf_key_v2_flow: src %x %x dst %x %x proto %u sport %u dport %u",	    laddr_str ? laddr_str : "<???>", lmask_str ? laddr_str : "<???>",	    raddr_str ? laddr_str : "<???>", rmask_str ? laddr_str : "<???>",	    tproto, ntohs (sport), ntohs (dport)));  if (laddr_str)    free (laddr_str);  if (lmask_str)    free (lmask_str);  if (raddr_str)    free (raddr_str);  if (rmask_str)    free (rmask_str);#endif /* USE_DEBUG */  ret = pf_key_v2_call (flow);  pf_key_v2_msg_free (flow);  flow = 0;  if (!ret)    goto cleanup;  err = ((struct sadb_msg *)TAILQ_FIRST (ret)->seg)->sadb_msg_errno;  if (err)    {      if (err == ESRCH) /* These are common and usually harmless.  */	LOG_DBG ((LOG_SYSDEP, 10, "pf_key_v2_flow: %sFLOW: %s", 		  delete ? "DEL" : "ADD", strerror (err)));      else	log_print ("pf_key_v2_flow: %sFLOW: %s", delete ? "DEL" : "ADD", 		   strerror (err));      goto cleanup;    }  pf_key_v2_msg_free (ret);  LOG_DBG ((LOG_MISC, 50, "pf_key_v2_flow: done"));  return 0; cleanup:#ifdef SADB_X_EXT_FLOW_TYPE  if (sid)    free (sid);#endif /* SADB_X_EXT_FLOW_TYPE */  if (addr)    free (addr);  if (flow)    pf_key_v2_msg_free (flow);  if (ret)    pf_key_v2_msg_free (ret);  return -1;#elif defined (SADB_X_SPDADD) && defined (SADB_X_SPDDELETE)  struct sadb_msg msg;  struct sadb_x_policy *policy = 0;  struct sadb_x_ipsecrequest *ipsecrequest;  struct sadb_x_sa2 ssa2;  struct sadb_address *addr = 0;  struct sockaddr *saddr;  struct pf_key_v2_msg *flow = 0, *ret = 0;  u_int8_t *policy_buf;  size_t len;  int err;  msg.sadb_msg_type = delete ? SADB_X_SPDDELETE : SADB_X_SPDADD;  msg.sadb_msg_satype = SADB_SATYPE_UNSPEC;  msg.sadb_msg_seq = 0;  flow = pf_key_v2_msg_new (&msg, 0);  if (!flow)    goto cleanup;  memset (&ssa2, 0, sizeof ssa2);  ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;  ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK;  ssa2.sadb_x_sa2_mode = 0;  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)&ssa2, 0) == -1)    goto cleanup;  /*   * Setup the ADDRESS extensions.   */  len = sizeof *addr + PF_KEY_V2_ROUND (src->sa_len);  addr = calloc (1, len);  if (!addr)    goto cleanup;  addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;  addr->sadb_address_len = len / PF_KEY_V2_CHUNK;  addr->sadb_address_proto = IPSEC_ULPROTO_ANY;  addr->sadb_address_reserved = 0;  pf_key_v2_setup_sockaddr (addr + 1, laddr, NULL, IPSEC_PORT_ANY, 0);  switch (laddr->sa_family)    {    case AF_INET:      ip4_sa = (struct sockaddr_in *)lmask;      addr->sadb_address_prefixlen = 	pf_key_v2_mask_to_bits (ip4_sa->sin_addr.in_addr);      break;    case AF_INET6:      ip6_sa = (struct sockaddr_in6 *)lmask;      addr->sadb_address_prefixlen = 	pf_key_v2_mask6_to_bits (ip6_sa->sin6_addr.in6_addr);      break;    }  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)addr,			 PF_KEY_V2_NODE_MALLOCED) == -1)    goto cleanup;  addr = 0;  addr = calloc (1, len);  if (!addr)    goto cleanup;  addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;  addr->sadb_address_len = len / PF_KEY_V2_CHUNK;  addr->sadb_address_proto = IPSEC_ULPROTO_ANY;  addr->sadb_address_reserved = 0;  pf_key_v2_setup_sockaddr (addr + 1, raddr, NULL, IPSEC_PORT_ANY, 0);  switch (raddr->sa_family)    {    case AF_INET:      ip4_sa = (struct sockaddr_in *)rmask;      addr->sadb_address_prefixlen = 	pf_key_v2_mask_to_bits (ip4_sa->sin_addr.in_addr);      break;    case AF_INET6:      ip6_sa = (struct sockaddr_in6 *)rmask;      addr->sadb_address_prefixlen = 	pf_key_v2_mask6_to_bits (ip6_sa->sin6_addr.in6_addr);      break;    }  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)addr,			 PF_KEY_V2_NODE_MALLOCED) == -1)    goto cleanup;  addr = 0;  /* Setup the POLICY extension.  */  policy_buf = (u_int8_t *)calloc (1, sizeof *policy + sizeof *ipsecrequest +				   2 * sockaddr_len (src));  if (!policy_buf)    {      log_error ("pf_key_v2_flow: calloc %d failed", sizeof *policy +		 sizeof *ipsecrequest + 2 * sockaddr_len (src));      goto cleanup;    }  policy = (struct sadb_x_policy *)policy_buf;  policy->sadb_x_policy_exttype = SADB_X_EXT_POLICY;  policy->sadb_x_policy_len = sizeof policy_buf / PF_KEY_V2_CHUNK;  policy->sadb_x_policy_type = IPSEC_POLICY_IPSEC;  if (ingress)  	policy->sadb_x_policy_dir = IPSEC_DIR_INBOUND;  else  	policy->sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;  policy->sadb_x_policy_reserved = 0;  /* Setup the IPSECREQUEST extension part.  */  ipsecrequest = (struct sadb_x_ipsecrequest *)(policy + 1);  ipsecrequest->sadb_x_ipsecrequest_len    = sizeof *ipsecrequest + 2 * sockaddr_len (src);  switch (proto)    {    case IPSEC_PROTO_IPSEC_ESP:      ipsecrequest->sadb_x_ipsecrequest_proto = IPPROTO_ESP;      break;    case IPSEC_PROTO_IPSEC_AH:      ipsecrequest->sadb_x_ipsecrequest_proto = IPPROTO_AH;      break;    default:      log_print ("pf_key_v2_flow: invalid proto %d", proto);      goto cleanup;    }  ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL;	/* XXX */  ipsecrequest->sadb_x_ipsecrequest_level    = ingress ? IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE;  ipsecrequest->sadb_x_ipsecrequest_reqid = 0;	/* XXX */  /* Add source and destination addresses. */  saddr = (struct sockaddr *)(ipsecrequest + 1);  pf_key_v2_setup_sockaddr (saddr, src, NULL, 0, 0);  switch (src->sa_family)    {    case AF_INET:      saddr = (struct sockaddr_in *)saddr + 1;      break;    case AF_INET6:      saddr = (struct sockaddr_in6 *)saddr + 1;      break;    }  pf_key_v2_setup_sockaddr (saddr, dst, NULL, 0, 0);  if (pf_key_v2_msg_add (flow, (struct sadb_ext *)policy, 0) == -1)    goto cleanup;#ifdef USE_DEBUG  if (sockaddr2text (laddr, &laddr_str, 0))    laddr_str = 0;  if (sockaddr2text (lmask, &lmask_str, 0))    lmask_str = 0;  if (sockaddr2text (raddr, &raddr_str, 0))    raddr_str = 0;  if (sockaddr2text (rmask, &rmask_str, 0))    rmask_str = 0;  LOG_DBG ((LOG_SYSDEP, 50, "pf_key_v2_flow: src %x %x dst %x %x",	    laddr_str ? laddr_str : "<???>", lmask_str ? laddr_str : "<???>", 	    raddr_str ? laddr_str : "<???>", rmask_str ? laddr_str : "<???>"));  if (laddr_str)    free (laddr_str);  if (lmask_str)    free (lmask_str);  if (raddr_str)    free (raddr_str);  if (rmask_str)    free (rmask_str);#endif  ret = pf_key_v2_call (flow);  pf_key_v2_msg_free (flow);  flow = 0;  if (!ret)    goto cleanup;  err = ((struct sadb_msg *)TAILQ_FIRST (ret)->seg)->sadb_msg_errno;  if (err)    {      log_print ("pf_key_v2_flow: SPD%s: %s", delete ? "DELETE" : "ADD",		 strerror (err));      goto cleanup;    }  pf_key_v2_msg_free (ret);  LOG_DBG ((LOG_SYSDEP, 50, "pf_key_v2_flow: done"));  return 0; cleanup:  if (addr)    free (addr);  if (policy)    free (policy);  if (flow)    pf_key_v2_msg_free (flow);  if (ret)    pf_key_v2_msg_free (ret);  return -1;#else  log_print ("pf_key_v2_flow: not supported in pure PF_KEYv2");  return -1;#endif}