+/* gen_portrange code */
+struct block *
+gen_portrangeatom(off, v1, v2)
+ int off;
+ bpf_int32 v1, v2;
+{
+ struct slist *s1, *s2;
+ struct block *b1, *b2;
+
+ if (v1 > v2) {
+ /*
+ * Reverse the order of the ports, so v1 is the lower one.
+ */
+ bpf_int32 vtemp;
+
+ vtemp = v1;
+ v1 = v2;
+ v2 = vtemp;
+ }
+ s1 = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
+ s1->s.k = off_nl;
+
+ s1->next = new_stmt(BPF_LD|BPF_IND|BPF_H);
+ s1->next->s.k = off_nl + off;
+
+ b1 = new_block(JMP(BPF_JGE));
+ b1->stmts = s1;
+ b1->s.k = v1;
+
+ s2 = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
+ s2->s.k = off_nl;
+
+ s2->next = new_stmt(BPF_LD|BPF_IND|BPF_H);
+ s2->next->s.k = off_nl + off;
+
+ b2 = new_block(JMP(BPF_JGT));
+ gen_not(b2);
+ b2->stmts = s2;
+ b2->s.k = v2;
+
+ gen_and(b1, b2);
+
+ return b2;
+}
+
+struct block *
+gen_portrangeop(port1, port2, proto, dir)
+ int port1, port2;
+ int proto;
+ int dir;
+{
+ struct block *b0, *b1, *tmp;
+
+ /* ip proto 'proto' */
+ tmp = gen_cmp(off_nl + 9, BPF_B, (bpf_int32)proto);
+ b0 = gen_ipfrag();
+ gen_and(tmp, b0);
+
+ switch (dir) {
+ case Q_SRC:
+ b1 = gen_portrangeatom(0, (bpf_int32)port1, (bpf_int32)port2);
+ break;
+
+ case Q_DST:
+ b1 = gen_portrangeatom(2, (bpf_int32)port1, (bpf_int32)port2);
+ break;
+
+ case Q_OR:
+ case Q_DEFAULT:
+ tmp = gen_portrangeatom(0, (bpf_int32)port1, (bpf_int32)port2);
+ b1 = gen_portrangeatom(2, (bpf_int32)port1, (bpf_int32)port2);
+ gen_or(tmp, b1);
+ break;
+
+ case Q_AND:
+ tmp = gen_portrangeatom(0, (bpf_int32)port1, (bpf_int32)port2);
+ b1 = gen_portrangeatom(2, (bpf_int32)port1, (bpf_int32)port2);
+ gen_and(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+
+ return b1;
+}
+
+static struct block *
+gen_portrange(port1, port2, ip_proto, dir)
+ int port1, port2;
+ int ip_proto;
+ int dir;
+{
+ struct block *b0, *b1, *tmp;
+
+ /* link proto ip */
+ b0 = gen_linktype(ETHERTYPE_IP);
+
+ switch (ip_proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPPROTO_SCTP:
+ b1 = gen_portrangeop(port1, port2, ip_proto, dir);
+ break;
+
+ case PROTO_UNDEF:
+ tmp = gen_portrangeop(port1, port2, IPPROTO_TCP, dir);
+ b1 = gen_portrangeop(port1, port2, IPPROTO_UDP, dir);
+ gen_or(tmp, b1);
+ tmp = gen_portrangeop(port1, port2, IPPROTO_SCTP, dir);
+ gen_or(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+ return b1;
+}
+
+#ifdef INET6
+struct block *
+gen_portrangeatom6(off, v1, v2)
+ int off;
+ bpf_int32 v1, v2;
+{
+ struct slist *s1, *s2;
+ struct block *b1, *b2;
+
+ if (v1 > v2) {
+ /*
+ * Reverse the order of the ports, so v1 is the lower one.
+ */
+ bpf_int32 vtemp;
+
+ vtemp = v1;
+ v1 = v2;
+ v2 = vtemp;
+ }
+
+ s1 = new_stmt(BPF_LD|BPF_ABS|BPF_H);
+ s1->s.k = off_nl + 40 + off;
+
+ b1 = new_block(JMP(BPF_JGE));
+ b1->stmts = s1;
+ b1->s.k = v1;
+
+ s2 = new_stmt(BPF_LD|BPF_ABS|BPF_H);
+ s2->s.k = off_nl + 40 + off;
+
+ b2 = new_block(JMP(BPF_JGT));
+ gen_not(b2);
+ b2->stmts = s2;
+ b2->s.k = v2;
+
+ gen_and(b1, b2);
+
+ return b2;
+}
+
+struct block *
+gen_portrangeop6(port1, port2, proto, dir)
+ int port1, port2;
+ int proto;
+ int dir;
+{
+ struct block *b0, *b1, *tmp;
+
+ /* ip6 proto 'proto' */
+ b0 = gen_cmp(off_nl + 6, BPF_B, (bpf_int32)proto);
+
+ switch (dir) {
+ case Q_SRC:
+ b1 = gen_portrangeatom6(0, (bpf_int32)port1, (bpf_int32)port2);
+ break;
+
+ case Q_DST:
+ b1 = gen_portrangeatom6(2, (bpf_int32)port1, (bpf_int32)port2);
+ break;
+
+ case Q_OR:
+ case Q_DEFAULT:
+ tmp = gen_portrangeatom6(0, (bpf_int32)port1, (bpf_int32)port2);
+ b1 = gen_portrangeatom6(2, (bpf_int32)port1, (bpf_int32)port2);
+ gen_or(tmp, b1);
+ break;
+
+ case Q_AND:
+ tmp = gen_portrangeatom6(0, (bpf_int32)port1, (bpf_int32)port2);
+ b1 = gen_portrangeatom6(2, (bpf_int32)port1, (bpf_int32)port2);
+ gen_and(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+
+ return b1;
+}
+
+static struct block *
+gen_portrange6(port1, port2, ip_proto, dir)
+ int port1, port2;
+ int ip_proto;
+ int dir;
+{
+ struct block *b0, *b1, *tmp;
+
+ /* link proto ip6 */
+ b0 = gen_linktype(ETHERTYPE_IPV6);
+
+ switch (ip_proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ case IPPROTO_SCTP:
+ b1 = gen_portrangeop6(port1, port2, ip_proto, dir);
+ break;
+
+ case PROTO_UNDEF:
+ tmp = gen_portrangeop6(port1, port2, IPPROTO_TCP, dir);
+ b1 = gen_portrangeop6(port1, port2, IPPROTO_UDP, dir);
+ gen_or(tmp, b1);
+ tmp = gen_portrangeop6(port1, port2, IPPROTO_SCTP, dir);
+ gen_or(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+ return b1;
+}
+#endif /* INET6 */
+