+static int
+key_validate_address_pair(struct sadb_address *src0,
+ struct sadb_address *dst0)
+{
+ u_int plen = 0;
+
+ /* check upper layer protocol */
+ if (src0->sadb_address_proto != dst0->sadb_address_proto) {
+ ipseclog((LOG_DEBUG, "key_parse: upper layer protocol mismatched.\n"));
+ PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+ return (EINVAL);
+ }
+
+ /* check family */
+ if (PFKEY_ADDR_SADDR(src0)->sa_family !=
+ PFKEY_ADDR_SADDR(dst0)->sa_family) {
+ ipseclog((LOG_DEBUG, "key_parse: address family mismatched.\n"));
+ PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+ return (EINVAL);
+ }
+ if (PFKEY_ADDR_SADDR(src0)->sa_len !=
+ PFKEY_ADDR_SADDR(dst0)->sa_len) {
+ ipseclog((LOG_DEBUG,
+ "key_parse: address struct size mismatched.\n"));
+ PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+ return (EINVAL);
+ }
+
+ switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
+ case AF_INET:
+ if (PFKEY_ADDR_SADDR(src0)->sa_len != sizeof(struct sockaddr_in)) {
+ PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+ return (EINVAL);
+ }
+ break;
+ case AF_INET6:
+ if (PFKEY_ADDR_SADDR(src0)->sa_len != sizeof(struct sockaddr_in6)) {
+ PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+ return (EINVAL);
+ }
+ break;
+ default:
+ ipseclog((LOG_DEBUG,
+ "key_parse: unsupported address family.\n"));
+ PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+ return (EAFNOSUPPORT);
+ }
+
+ switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ plen = 0; /*fool gcc*/
+ break;
+ }
+
+ /* check max prefix length */
+ if (src0->sadb_address_prefixlen > plen ||
+ dst0->sadb_address_prefixlen > plen) {
+ ipseclog((LOG_DEBUG,
+ "key_parse: illegal prefixlen.\n"));
+ PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+ return (EINVAL);
+ }
+
+ /*
+ * prefixlen == 0 is valid because there can be a case when
+ * all addresses are matched.
+ */
+ return (0);
+}
+