+ && spidx0->ul_proto != spidx1->ul_proto) {
+ return 0;
+ }
+
+ /* If spidx1 specifies interface, ignore src addr */
+ if (spidx1->internal_if != NULL) {
+ if (spidx0->internal_if == NULL
+ || spidx0->internal_if != spidx1->internal_if) {
+ return 0;
+ }
+
+ /* Still check ports */
+ switch (spidx0->src.ss_family) {
+ case AF_INET:
+ if (spidx0_src_is_range &&
+ (satosin(&spidx1->src)->sin_port < satosin(&spidx0->src_range.start)->sin_port
+ || satosin(&spidx1->src)->sin_port > satosin(&spidx0->src_range.end)->sin_port)) {
+ return 0;
+ } else if (satosin(&spidx0->src)->sin_port != IPSEC_PORT_ANY
+ && satosin(&spidx0->src)->sin_port !=
+ satosin(&spidx1->src)->sin_port) {
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if (spidx0_src_is_range &&
+ (satosin6(&spidx1->src)->sin6_port < satosin6(&spidx0->src_range.start)->sin6_port
+ || satosin6(&spidx1->src)->sin6_port > satosin6(&spidx0->src_range.end)->sin6_port)) {
+ return 0;
+ } else if (satosin6(&spidx0->src)->sin6_port != IPSEC_PORT_ANY
+ && satosin6(&spidx0->src)->sin6_port !=
+ satosin6(&spidx1->src)->sin6_port) {
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ } else if (spidx0_src_is_range) {
+ if (!key_is_addr_in_range(&spidx1->src, &spidx0->src_range)) {
+ return 0;
+ }
+ } else {
+ switch (spidx0->src.ss_family) {
+ case AF_INET:
+ if (satosin(&spidx0->src)->sin_port != IPSEC_PORT_ANY
+ && satosin(&spidx0->src)->sin_port !=
+ satosin(&spidx1->src)->sin_port) {
+ return 0;
+ }
+ if (!key_bbcmp((caddr_t)&satosin(&spidx0->src)->sin_addr,
+ (caddr_t)&satosin(&spidx1->src)->sin_addr, spidx0->prefs)) {
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if (satosin6(&spidx0->src)->sin6_port != IPSEC_PORT_ANY
+ && satosin6(&spidx0->src)->sin6_port !=
+ satosin6(&spidx1->src)->sin6_port) {
+ return 0;
+ }
+ /*
+ * scope_id check. if sin6_scope_id is 0, we regard it
+ * as a wildcard scope, which matches any scope zone ID.
+ */
+ if (satosin6(&spidx0->src)->sin6_scope_id &&
+ satosin6(&spidx1->src)->sin6_scope_id &&
+ satosin6(&spidx0->src)->sin6_scope_id !=
+ satosin6(&spidx1->src)->sin6_scope_id) {
+ return 0;
+ }
+ if (!key_bbcmp((caddr_t)&satosin6(&spidx0->src)->sin6_addr,
+ (caddr_t)&satosin6(&spidx1->src)->sin6_addr, spidx0->prefs)) {
+ return 0;
+ }
+ break;
+ default:
+ /* XXX */
+ if (bcmp(&spidx0->src, &spidx1->src, spidx0->src.ss_len) != 0) {
+ return 0;
+ }
+ break;
+ }
+ }
+
+ if (spidx0_dst_is_range) {
+ if (!key_is_addr_in_range(&spidx1->dst, &spidx0->dst_range)) {
+ return 0;
+ }
+ } else {
+ switch (spidx0->dst.ss_family) {
+ case AF_INET:
+ if (satosin(&spidx0->dst)->sin_port != IPSEC_PORT_ANY
+ && satosin(&spidx0->dst)->sin_port !=
+ satosin(&spidx1->dst)->sin_port) {
+ return 0;
+ }
+ if (!key_bbcmp((caddr_t)&satosin(&spidx0->dst)->sin_addr,
+ (caddr_t)&satosin(&spidx1->dst)->sin_addr, spidx0->prefd)) {
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if (satosin6(&spidx0->dst)->sin6_port != IPSEC_PORT_ANY
+ && satosin6(&spidx0->dst)->sin6_port !=
+ satosin6(&spidx1->dst)->sin6_port) {
+ return 0;
+ }
+ /*
+ * scope_id check. if sin6_scope_id is 0, we regard it
+ * as a wildcard scope, which matches any scope zone ID.
+ */
+ if (satosin6(&spidx0->src)->sin6_scope_id &&
+ satosin6(&spidx1->src)->sin6_scope_id &&
+ satosin6(&spidx0->dst)->sin6_scope_id !=
+ satosin6(&spidx1->dst)->sin6_scope_id) {
+ return 0;
+ }
+ if (!key_bbcmp((caddr_t)&satosin6(&spidx0->dst)->sin6_addr,
+ (caddr_t)&satosin6(&spidx1->dst)->sin6_addr, spidx0->prefd)) {
+ return 0;
+ }
+ break;
+ default:
+ /* XXX */
+ if (bcmp(&spidx0->dst, &spidx1->dst, spidx0->dst.ss_len) != 0) {
+ return 0;
+ }
+ break;
+ }
+ }
+
+ /* XXX Do we check other field ? e.g. flowinfo */
+
+ return 1;
+}
+
+static int
+key_is_addr_in_range(struct sockaddr_storage *addr, struct secpolicyaddrrange *addr_range)
+{
+ int cmp = 0;
+
+ if (addr == NULL || addr_range == NULL) {
+ return 0;
+ }
+
+ /* Must be greater than or equal to start */
+ cmp = key_sockaddrcmp((struct sockaddr *)addr, (struct sockaddr *)&addr_range->start, 1);
+ if (cmp != 0 && cmp != 1) {
+ return 0;
+ }
+
+ /* Must be less than or equal to end */
+ cmp = key_sockaddrcmp((struct sockaddr *)addr, (struct sockaddr *)&addr_range->end, 1);
+ if (cmp != 0 && cmp != -1) {