1*f6e4162fSjsg /* $OpenBSD: gencode.c,v 1.67 2024/09/15 07:14:58 jsg Exp $ */ 2df930be7Sderaadt 3df930be7Sderaadt /* 401efc7efSderaadt * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 5df930be7Sderaadt * The Regents of the University of California. All rights reserved. 6df930be7Sderaadt * 7df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 8df930be7Sderaadt * modification, are permitted provided that: (1) source code distributions 9df930be7Sderaadt * retain the above copyright notice and this paragraph in its entirety, (2) 10df930be7Sderaadt * distributions including binary code include the above copyright notice and 11df930be7Sderaadt * this paragraph in its entirety in the documentation or other materials 12df930be7Sderaadt * provided with the distribution, and (3) all advertising materials mentioning 13df930be7Sderaadt * features or use of this software display the following acknowledgement: 14df930be7Sderaadt * ``This product includes software developed by the University of California, 15df930be7Sderaadt * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16df930be7Sderaadt * the University nor the names of its contributors may be used to endorse 17df930be7Sderaadt * or promote products derived from this software without specific prior 18df930be7Sderaadt * written permission. 19df930be7Sderaadt * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20df930be7Sderaadt * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21df930be7Sderaadt * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22df930be7Sderaadt */ 23df930be7Sderaadt 249b113833Smickey #include <sys/types.h> 25df930be7Sderaadt #include <sys/socket.h> 26df930be7Sderaadt #include <sys/time.h> 27df930be7Sderaadt 28df930be7Sderaadt #include <net/if.h> 29df930be7Sderaadt 30df930be7Sderaadt #include <netinet/in.h> 31df930be7Sderaadt #include <netinet/if_ether.h> 32df930be7Sderaadt 33e83aed87Sfrantzen #include <net/if_pflog.h> 34e83aed87Sfrantzen #include <net/pfvar.h> 35e83aed87Sfrantzen 36ff52dd4aSdenis #include <netmpls/mpls.h> 37ff52dd4aSdenis 38d42a50a0Sreyk #include <net80211/ieee80211.h> 39d42a50a0Sreyk #include <net80211/ieee80211_radiotap.h> 40d42a50a0Sreyk 419b113833Smickey #include <stdlib.h> 42e83aed87Sfrantzen #include <stddef.h> 43df930be7Sderaadt #include <setjmp.h> 44df930be7Sderaadt #include <stdarg.h> 453a9b5ec4Smmcc #include <string.h> 46df930be7Sderaadt 479b113833Smickey #include "pcap-int.h" 489b113833Smickey 4901efc7efSderaadt #include "ethertype.h" 50f562933eSmpf #include "llc.h" 519b113833Smickey #include "gencode.h" 5201efc7efSderaadt #include "ppp.h" 5301efc7efSderaadt #include <pcap-namedb.h> 54a9b0695fSjakob #ifdef INET6 55a9b0695fSjakob #include <netdb.h> 56a9b0695fSjakob #endif /*INET6*/ 579b113833Smickey 5801efc7efSderaadt #ifdef HAVE_OS_PROTO_H 5901efc7efSderaadt #include "os-proto.h" 60df930be7Sderaadt #endif 61df930be7Sderaadt 62df930be7Sderaadt #define JMP(c) ((c)|BPF_JMP|BPF_K) 63df930be7Sderaadt 649b113833Smickey /* Locals */ 65df930be7Sderaadt static jmp_buf top_ctx; 66df930be7Sderaadt static pcap_t *bpf_pcap; 67df930be7Sderaadt 68febc6dcdSdtucker /* Hack for updating VLAN offsets. */ 69febc6dcdSdtucker static u_int orig_linktype = -1, orig_nl = -1, orig_nl_nosnap = -1; 70ff52dd4aSdenis static u_int mpls_stack = 0; 71febc6dcdSdtucker 729b113833Smickey /* XXX */ 739b113833Smickey #ifdef PCAP_FDDIPAD 749b113833Smickey int pcap_fddipad = PCAP_FDDIPAD; 759b113833Smickey #else 769b113833Smickey int pcap_fddipad; 779b113833Smickey #endif 789b113833Smickey 799b113833Smickey __dead void 809b113833Smickey bpf_error(const char *fmt, ...) 81df930be7Sderaadt { 82df930be7Sderaadt va_list ap; 83df930be7Sderaadt 84df930be7Sderaadt va_start(ap, fmt); 85df930be7Sderaadt if (bpf_pcap != NULL) 8613c7aa11Sderaadt (void)vsnprintf(pcap_geterr(bpf_pcap), PCAP_ERRBUF_SIZE, 8713c7aa11Sderaadt fmt, ap); 88df930be7Sderaadt va_end(ap); 89df930be7Sderaadt longjmp(top_ctx, 1); 90df930be7Sderaadt /* NOTREACHED */ 91df930be7Sderaadt } 92df930be7Sderaadt 93df930be7Sderaadt static void init_linktype(int); 94df930be7Sderaadt 95df930be7Sderaadt static int alloc_reg(void); 96df930be7Sderaadt static void free_reg(int); 97df930be7Sderaadt 98df930be7Sderaadt static struct block *root; 99df930be7Sderaadt 1008d8814c2Scanacar /* initialization code used for variable link header */ 1018d8814c2Scanacar static struct slist *init_code = NULL; 1028d8814c2Scanacar 1038d8814c2Scanacar /* Flags and registers for variable link type handling */ 1048d8814c2Scanacar static int variable_nl; 1058d8814c2Scanacar static int nl_reg, iphl_reg; 1068d8814c2Scanacar 107df930be7Sderaadt /* 1086c734e6eSderaadt * Track memory allocations, for bulk freeing at the end 109df930be7Sderaadt */ 1106c734e6eSderaadt #define NMEMBAG 16 1116c734e6eSderaadt #define MEMBAG0SIZE (4096 / sizeof (void *)) 1126c734e6eSderaadt struct membag { 1136c734e6eSderaadt u_int total; 1146c734e6eSderaadt u_int slot; 1156c734e6eSderaadt void **ptrs; /* allocated array[total] to each malloc */ 116df930be7Sderaadt }; 117df930be7Sderaadt 1186c734e6eSderaadt static struct membag membag[NMEMBAG]; 1196c734e6eSderaadt static int cur_membag; 120df930be7Sderaadt 1216c734e6eSderaadt static void *newchunk(size_t); 122df930be7Sderaadt static void freechunks(void); 1238df16311Stholo static __inline struct block *new_block(int); 1248df16311Stholo static __inline struct slist *new_stmt(int); 125df930be7Sderaadt static struct block *gen_retblk(int); 1268df16311Stholo static __inline void syntax(void); 127df930be7Sderaadt 128df930be7Sderaadt static void backpatch(struct block *, struct block *); 129df930be7Sderaadt static void merge(struct block *, struct block *); 1309b113833Smickey static struct block *gen_cmp(u_int, u_int, bpf_int32); 131f562933eSmpf static struct block *gen_cmp_gt(u_int, u_int, bpf_int32); 1328d8814c2Scanacar static struct block *gen_cmp_nl(u_int, u_int, bpf_int32); 1339b113833Smickey static struct block *gen_mcmp(u_int, u_int, bpf_int32, bpf_u_int32); 1348d8814c2Scanacar static struct block *gen_mcmp_nl(u_int, u_int, bpf_int32, bpf_u_int32); 13501efc7efSderaadt static struct block *gen_bcmp(u_int, u_int, const u_char *); 136df930be7Sderaadt static struct block *gen_uncond(int); 1378df16311Stholo static __inline struct block *gen_true(void); 1388df16311Stholo static __inline struct block *gen_false(void); 139df930be7Sderaadt static struct block *gen_linktype(int); 1409b113833Smickey static struct block *gen_hostop(bpf_u_int32, bpf_u_int32, int, int, u_int, u_int); 141a9b0695fSjakob #ifdef INET6 142a9b0695fSjakob static struct block *gen_hostop6(struct in6_addr *, struct in6_addr *, int, int, u_int, u_int); 143a9b0695fSjakob #endif 14401efc7efSderaadt static struct block *gen_ehostop(const u_char *, int); 14501efc7efSderaadt static struct block *gen_fhostop(const u_char *, int); 1469b113833Smickey static struct block *gen_dnhostop(bpf_u_int32, int, u_int); 147d42a50a0Sreyk static struct block *gen_p80211_hostop(const u_char *, int); 148d42a50a0Sreyk static struct block *gen_p80211_addr(int, u_int, const u_char *); 1499b113833Smickey static struct block *gen_host(bpf_u_int32, bpf_u_int32, int, int); 150a9b0695fSjakob #ifdef INET6 151a9b0695fSjakob static struct block *gen_host6(struct in6_addr *, struct in6_addr *, int, int); 152a9b0695fSjakob #endif 153a9b0695fSjakob #ifndef INET6 15401efc7efSderaadt static struct block *gen_gateway(const u_char *, bpf_u_int32 **, int, int); 155a9b0695fSjakob #endif 156df930be7Sderaadt static struct block *gen_ipfrag(void); 1579b113833Smickey static struct block *gen_portatom(int, bpf_int32); 158a9b0695fSjakob #ifdef INET6 159a9b0695fSjakob static struct block *gen_portatom6(int, bpf_int32); 160a9b0695fSjakob #endif 161df930be7Sderaadt struct block *gen_portop(int, int, int); 162df930be7Sderaadt static struct block *gen_port(int, int, int); 163a9b0695fSjakob #ifdef INET6 164a9b0695fSjakob struct block *gen_portop6(int, int, int); 165a9b0695fSjakob static struct block *gen_port6(int, int, int); 166a9b0695fSjakob #endif 16701efc7efSderaadt static int lookup_proto(const char *, int); 168a9b0695fSjakob static struct block *gen_protochain(int, int, int); 169df930be7Sderaadt static struct block *gen_proto(int, int, int); 170df930be7Sderaadt static struct slist *xfer_to_x(struct arth *); 171df930be7Sderaadt static struct slist *xfer_to_a(struct arth *); 172df930be7Sderaadt static struct block *gen_len(int, int); 173df930be7Sderaadt 174df930be7Sderaadt static void * 1756c734e6eSderaadt newchunk(size_t n) 176df930be7Sderaadt { 1776c734e6eSderaadt struct membag *m; 1786c734e6eSderaadt void *p; 179df930be7Sderaadt 1806c734e6eSderaadt m = &membag[cur_membag]; 1816c734e6eSderaadt if (m->total != 0 && m->total - m->slot == 0) { 1826c734e6eSderaadt if (++cur_membag == NMEMBAG) 183df930be7Sderaadt bpf_error("out of memory"); 1846c734e6eSderaadt m = &membag[cur_membag]; 185df930be7Sderaadt } 1866c734e6eSderaadt if (m->total - m->slot == 0) { 1876c734e6eSderaadt m->ptrs = calloc(sizeof (char *), MEMBAG0SIZE << cur_membag); 1886c734e6eSderaadt if (m->ptrs == NULL) 1896c734e6eSderaadt bpf_error("out of memory"); 1906c734e6eSderaadt m->total = MEMBAG0SIZE << cur_membag; 1916c734e6eSderaadt m->slot = 0; 1926c734e6eSderaadt } 1936c734e6eSderaadt 1946c734e6eSderaadt p = calloc(1, n); 1956c734e6eSderaadt if (p == NULL) 1966c734e6eSderaadt bpf_error("out of memory"); 1976c734e6eSderaadt m->ptrs[m->slot++] = p; 1986c734e6eSderaadt return (p); 199df930be7Sderaadt } 200df930be7Sderaadt 201df930be7Sderaadt static void 2026c734e6eSderaadt freechunks(void) 203df930be7Sderaadt { 2046c734e6eSderaadt int i, j; 205df930be7Sderaadt 2066c734e6eSderaadt for (i = 0; i <= cur_membag; i++) { 2070931029aSotto if (membag[i].ptrs == NULL) 2080931029aSotto continue; 209c8ee1a74Sderaadt for (j = 0; j < membag[i].slot; j++) 2106c734e6eSderaadt free(membag[i].ptrs[j]); 2116c734e6eSderaadt free(membag[i].ptrs); 2126c734e6eSderaadt membag[i].ptrs = NULL; 2136c734e6eSderaadt membag[i].slot = membag[i].total = 0; 2149b113833Smickey } 2159aff5a10Sderaadt cur_membag = 0; 216df930be7Sderaadt } 217df930be7Sderaadt 218df930be7Sderaadt /* 219df930be7Sderaadt * A strdup whose allocations are freed after code generation is over. 220df930be7Sderaadt */ 221df930be7Sderaadt char * 22219fef815Sderaadt sdup(const char *s) 223df930be7Sderaadt { 224df930be7Sderaadt int n = strlen(s) + 1; 225df930be7Sderaadt char *cp = newchunk(n); 22601efc7efSderaadt 22701efc7efSderaadt strlcpy(cp, s, n); 228df930be7Sderaadt return (cp); 229df930be7Sderaadt } 230df930be7Sderaadt 2318df16311Stholo static __inline struct block * 23219fef815Sderaadt new_block(int code) 233df930be7Sderaadt { 234df930be7Sderaadt struct block *p; 235df930be7Sderaadt 236df930be7Sderaadt p = (struct block *)newchunk(sizeof(*p)); 237df930be7Sderaadt p->s.code = code; 238df930be7Sderaadt p->head = p; 239df930be7Sderaadt 240df930be7Sderaadt return p; 241df930be7Sderaadt } 242df930be7Sderaadt 2438df16311Stholo static __inline struct slist * 24419fef815Sderaadt new_stmt(int code) 245df930be7Sderaadt { 246df930be7Sderaadt struct slist *p; 247df930be7Sderaadt 248df930be7Sderaadt p = (struct slist *)newchunk(sizeof(*p)); 249df930be7Sderaadt p->s.code = code; 250df930be7Sderaadt 251df930be7Sderaadt return p; 252df930be7Sderaadt } 253df930be7Sderaadt 254df930be7Sderaadt static struct block * 25519fef815Sderaadt gen_retblk(int v) 256df930be7Sderaadt { 257df930be7Sderaadt struct block *b = new_block(BPF_RET|BPF_K); 258df930be7Sderaadt 259df930be7Sderaadt b->s.k = v; 260df930be7Sderaadt return b; 261df930be7Sderaadt } 262df930be7Sderaadt 2638df16311Stholo static __inline void 264146262eaSjsg syntax(void) 265df930be7Sderaadt { 266df930be7Sderaadt bpf_error("syntax error in filter expression"); 267df930be7Sderaadt } 268df930be7Sderaadt 2699b113833Smickey static bpf_u_int32 netmask; 270df930be7Sderaadt static int snaplen; 271a9b0695fSjakob int no_optimize; 272df930be7Sderaadt 273df930be7Sderaadt int 274df930be7Sderaadt pcap_compile(pcap_t *p, struct bpf_program *program, 275aa4ed2b9Ssthen const char *buf, int optimize, bpf_u_int32 mask) 276df930be7Sderaadt { 277df930be7Sderaadt extern int n_errors; 278df930be7Sderaadt int len; 279df930be7Sderaadt 280a9b0695fSjakob no_optimize = 0; 2819b113833Smickey n_errors = 0; 2829b113833Smickey root = NULL; 283df930be7Sderaadt bpf_pcap = p; 2849b113833Smickey if (setjmp(top_ctx)) { 2859b113833Smickey freechunks(); 286df930be7Sderaadt return (-1); 2879b113833Smickey } 288df930be7Sderaadt 289df930be7Sderaadt netmask = mask; 290df930be7Sderaadt snaplen = pcap_snapshot(p); 291df930be7Sderaadt 292df930be7Sderaadt lex_init(buf ? buf : ""); 293df930be7Sderaadt init_linktype(pcap_datalink(p)); 2949b113833Smickey (void)pcap_parse(); 295df930be7Sderaadt 296df930be7Sderaadt if (n_errors) 297df930be7Sderaadt syntax(); 298df930be7Sderaadt 299df930be7Sderaadt if (root == NULL) 300df930be7Sderaadt root = gen_retblk(snaplen); 301df930be7Sderaadt 302a9b0695fSjakob if (optimize && !no_optimize) { 303a9b0695fSjakob bpf_optimize(&root); 304a9b0695fSjakob if (root == NULL || 305a9b0695fSjakob (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0)) 306a9b0695fSjakob bpf_error("expression rejects all packets"); 307a9b0695fSjakob } 308a9b0695fSjakob program->bf_insns = icode_to_fcode(root, &len); 309a9b0695fSjakob program->bf_len = len; 310a9b0695fSjakob 311a9b0695fSjakob freechunks(); 312a9b0695fSjakob return (0); 313a9b0695fSjakob } 314a9b0695fSjakob 315a9b0695fSjakob /* 316a9b0695fSjakob * entry point for using the compiler with no pcap open 317a9b0695fSjakob * pass in all the stuff that is needed explicitly instead. 318a9b0695fSjakob */ 319a9b0695fSjakob int 320a9b0695fSjakob pcap_compile_nopcap(int snaplen_arg, int linktype_arg, 321a9b0695fSjakob struct bpf_program *program, 322aa4ed2b9Ssthen const char *buf, int optimize, bpf_u_int32 mask) 323a9b0695fSjakob { 324a9b0695fSjakob extern int n_errors; 325a9b0695fSjakob int len; 326a9b0695fSjakob 327a9b0695fSjakob n_errors = 0; 328a9b0695fSjakob root = NULL; 329a9b0695fSjakob bpf_pcap = NULL; 330a9b0695fSjakob if (setjmp(top_ctx)) { 331a9b0695fSjakob freechunks(); 332a9b0695fSjakob return (-1); 333a9b0695fSjakob } 334a9b0695fSjakob 335a9b0695fSjakob netmask = mask; 336a9b0695fSjakob 337a9b0695fSjakob /* XXX needed? I don't grok the use of globals here. */ 338a9b0695fSjakob snaplen = snaplen_arg; 339a9b0695fSjakob 340a9b0695fSjakob lex_init(buf ? buf : ""); 341a9b0695fSjakob init_linktype(linktype_arg); 342a9b0695fSjakob (void)pcap_parse(); 343a9b0695fSjakob 344a9b0695fSjakob if (n_errors) 345a9b0695fSjakob syntax(); 346a9b0695fSjakob 347a9b0695fSjakob if (root == NULL) 348a9b0695fSjakob root = gen_retblk(snaplen_arg); 349a9b0695fSjakob 350df930be7Sderaadt if (optimize) { 351df930be7Sderaadt bpf_optimize(&root); 352df930be7Sderaadt if (root == NULL || 353df930be7Sderaadt (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0)) 354df930be7Sderaadt bpf_error("expression rejects all packets"); 355df930be7Sderaadt } 356df930be7Sderaadt program->bf_insns = icode_to_fcode(root, &len); 357df930be7Sderaadt program->bf_len = len; 358df930be7Sderaadt 359df930be7Sderaadt freechunks(); 360df930be7Sderaadt return (0); 361df930be7Sderaadt } 362df930be7Sderaadt 363df930be7Sderaadt /* 36478871eb8Sdugsong * Clean up a "struct bpf_program" by freeing all the memory allocated 36578871eb8Sdugsong * in it. 36678871eb8Sdugsong */ 36778871eb8Sdugsong void 36878871eb8Sdugsong pcap_freecode(struct bpf_program *program) 36978871eb8Sdugsong { 37078871eb8Sdugsong program->bf_len = 0; 37178871eb8Sdugsong if (program->bf_insns != NULL) { 37278871eb8Sdugsong free((char *)program->bf_insns); 37378871eb8Sdugsong program->bf_insns = NULL; 37478871eb8Sdugsong } 37578871eb8Sdugsong } 37678871eb8Sdugsong 37778871eb8Sdugsong /* 378df930be7Sderaadt * Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates 379df930be7Sderaadt * which of the jt and jf fields has been resolved and which is a pointer 380df930be7Sderaadt * back to another unresolved block (or nil). At least one of the fields 381df930be7Sderaadt * in each block is already resolved. 382df930be7Sderaadt */ 383df930be7Sderaadt static void 38419fef815Sderaadt backpatch(struct block *list, struct block *target) 385df930be7Sderaadt { 386df930be7Sderaadt struct block *next; 387df930be7Sderaadt 388df930be7Sderaadt while (list) { 389df930be7Sderaadt if (!list->sense) { 390df930be7Sderaadt next = JT(list); 391df930be7Sderaadt JT(list) = target; 392df930be7Sderaadt } else { 393df930be7Sderaadt next = JF(list); 394df930be7Sderaadt JF(list) = target; 395df930be7Sderaadt } 396df930be7Sderaadt list = next; 397df930be7Sderaadt } 398df930be7Sderaadt } 399df930be7Sderaadt 400df930be7Sderaadt /* 401df930be7Sderaadt * Merge the lists in b0 and b1, using the 'sense' field to indicate 402df930be7Sderaadt * which of jt and jf is the link. 403df930be7Sderaadt */ 404df930be7Sderaadt static void 40519fef815Sderaadt merge(struct block *b0, struct block *b1) 406df930be7Sderaadt { 407d0438536Smmcc struct block **p = &b0; 408df930be7Sderaadt 409df930be7Sderaadt /* Find end of list. */ 410df930be7Sderaadt while (*p) 411df930be7Sderaadt p = !((*p)->sense) ? &JT(*p) : &JF(*p); 412df930be7Sderaadt 413df930be7Sderaadt /* Concatenate the lists. */ 414df930be7Sderaadt *p = b1; 415df930be7Sderaadt } 416df930be7Sderaadt 417df930be7Sderaadt void 41819fef815Sderaadt finish_parse(struct block *p) 419df930be7Sderaadt { 420df930be7Sderaadt backpatch(p, gen_retblk(snaplen)); 421df930be7Sderaadt p->sense = !p->sense; 422df930be7Sderaadt backpatch(p, gen_retblk(0)); 423df930be7Sderaadt root = p->head; 4248d8814c2Scanacar 4258d8814c2Scanacar /* prepend initialization code to root */ 4268d8814c2Scanacar if (init_code != NULL && root != NULL) { 4278d8814c2Scanacar sappend(init_code, root->stmts); 4288d8814c2Scanacar root->stmts = init_code; 4298d8814c2Scanacar init_code = NULL; 4308d8814c2Scanacar } 4318d8814c2Scanacar 4328d8814c2Scanacar if (iphl_reg != -1) { 4338d8814c2Scanacar free_reg(iphl_reg); 4348d8814c2Scanacar iphl_reg = -1; 4358d8814c2Scanacar } 4368d8814c2Scanacar if (nl_reg != -1) { 4378d8814c2Scanacar free_reg(nl_reg); 4388d8814c2Scanacar nl_reg = -1; 4398d8814c2Scanacar } 440df930be7Sderaadt } 441df930be7Sderaadt 442df930be7Sderaadt void 44319fef815Sderaadt gen_and(struct block *b0, struct block *b1) 444df930be7Sderaadt { 445df930be7Sderaadt backpatch(b0, b1->head); 446df930be7Sderaadt b0->sense = !b0->sense; 447df930be7Sderaadt b1->sense = !b1->sense; 448df930be7Sderaadt merge(b1, b0); 449df930be7Sderaadt b1->sense = !b1->sense; 450df930be7Sderaadt b1->head = b0->head; 451df930be7Sderaadt } 452df930be7Sderaadt 453df930be7Sderaadt void 45419fef815Sderaadt gen_or(struct block *b0, struct block *b1) 455df930be7Sderaadt { 456df930be7Sderaadt b0->sense = !b0->sense; 457df930be7Sderaadt backpatch(b0, b1->head); 458df930be7Sderaadt b0->sense = !b0->sense; 459df930be7Sderaadt merge(b1, b0); 460df930be7Sderaadt b1->head = b0->head; 461df930be7Sderaadt } 462df930be7Sderaadt 463df930be7Sderaadt void 46419fef815Sderaadt gen_not(struct block *b) 465df930be7Sderaadt { 466df930be7Sderaadt b->sense = !b->sense; 467df930be7Sderaadt } 468df930be7Sderaadt 469df930be7Sderaadt static struct block * 47019fef815Sderaadt gen_cmp(u_int offset, u_int size, bpf_int32 v) 471df930be7Sderaadt { 472df930be7Sderaadt struct slist *s; 473df930be7Sderaadt struct block *b; 474df930be7Sderaadt 475df930be7Sderaadt s = new_stmt(BPF_LD|BPF_ABS|size); 476df930be7Sderaadt s->s.k = offset; 477df930be7Sderaadt 478df930be7Sderaadt b = new_block(JMP(BPF_JEQ)); 479df930be7Sderaadt b->stmts = s; 480df930be7Sderaadt b->s.k = v; 481df930be7Sderaadt 482df930be7Sderaadt return b; 483df930be7Sderaadt } 484df930be7Sderaadt 485df930be7Sderaadt static struct block * 48619fef815Sderaadt gen_cmp_gt(u_int offset, u_int size, bpf_int32 v) 487f562933eSmpf { 488f562933eSmpf struct slist *s; 489f562933eSmpf struct block *b; 490f562933eSmpf 491f562933eSmpf s = new_stmt(BPF_LD|BPF_ABS|size); 492f562933eSmpf s->s.k = offset; 493f562933eSmpf 494f562933eSmpf b = new_block(JMP(BPF_JGT)); 495f562933eSmpf b->stmts = s; 496f562933eSmpf b->s.k = v; 497f562933eSmpf 498f562933eSmpf return b; 499f562933eSmpf } 500f562933eSmpf 501f562933eSmpf static struct block * 50219fef815Sderaadt gen_mcmp(u_int offset, u_int size, bpf_int32 v, bpf_u_int32 mask) 503df930be7Sderaadt { 504df930be7Sderaadt struct block *b = gen_cmp(offset, size, v); 505df930be7Sderaadt struct slist *s; 506df930be7Sderaadt 507df930be7Sderaadt if (mask != 0xffffffff) { 508df930be7Sderaadt s = new_stmt(BPF_ALU|BPF_AND|BPF_K); 509df930be7Sderaadt s->s.k = mask; 510d89ea119Skrw sappend(b->stmts, s); 511df930be7Sderaadt } 512df930be7Sderaadt return b; 513df930be7Sderaadt } 514df930be7Sderaadt 5158d8814c2Scanacar /* Like gen_mcmp with 'dynamic off_nl' added to the offset */ 5168d8814c2Scanacar static struct block * 51719fef815Sderaadt gen_mcmp_nl(u_int offset, u_int size, bpf_int32 v, bpf_u_int32 mask) 5188d8814c2Scanacar { 5198d8814c2Scanacar struct block *b = gen_cmp_nl(offset, size, v); 5208d8814c2Scanacar struct slist *s; 5218d8814c2Scanacar 5228d8814c2Scanacar if (mask != 0xffffffff) { 5238d8814c2Scanacar s = new_stmt(BPF_ALU|BPF_AND|BPF_K); 5248d8814c2Scanacar s->s.k = mask; 525d89ea119Skrw sappend(b->stmts, s); 5268d8814c2Scanacar } 5278d8814c2Scanacar return b; 5288d8814c2Scanacar } 5298d8814c2Scanacar 530df930be7Sderaadt static struct block * 53119fef815Sderaadt gen_bcmp(u_int offset, u_int size, const u_char *v) 532df930be7Sderaadt { 533d0438536Smmcc struct block *b, *tmp; 534df930be7Sderaadt 535df930be7Sderaadt b = NULL; 536df930be7Sderaadt while (size >= 4) { 537d0438536Smmcc const u_char *p = &v[size - 4]; 53801efc7efSderaadt bpf_int32 w = ((bpf_int32)p[0] << 24) | 53901efc7efSderaadt ((bpf_int32)p[1] << 16) | ((bpf_int32)p[2] << 8) | p[3]; 54001efc7efSderaadt 541df930be7Sderaadt tmp = gen_cmp(offset + size - 4, BPF_W, w); 542df930be7Sderaadt if (b != NULL) 543df930be7Sderaadt gen_and(b, tmp); 544df930be7Sderaadt b = tmp; 545df930be7Sderaadt size -= 4; 546df930be7Sderaadt } 547df930be7Sderaadt while (size >= 2) { 548d0438536Smmcc const u_char *p = &v[size - 2]; 54901efc7efSderaadt bpf_int32 w = ((bpf_int32)p[0] << 8) | p[1]; 55001efc7efSderaadt 551df930be7Sderaadt tmp = gen_cmp(offset + size - 2, BPF_H, w); 552df930be7Sderaadt if (b != NULL) 553df930be7Sderaadt gen_and(b, tmp); 554df930be7Sderaadt b = tmp; 555df930be7Sderaadt size -= 2; 556df930be7Sderaadt } 557df930be7Sderaadt if (size > 0) { 5589b113833Smickey tmp = gen_cmp(offset, BPF_B, (bpf_int32)v[0]); 559df930be7Sderaadt if (b != NULL) 560df930be7Sderaadt gen_and(b, tmp); 561df930be7Sderaadt b = tmp; 562df930be7Sderaadt } 563df930be7Sderaadt return b; 564df930be7Sderaadt } 565df930be7Sderaadt 566df930be7Sderaadt /* 567df930be7Sderaadt * Various code constructs need to know the layout of the data link 568df930be7Sderaadt * layer. These variables give the necessary offsets. off_linktype 569df930be7Sderaadt * is set to -1 for no encapsulation, in which case, IP is assumed. 570df930be7Sderaadt */ 571df930be7Sderaadt static u_int off_linktype; 572df930be7Sderaadt static u_int off_nl; 573febc6dcdSdtucker static u_int off_nl_nosnap; 574febc6dcdSdtucker 575df930be7Sderaadt static int linktype; 576df930be7Sderaadt 5778d8814c2Scanacar /* Generate code to load the dynamic 'off_nl' to the X register */ 5788d8814c2Scanacar static struct slist * 5798d8814c2Scanacar nl2X_stmt(void) 5808d8814c2Scanacar { 5818d8814c2Scanacar struct slist *s, *tmp; 5828d8814c2Scanacar 5838d8814c2Scanacar if (nl_reg == -1) { 5848d8814c2Scanacar switch (linktype) { 5858d8814c2Scanacar case DLT_PFLOG: 5868d8814c2Scanacar /* The pflog header contains PFLOG_REAL_HDRLEN 5878d8814c2Scanacar which does NOT include the padding. Round 5888d8814c2Scanacar up to the nearest dword boundary */ 5898d8814c2Scanacar s = new_stmt(BPF_LD|BPF_B|BPF_ABS); 5908d8814c2Scanacar s->s.k = 0; 5918d8814c2Scanacar 5928d8814c2Scanacar tmp = new_stmt(BPF_ALU|BPF_ADD|BPF_K); 5938d8814c2Scanacar tmp->s.k = 3; 5948d8814c2Scanacar sappend(s, tmp); 5958d8814c2Scanacar 5968d8814c2Scanacar tmp = new_stmt(BPF_ALU|BPF_AND|BPF_K); 597c266690cScanacar tmp->s.k = 0xfc; 5988d8814c2Scanacar sappend(s, tmp); 5998d8814c2Scanacar 6008d8814c2Scanacar nl_reg = alloc_reg(); 6018d8814c2Scanacar tmp = new_stmt(BPF_ST); 6028d8814c2Scanacar tmp->s.k = nl_reg; 6038d8814c2Scanacar sappend(s, tmp); 6048d8814c2Scanacar 6058d8814c2Scanacar break; 6068d8814c2Scanacar default: 6078d8814c2Scanacar bpf_error("Unknown header size for link type 0x%x", 6088d8814c2Scanacar linktype); 6098d8814c2Scanacar } 6108d8814c2Scanacar 6118d8814c2Scanacar if (init_code == NULL) 6128d8814c2Scanacar init_code = s; 6138d8814c2Scanacar else 6148d8814c2Scanacar sappend(init_code, s); 6158d8814c2Scanacar } 6168d8814c2Scanacar 6178d8814c2Scanacar s = new_stmt(BPF_LDX|BPF_MEM); 6188d8814c2Scanacar s->s.k = nl_reg; 6198d8814c2Scanacar 6208d8814c2Scanacar return s; 6218d8814c2Scanacar } 6228d8814c2Scanacar 6238d8814c2Scanacar /* Like gen_cmp but adds the dynamic 'off_nl' to the offset */ 6248d8814c2Scanacar static struct block * 62519fef815Sderaadt gen_cmp_nl(u_int offset, u_int size, bpf_int32 v) 6268d8814c2Scanacar { 6278d8814c2Scanacar struct slist *s, *tmp; 6288d8814c2Scanacar struct block *b; 6298d8814c2Scanacar 6308d8814c2Scanacar if (variable_nl) { 6318d8814c2Scanacar s = nl2X_stmt(); 6328d8814c2Scanacar tmp = new_stmt(BPF_LD|BPF_IND|size); 6338d8814c2Scanacar tmp->s.k = offset; 6348d8814c2Scanacar sappend(s, tmp); 6358d8814c2Scanacar } else { 6368d8814c2Scanacar s = new_stmt(BPF_LD|BPF_ABS|size); 6378d8814c2Scanacar s->s.k = offset + off_nl; 6388d8814c2Scanacar } 6398d8814c2Scanacar b = new_block(JMP(BPF_JEQ)); 6408d8814c2Scanacar b->stmts = s; 6418d8814c2Scanacar b->s.k = v; 6428d8814c2Scanacar 6438d8814c2Scanacar return b; 6448d8814c2Scanacar } 6458d8814c2Scanacar 646df930be7Sderaadt static void 64719fef815Sderaadt init_linktype(int type) 648df930be7Sderaadt { 649df930be7Sderaadt linktype = type; 6508d8814c2Scanacar init_code = NULL; 6518d8814c2Scanacar nl_reg = iphl_reg = -1; 652df930be7Sderaadt 653df930be7Sderaadt switch (type) { 654df930be7Sderaadt 655df930be7Sderaadt case DLT_EN10MB: 656df930be7Sderaadt off_linktype = 12; 657df930be7Sderaadt off_nl = 14; 658df930be7Sderaadt return; 659df930be7Sderaadt 660df930be7Sderaadt case DLT_SLIP: 661df930be7Sderaadt /* 662df930be7Sderaadt * SLIP doesn't have a link level type. The 16 byte 663df930be7Sderaadt * header is hacked into our SLIP driver. 664df930be7Sderaadt */ 665df930be7Sderaadt off_linktype = -1; 666df930be7Sderaadt off_nl = 16; 667df930be7Sderaadt return; 668df930be7Sderaadt 66901efc7efSderaadt case DLT_SLIP_BSDOS: 67001efc7efSderaadt /* XXX this may be the same as the DLT_PPP_BSDOS case */ 67101efc7efSderaadt off_linktype = -1; 67201efc7efSderaadt /* XXX end */ 67301efc7efSderaadt off_nl = 24; 67401efc7efSderaadt return; 67501efc7efSderaadt 676df930be7Sderaadt case DLT_NULL: 67701efc7efSderaadt off_linktype = 0; 678c164a838Sderaadt off_nl = 4; 679c164a838Sderaadt return; 680c164a838Sderaadt 681df930be7Sderaadt case DLT_PPP: 682df930be7Sderaadt off_linktype = 2; 683df930be7Sderaadt off_nl = 4; 684df930be7Sderaadt return; 685df930be7Sderaadt 6862524a2d3Sdlg case DLT_PPP_SERIAL: 6872524a2d3Sdlg off_linktype = -1; 6882524a2d3Sdlg off_nl = 2; 6892524a2d3Sdlg return; 6902524a2d3Sdlg 691477f9f21Sbrad case DLT_PPP_ETHER: 692477f9f21Sbrad /* 693477f9f21Sbrad * This does not include the Ethernet header, and 694477f9f21Sbrad * only covers session state. 695477f9f21Sbrad */ 696477f9f21Sbrad off_linktype = 6; 697477f9f21Sbrad off_nl = 8; 698477f9f21Sbrad return; 699477f9f21Sbrad 70001efc7efSderaadt case DLT_PPP_BSDOS: 70101efc7efSderaadt off_linktype = 5; 70201efc7efSderaadt off_nl = 24; 70301efc7efSderaadt return; 70401efc7efSderaadt 705df930be7Sderaadt case DLT_FDDI: 706df930be7Sderaadt /* 707df930be7Sderaadt * FDDI doesn't really have a link-level type field. 708df930be7Sderaadt * We assume that SSAP = SNAP is being used and pick 709df930be7Sderaadt * out the encapsulated Ethernet type. 710df930be7Sderaadt */ 7119b113833Smickey off_linktype = 19; 7129b113833Smickey #ifdef PCAP_FDDIPAD 7139b113833Smickey off_linktype += pcap_fddipad; 714df930be7Sderaadt #endif 7159b113833Smickey off_nl = 21; 7169b113833Smickey #ifdef PCAP_FDDIPAD 7179b113833Smickey off_nl += pcap_fddipad; 7189b113833Smickey #endif 7199b113833Smickey return; 720df930be7Sderaadt 721df930be7Sderaadt case DLT_IEEE802: 722df930be7Sderaadt off_linktype = 20; 723df930be7Sderaadt off_nl = 22; 724df930be7Sderaadt return; 7259b113833Smickey 72692f41fdeSfgsch case DLT_IEEE802_11: 72792f41fdeSfgsch off_linktype = 30; /* XXX variable */ 72892f41fdeSfgsch off_nl = 32; 72992f41fdeSfgsch return; 73092f41fdeSfgsch 731d42a50a0Sreyk case DLT_IEEE802_11_RADIO: /* XXX variable */ 732d42a50a0Sreyk off_linktype = 30 + IEEE80211_RADIOTAP_HDRLEN; 733d42a50a0Sreyk off_nl = 32 + IEEE80211_RADIOTAP_HDRLEN; 734a97876cfSreyk return; 735a97876cfSreyk 7369b113833Smickey case DLT_ATM_RFC1483: 7379b113833Smickey /* 7389b113833Smickey * assume routed, non-ISO PDUs 7399b113833Smickey * (i.e., LLC = 0xAA-AA-03, OUT = 0x00-00-00) 7409b113833Smickey */ 7419b113833Smickey off_linktype = 6; 7429b113833Smickey off_nl = 8; 7439b113833Smickey return; 74401efc7efSderaadt 74501efc7efSderaadt case DLT_LOOP: 7460918526aSdlg off_linktype = 0; 74701efc7efSderaadt off_nl = 4; 74801efc7efSderaadt return; 74901efc7efSderaadt 75001efc7efSderaadt case DLT_ENC: 75101efc7efSderaadt off_linktype = -1; 75201efc7efSderaadt off_nl = 12; 75301efc7efSderaadt return; 75401efc7efSderaadt 755263bcd0cScanacar case DLT_PFLOG: 756263bcd0cScanacar off_linktype = 0; 7578d8814c2Scanacar variable_nl = 1; 7588d8814c2Scanacar off_nl = 0; 759263bcd0cScanacar return; 760263bcd0cScanacar 76131f5fcb8Smickey case DLT_PFSYNC: 76231f5fcb8Smickey off_linktype = -1; 76331f5fcb8Smickey off_nl = 4; 76431f5fcb8Smickey return; 76531f5fcb8Smickey 7667a61d4b0Sreyk case DLT_OPENFLOW: 7677a61d4b0Sreyk off_linktype = -1; 7688167ef46Sreyk off_nl = 12; 7697a61d4b0Sreyk return; 7707a61d4b0Sreyk 771d00b8992Smpi case DLT_USBPCAP: 772d00b8992Smpi /* FALLTHROUGH */ 77301efc7efSderaadt case DLT_RAW: 77401efc7efSderaadt off_linktype = -1; 77501efc7efSderaadt off_nl = 0; 77601efc7efSderaadt return; 777df930be7Sderaadt } 778df930be7Sderaadt bpf_error("unknown data link type 0x%x", linktype); 779df930be7Sderaadt /* NOTREACHED */ 780df930be7Sderaadt } 781df930be7Sderaadt 782df930be7Sderaadt static struct block * 78319fef815Sderaadt gen_uncond(int rsense) 784df930be7Sderaadt { 785df930be7Sderaadt struct block *b; 786df930be7Sderaadt struct slist *s; 787df930be7Sderaadt 788df930be7Sderaadt s = new_stmt(BPF_LD|BPF_IMM); 789df930be7Sderaadt s->s.k = !rsense; 790df930be7Sderaadt b = new_block(JMP(BPF_JEQ)); 791df930be7Sderaadt b->stmts = s; 792df930be7Sderaadt 793df930be7Sderaadt return b; 794df930be7Sderaadt } 795df930be7Sderaadt 7968df16311Stholo static __inline struct block * 797146262eaSjsg gen_true(void) 798df930be7Sderaadt { 799df930be7Sderaadt return gen_uncond(1); 800df930be7Sderaadt } 801df930be7Sderaadt 8028df16311Stholo static __inline struct block * 803146262eaSjsg gen_false(void) 804df930be7Sderaadt { 805df930be7Sderaadt return gen_uncond(0); 806df930be7Sderaadt } 807df930be7Sderaadt 808df930be7Sderaadt static struct block * 80919fef815Sderaadt gen_linktype(int proto) 810df930be7Sderaadt { 81101efc7efSderaadt struct block *b0, *b1; 81201efc7efSderaadt 81301efc7efSderaadt /* If we're not using encapsulation and checking for IP, we're done */ 814ff52dd4aSdenis if ((off_linktype == -1 || mpls_stack > 0) && proto == ETHERTYPE_IP) 815df930be7Sderaadt return gen_true(); 816a9b0695fSjakob #ifdef INET6 817a9b0695fSjakob /* this isn't the right thing to do, but sometimes necessary */ 818ff52dd4aSdenis if ((off_linktype == -1 || mpls_stack > 0) && proto == ETHERTYPE_IPV6) 819a9b0695fSjakob return gen_true(); 820a9b0695fSjakob #endif 82101efc7efSderaadt 82201efc7efSderaadt switch (linktype) { 82301efc7efSderaadt 824f562933eSmpf case DLT_EN10MB: 825f562933eSmpf if (proto <= ETHERMTU) { 826f562933eSmpf /* This is an LLC SAP value */ 827f562933eSmpf b0 = gen_cmp_gt(off_linktype, BPF_H, ETHERMTU); 828f562933eSmpf gen_not(b0); 829f562933eSmpf b1 = gen_cmp(off_linktype + 2, BPF_B, (bpf_int32)proto); 830f562933eSmpf gen_and(b0, b1); 831f562933eSmpf return b1; 832f562933eSmpf } else { 833f562933eSmpf /* This is an Ethernet type */ 834f562933eSmpf return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto); 835f562933eSmpf } 836f562933eSmpf break; 837f562933eSmpf 83801efc7efSderaadt case DLT_SLIP: 839df930be7Sderaadt return gen_false(); 840df930be7Sderaadt 841df930be7Sderaadt case DLT_PPP: 842477f9f21Sbrad case DLT_PPP_ETHER: 843df930be7Sderaadt if (proto == ETHERTYPE_IP) 84401efc7efSderaadt proto = PPP_IP; /* XXX was 0x21 */ 845a9b0695fSjakob #ifdef INET6 846a9b0695fSjakob else if (proto == ETHERTYPE_IPV6) 847a9b0695fSjakob proto = PPP_IPV6; 848a9b0695fSjakob #endif 84901efc7efSderaadt break; 85001efc7efSderaadt 85101efc7efSderaadt case DLT_PPP_BSDOS: 85201efc7efSderaadt switch (proto) { 85301efc7efSderaadt 85401efc7efSderaadt case ETHERTYPE_IP: 85501efc7efSderaadt b0 = gen_cmp(off_linktype, BPF_H, PPP_IP); 85601efc7efSderaadt b1 = gen_cmp(off_linktype, BPF_H, PPP_VJC); 85701efc7efSderaadt gen_or(b0, b1); 85801efc7efSderaadt b0 = gen_cmp(off_linktype, BPF_H, PPP_VJNC); 85901efc7efSderaadt gen_or(b1, b0); 86001efc7efSderaadt return b0; 86101efc7efSderaadt 862a9b0695fSjakob #ifdef INET6 863a9b0695fSjakob case ETHERTYPE_IPV6: 864a9b0695fSjakob proto = PPP_IPV6; 865a9b0695fSjakob /* more to go? */ 866a9b0695fSjakob break; 867a9b0695fSjakob #endif /* INET6 */ 868a9b0695fSjakob 86901efc7efSderaadt case ETHERTYPE_DN: 87001efc7efSderaadt proto = PPP_DECNET; 87101efc7efSderaadt break; 87201efc7efSderaadt 87301efc7efSderaadt case ETHERTYPE_ATALK: 87401efc7efSderaadt proto = PPP_APPLE; 87501efc7efSderaadt break; 87601efc7efSderaadt 87701efc7efSderaadt case ETHERTYPE_NS: 87801efc7efSderaadt proto = PPP_NS; 87901efc7efSderaadt break; 88001efc7efSderaadt } 881df930be7Sderaadt break; 8829b113833Smickey 883c164a838Sderaadt case DLT_LOOP: 8844c52d65cSderaadt case DLT_ENC: 8859b113833Smickey case DLT_NULL: 886fe3e795bSkn { 887fe3e795bSkn int v; 888fe3e795bSkn 8899b113833Smickey if (proto == ETHERTYPE_IP) 890fe3e795bSkn v = AF_INET; 891a9b0695fSjakob #ifdef INET6 892a9b0695fSjakob else if (proto == ETHERTYPE_IPV6) 893fe3e795bSkn v = AF_INET6; 894a9b0695fSjakob #endif /* INET6 */ 8959b113833Smickey else 8969b113833Smickey return gen_false(); 897fe3e795bSkn 898fe3e795bSkn /* 899fe3e795bSkn * For DLT_NULL, the link-layer header is a 32-bit word 900fe3e795bSkn * containing an AF_ value in *host* byte order, and for 901fe3e795bSkn * DLT_ENC, the link-layer header begins with a 32-bit 902fe3e795bSkn * word containing an AF_ value in host byte order. 903fe3e795bSkn * 904fe3e795bSkn * For DLT_LOOP, the link-layer header is a 32-bit 905fe3e795bSkn * word containing an AF_ value in *network* byte order. 906fe3e795bSkn */ 907fe3e795bSkn if (linktype != DLT_LOOP) 908fe3e795bSkn v = htonl(v); 909fe3e795bSkn 910fe3e795bSkn return (gen_cmp(0, BPF_W, (bpf_int32)v)); 911a9b0695fSjakob break; 912fe3e795bSkn } 913263bcd0cScanacar case DLT_PFLOG: 914263bcd0cScanacar if (proto == ETHERTYPE_IP) 915263bcd0cScanacar return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B, 916263bcd0cScanacar (bpf_int32)AF_INET)); 917263bcd0cScanacar #ifdef INET6 918263bcd0cScanacar else if (proto == ETHERTYPE_IPV6) 919263bcd0cScanacar return (gen_cmp(offsetof(struct pfloghdr, af), BPF_B, 920263bcd0cScanacar (bpf_int32)AF_INET6)); 921263bcd0cScanacar #endif /* INET6 */ 922263bcd0cScanacar else 923263bcd0cScanacar return gen_false(); 924263bcd0cScanacar break; 925263bcd0cScanacar 926df930be7Sderaadt } 9279b113833Smickey return gen_cmp(off_linktype, BPF_H, (bpf_int32)proto); 928df930be7Sderaadt } 929df930be7Sderaadt 930df930be7Sderaadt static struct block * 93119fef815Sderaadt gen_hostop(bpf_u_int32 addr, bpf_u_int32 mask, int dir, int proto, 93219fef815Sderaadt u_int src_off, u_int dst_off) 933df930be7Sderaadt { 934df930be7Sderaadt struct block *b0, *b1; 935df930be7Sderaadt u_int offset; 936df930be7Sderaadt 937df930be7Sderaadt switch (dir) { 938df930be7Sderaadt 939df930be7Sderaadt case Q_SRC: 940df930be7Sderaadt offset = src_off; 941df930be7Sderaadt break; 942df930be7Sderaadt 943df930be7Sderaadt case Q_DST: 944df930be7Sderaadt offset = dst_off; 945df930be7Sderaadt break; 946df930be7Sderaadt 947df930be7Sderaadt case Q_AND: 948df930be7Sderaadt b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off); 949df930be7Sderaadt b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off); 950df930be7Sderaadt gen_and(b0, b1); 951df930be7Sderaadt return b1; 952df930be7Sderaadt 953df930be7Sderaadt case Q_OR: 954df930be7Sderaadt case Q_DEFAULT: 955df930be7Sderaadt b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off); 956df930be7Sderaadt b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off); 957df930be7Sderaadt gen_or(b0, b1); 958df930be7Sderaadt return b1; 959df930be7Sderaadt 960df930be7Sderaadt default: 961d42a50a0Sreyk bpf_error("direction not supported on linktype 0x%x", 962d42a50a0Sreyk linktype); 963df930be7Sderaadt } 964df930be7Sderaadt b0 = gen_linktype(proto); 9658d8814c2Scanacar b1 = gen_mcmp_nl(offset, BPF_W, (bpf_int32)addr, mask); 966df930be7Sderaadt gen_and(b0, b1); 967df930be7Sderaadt return b1; 968df930be7Sderaadt } 969df930be7Sderaadt 970a9b0695fSjakob #ifdef INET6 971a9b0695fSjakob static struct block * 97219fef815Sderaadt gen_hostop6(struct in6_addr *addr, struct in6_addr *mask, int dir, int proto, 97319fef815Sderaadt u_int src_off, u_int dst_off) 974a9b0695fSjakob { 975a9b0695fSjakob struct block *b0, *b1; 976a9b0695fSjakob u_int offset; 977a9b0695fSjakob u_int32_t *a, *m; 978a9b0695fSjakob 979a9b0695fSjakob switch (dir) { 980a9b0695fSjakob 981a9b0695fSjakob case Q_SRC: 982a9b0695fSjakob offset = src_off; 983a9b0695fSjakob break; 984a9b0695fSjakob 985a9b0695fSjakob case Q_DST: 986a9b0695fSjakob offset = dst_off; 987a9b0695fSjakob break; 988a9b0695fSjakob 989a9b0695fSjakob case Q_AND: 990a9b0695fSjakob b0 = gen_hostop6(addr, mask, Q_SRC, proto, src_off, dst_off); 991a9b0695fSjakob b1 = gen_hostop6(addr, mask, Q_DST, proto, src_off, dst_off); 992a9b0695fSjakob gen_and(b0, b1); 993a9b0695fSjakob return b1; 994a9b0695fSjakob 995a9b0695fSjakob case Q_OR: 996a9b0695fSjakob case Q_DEFAULT: 997a9b0695fSjakob b0 = gen_hostop6(addr, mask, Q_SRC, proto, src_off, dst_off); 998a9b0695fSjakob b1 = gen_hostop6(addr, mask, Q_DST, proto, src_off, dst_off); 999a9b0695fSjakob gen_or(b0, b1); 1000a9b0695fSjakob return b1; 1001a9b0695fSjakob 1002a9b0695fSjakob default: 1003d42a50a0Sreyk bpf_error("direction not supported on linktype 0x%x", 1004d42a50a0Sreyk linktype); 1005a9b0695fSjakob } 1006a9b0695fSjakob /* this order is important */ 1007a9b0695fSjakob a = (u_int32_t *)addr; 1008a9b0695fSjakob m = (u_int32_t *)mask; 10098d8814c2Scanacar b1 = gen_mcmp_nl(offset + 12, BPF_W, ntohl(a[3]), ntohl(m[3])); 10108d8814c2Scanacar b0 = gen_mcmp_nl(offset + 8, BPF_W, ntohl(a[2]), ntohl(m[2])); 1011a9b0695fSjakob gen_and(b0, b1); 10128d8814c2Scanacar b0 = gen_mcmp_nl(offset + 4, BPF_W, ntohl(a[1]), ntohl(m[1])); 1013a9b0695fSjakob gen_and(b0, b1); 10148d8814c2Scanacar b0 = gen_mcmp_nl(offset + 0, BPF_W, ntohl(a[0]), ntohl(m[0])); 1015a9b0695fSjakob gen_and(b0, b1); 1016a9b0695fSjakob b0 = gen_linktype(proto); 1017a9b0695fSjakob gen_and(b0, b1); 1018a9b0695fSjakob return b1; 1019a9b0695fSjakob } 1020a9b0695fSjakob #endif /*INET6*/ 1021a9b0695fSjakob 1022df930be7Sderaadt static struct block * 102319fef815Sderaadt gen_ehostop(const u_char *eaddr, int dir) 1024df930be7Sderaadt { 1025a9b0695fSjakob struct block *b0, *b1; 1026df930be7Sderaadt 1027df930be7Sderaadt switch (dir) { 1028df930be7Sderaadt case Q_SRC: 1029df930be7Sderaadt return gen_bcmp(6, 6, eaddr); 1030df930be7Sderaadt 1031df930be7Sderaadt case Q_DST: 1032df930be7Sderaadt return gen_bcmp(0, 6, eaddr); 1033df930be7Sderaadt 1034df930be7Sderaadt case Q_AND: 1035df930be7Sderaadt b0 = gen_ehostop(eaddr, Q_SRC); 1036df930be7Sderaadt b1 = gen_ehostop(eaddr, Q_DST); 1037df930be7Sderaadt gen_and(b0, b1); 1038df930be7Sderaadt return b1; 1039df930be7Sderaadt 1040df930be7Sderaadt case Q_DEFAULT: 1041df930be7Sderaadt case Q_OR: 1042df930be7Sderaadt b0 = gen_ehostop(eaddr, Q_SRC); 1043df930be7Sderaadt b1 = gen_ehostop(eaddr, Q_DST); 1044df930be7Sderaadt gen_or(b0, b1); 1045df930be7Sderaadt return b1; 1046d42a50a0Sreyk default: 1047d42a50a0Sreyk bpf_error("direction not supported on linktype 0x%x", 1048d42a50a0Sreyk linktype); 1049df930be7Sderaadt } 1050df930be7Sderaadt /* NOTREACHED */ 1051df930be7Sderaadt } 1052df930be7Sderaadt 1053df930be7Sderaadt /* 1054df930be7Sderaadt * Like gen_ehostop, but for DLT_FDDI 1055df930be7Sderaadt */ 1056df930be7Sderaadt static struct block * 105719fef815Sderaadt gen_fhostop(const u_char *eaddr, int dir) 1058df930be7Sderaadt { 1059df930be7Sderaadt struct block *b0, *b1; 1060df930be7Sderaadt 1061df930be7Sderaadt switch (dir) { 1062df930be7Sderaadt case Q_SRC: 10639b113833Smickey #ifdef PCAP_FDDIPAD 10649b113833Smickey return gen_bcmp(6 + 1 + pcap_fddipad, 6, eaddr); 10659b113833Smickey #else 10669b113833Smickey return gen_bcmp(6 + 1, 6, eaddr); 10679b113833Smickey #endif 1068df930be7Sderaadt 1069df930be7Sderaadt case Q_DST: 10709b113833Smickey #ifdef PCAP_FDDIPAD 10719b113833Smickey return gen_bcmp(0 + 1 + pcap_fddipad, 6, eaddr); 10729b113833Smickey #else 10739b113833Smickey return gen_bcmp(0 + 1, 6, eaddr); 10749b113833Smickey #endif 1075df930be7Sderaadt 1076df930be7Sderaadt case Q_AND: 1077df930be7Sderaadt b0 = gen_fhostop(eaddr, Q_SRC); 1078df930be7Sderaadt b1 = gen_fhostop(eaddr, Q_DST); 1079df930be7Sderaadt gen_and(b0, b1); 1080df930be7Sderaadt return b1; 1081df930be7Sderaadt 1082df930be7Sderaadt case Q_DEFAULT: 1083df930be7Sderaadt case Q_OR: 1084df930be7Sderaadt b0 = gen_fhostop(eaddr, Q_SRC); 1085df930be7Sderaadt b1 = gen_fhostop(eaddr, Q_DST); 1086df930be7Sderaadt gen_or(b0, b1); 1087df930be7Sderaadt return b1; 1088d42a50a0Sreyk default: 1089d42a50a0Sreyk bpf_error("direction not supported on linktype 0x%x", 1090d42a50a0Sreyk linktype); 1091df930be7Sderaadt } 1092df930be7Sderaadt /* NOTREACHED */ 1093df930be7Sderaadt } 1094df930be7Sderaadt 1095df930be7Sderaadt /* 1096df930be7Sderaadt * This is quite tricky because there may be pad bytes in front of the 1097df930be7Sderaadt * DECNET header, and then there are two possible data packet formats that 1098df930be7Sderaadt * carry both src and dst addresses, plus 5 packet types in a format that 1099df930be7Sderaadt * carries only the src node, plus 2 types that use a different format and 1100df930be7Sderaadt * also carry just the src node. 1101df930be7Sderaadt * 1102df930be7Sderaadt * Yuck. 1103df930be7Sderaadt * 1104df930be7Sderaadt * Instead of doing those all right, we just look for data packets with 1105df930be7Sderaadt * 0 or 1 bytes of padding. If you want to look at other packets, that 1106df930be7Sderaadt * will require a lot more hacking. 1107df930be7Sderaadt * 1108df930be7Sderaadt * To add support for filtering on DECNET "areas" (network numbers) 1109df930be7Sderaadt * one would want to add a "mask" argument to this routine. That would 1110df930be7Sderaadt * make the filter even more inefficient, although one could be clever 1111df930be7Sderaadt * and not generate masking instructions if the mask is 0xFFFF. 1112df930be7Sderaadt */ 1113df930be7Sderaadt static struct block * 111419fef815Sderaadt gen_dnhostop(bpf_u_int32 addr, int dir, u_int base_off) 1115df930be7Sderaadt { 1116df930be7Sderaadt struct block *b0, *b1, *b2, *tmp; 1117df930be7Sderaadt u_int offset_lh; /* offset if long header is received */ 1118df930be7Sderaadt u_int offset_sh; /* offset if short header is received */ 1119df930be7Sderaadt 1120df930be7Sderaadt switch (dir) { 1121df930be7Sderaadt 1122df930be7Sderaadt case Q_DST: 1123df930be7Sderaadt offset_sh = 1; /* follows flags */ 1124df930be7Sderaadt offset_lh = 7; /* flgs,darea,dsubarea,HIORD */ 1125df930be7Sderaadt break; 1126df930be7Sderaadt 1127df930be7Sderaadt case Q_SRC: 1128df930be7Sderaadt offset_sh = 3; /* follows flags, dstnode */ 1129df930be7Sderaadt offset_lh = 15; /* flgs,darea,dsubarea,did,sarea,ssub,HIORD */ 1130df930be7Sderaadt break; 1131df930be7Sderaadt 1132df930be7Sderaadt case Q_AND: 1133df930be7Sderaadt /* Inefficient because we do our Calvinball dance twice */ 1134df930be7Sderaadt b0 = gen_dnhostop(addr, Q_SRC, base_off); 1135df930be7Sderaadt b1 = gen_dnhostop(addr, Q_DST, base_off); 1136df930be7Sderaadt gen_and(b0, b1); 1137df930be7Sderaadt return b1; 1138df930be7Sderaadt 1139df930be7Sderaadt case Q_OR: 1140df930be7Sderaadt case Q_DEFAULT: 1141df930be7Sderaadt /* Inefficient because we do our Calvinball dance twice */ 1142df930be7Sderaadt b0 = gen_dnhostop(addr, Q_SRC, base_off); 1143df930be7Sderaadt b1 = gen_dnhostop(addr, Q_DST, base_off); 1144df930be7Sderaadt gen_or(b0, b1); 1145df930be7Sderaadt return b1; 1146df930be7Sderaadt 1147df930be7Sderaadt default: 1148d42a50a0Sreyk bpf_error("direction not supported on linktype 0x%x", 1149d42a50a0Sreyk linktype); 1150df930be7Sderaadt } 1151df930be7Sderaadt b0 = gen_linktype(ETHERTYPE_DN); 1152df930be7Sderaadt /* Check for pad = 1, long header case */ 11538d8814c2Scanacar tmp = gen_mcmp_nl(base_off + 2, BPF_H, 11549b113833Smickey (bpf_int32)ntohs(0x0681), (bpf_int32)ntohs(0x07FF)); 11558d8814c2Scanacar b1 = gen_cmp_nl(base_off + 2 + 1 + offset_lh, 11569b113833Smickey BPF_H, (bpf_int32)ntohs(addr)); 1157df930be7Sderaadt gen_and(tmp, b1); 1158df930be7Sderaadt /* Check for pad = 0, long header case */ 11598d8814c2Scanacar tmp = gen_mcmp_nl(base_off + 2, BPF_B, (bpf_int32)0x06, (bpf_int32)0x7); 11608d8814c2Scanacar b2 = gen_cmp_nl(base_off + 2 + offset_lh, BPF_H, (bpf_int32)ntohs(addr)); 1161df930be7Sderaadt gen_and(tmp, b2); 1162df930be7Sderaadt gen_or(b2, b1); 1163df930be7Sderaadt /* Check for pad = 1, short header case */ 11648d8814c2Scanacar tmp = gen_mcmp_nl(base_off + 2, BPF_H, 11659b113833Smickey (bpf_int32)ntohs(0x0281), (bpf_int32)ntohs(0x07FF)); 11668d8814c2Scanacar b2 = gen_cmp_nl(base_off + 2 + 1 + offset_sh, 11679b113833Smickey BPF_H, (bpf_int32)ntohs(addr)); 1168df930be7Sderaadt gen_and(tmp, b2); 1169df930be7Sderaadt gen_or(b2, b1); 1170df930be7Sderaadt /* Check for pad = 0, short header case */ 11718d8814c2Scanacar tmp = gen_mcmp_nl(base_off + 2, BPF_B, (bpf_int32)0x02, (bpf_int32)0x7); 11728d8814c2Scanacar b2 = gen_cmp_nl(base_off + 2 + offset_sh, BPF_H, (bpf_int32)ntohs(addr)); 1173df930be7Sderaadt gen_and(tmp, b2); 1174df930be7Sderaadt gen_or(b2, b1); 1175df930be7Sderaadt 1176df930be7Sderaadt /* Combine with test for linktype */ 1177df930be7Sderaadt gen_and(b0, b1); 1178df930be7Sderaadt return b1; 1179df930be7Sderaadt } 1180df930be7Sderaadt 1181df930be7Sderaadt static struct block * 118219fef815Sderaadt gen_host(bpf_u_int32 addr, bpf_u_int32 mask, int proto, int dir) 1183df930be7Sderaadt { 1184df930be7Sderaadt struct block *b0, *b1; 1185df930be7Sderaadt 1186df930be7Sderaadt switch (proto) { 1187df930be7Sderaadt 1188df930be7Sderaadt case Q_DEFAULT: 1189df930be7Sderaadt b0 = gen_host(addr, mask, Q_IP, dir); 1190df930be7Sderaadt b1 = gen_host(addr, mask, Q_ARP, dir); 1191df930be7Sderaadt gen_or(b0, b1); 1192df930be7Sderaadt b0 = gen_host(addr, mask, Q_RARP, dir); 1193df930be7Sderaadt gen_or(b1, b0); 1194df930be7Sderaadt return b0; 1195df930be7Sderaadt 1196df930be7Sderaadt case Q_IP: 1197df930be7Sderaadt return gen_hostop(addr, mask, dir, ETHERTYPE_IP, 11988d8814c2Scanacar 12, 16); 1199df930be7Sderaadt 1200df930be7Sderaadt case Q_RARP: 1201df930be7Sderaadt return gen_hostop(addr, mask, dir, ETHERTYPE_REVARP, 12028d8814c2Scanacar 14, 24); 1203df930be7Sderaadt 1204df930be7Sderaadt case Q_ARP: 1205df930be7Sderaadt return gen_hostop(addr, mask, dir, ETHERTYPE_ARP, 12068d8814c2Scanacar 14, 24); 1207df930be7Sderaadt 1208df930be7Sderaadt case Q_TCP: 1209df930be7Sderaadt bpf_error("'tcp' modifier applied to host"); 1210df930be7Sderaadt 1211df930be7Sderaadt case Q_UDP: 1212df930be7Sderaadt bpf_error("'udp' modifier applied to host"); 1213df930be7Sderaadt 1214df930be7Sderaadt case Q_ICMP: 1215df930be7Sderaadt bpf_error("'icmp' modifier applied to host"); 1216df930be7Sderaadt 12179b113833Smickey case Q_IGMP: 12189b113833Smickey bpf_error("'igmp' modifier applied to host"); 12199b113833Smickey 122001efc7efSderaadt case Q_IGRP: 122101efc7efSderaadt bpf_error("'igrp' modifier applied to host"); 122201efc7efSderaadt 1223a9b0695fSjakob case Q_PIM: 1224a9b0695fSjakob bpf_error("'pim' modifier applied to host"); 1225a9b0695fSjakob 1226f562933eSmpf case Q_STP: 1227f562933eSmpf bpf_error("'stp' modifier applied to host"); 1228f562933eSmpf 122901efc7efSderaadt case Q_ATALK: 123001efc7efSderaadt bpf_error("ATALK host filtering not implemented"); 123101efc7efSderaadt 1232df930be7Sderaadt case Q_DECNET: 12338d8814c2Scanacar return gen_dnhostop(addr, dir, 0); 1234df930be7Sderaadt 123501efc7efSderaadt case Q_SCA: 123601efc7efSderaadt bpf_error("SCA host filtering not implemented"); 123701efc7efSderaadt 1238df930be7Sderaadt case Q_LAT: 1239df930be7Sderaadt bpf_error("LAT host filtering not implemented"); 1240df930be7Sderaadt 1241df930be7Sderaadt case Q_MOPDL: 1242df930be7Sderaadt bpf_error("MOPDL host filtering not implemented"); 1243df930be7Sderaadt 1244df930be7Sderaadt case Q_MOPRC: 1245df930be7Sderaadt bpf_error("MOPRC host filtering not implemented"); 1246df930be7Sderaadt 1247a9b0695fSjakob #ifdef INET6 1248a9b0695fSjakob case Q_IPV6: 1249a9b0695fSjakob bpf_error("'ip6' modifier applied to ip host"); 1250a9b0695fSjakob 1251a9b0695fSjakob case Q_ICMPV6: 1252a9b0695fSjakob bpf_error("'icmp6' modifier applied to host"); 1253a9b0695fSjakob #endif /* INET6 */ 1254a9b0695fSjakob 1255a9b0695fSjakob case Q_AH: 1256a9b0695fSjakob bpf_error("'ah' modifier applied to host"); 1257a9b0695fSjakob 1258a9b0695fSjakob case Q_ESP: 1259a9b0695fSjakob bpf_error("'esp' modifier applied to host"); 1260a9b0695fSjakob 1261df930be7Sderaadt default: 1262d42a50a0Sreyk bpf_error("direction not supported on linktype 0x%x", 1263d42a50a0Sreyk linktype); 1264df930be7Sderaadt } 1265df930be7Sderaadt /* NOTREACHED */ 1266df930be7Sderaadt } 1267df930be7Sderaadt 1268a9b0695fSjakob #ifdef INET6 1269a9b0695fSjakob static struct block * 127019fef815Sderaadt gen_host6(struct in6_addr *addr, struct in6_addr *mask, int proto, int dir) 1271a9b0695fSjakob { 1272a9b0695fSjakob switch (proto) { 1273a9b0695fSjakob 1274a9b0695fSjakob case Q_DEFAULT: 1275a9b0695fSjakob return gen_host6(addr, mask, Q_IPV6, dir); 1276a9b0695fSjakob 1277a9b0695fSjakob case Q_IP: 1278a9b0695fSjakob bpf_error("'ip' modifier applied to ip6 host"); 1279a9b0695fSjakob 1280a9b0695fSjakob case Q_RARP: 1281a9b0695fSjakob bpf_error("'rarp' modifier applied to ip6 host"); 1282a9b0695fSjakob 1283a9b0695fSjakob case Q_ARP: 1284a9b0695fSjakob bpf_error("'arp' modifier applied to ip6 host"); 1285a9b0695fSjakob 1286a9b0695fSjakob case Q_TCP: 1287a9b0695fSjakob bpf_error("'tcp' modifier applied to host"); 1288a9b0695fSjakob 1289a9b0695fSjakob case Q_UDP: 1290a9b0695fSjakob bpf_error("'udp' modifier applied to host"); 1291a9b0695fSjakob 1292a9b0695fSjakob case Q_ICMP: 1293a9b0695fSjakob bpf_error("'icmp' modifier applied to host"); 1294a9b0695fSjakob 1295a9b0695fSjakob case Q_IGMP: 1296a9b0695fSjakob bpf_error("'igmp' modifier applied to host"); 1297a9b0695fSjakob 1298a9b0695fSjakob case Q_IGRP: 1299a9b0695fSjakob bpf_error("'igrp' modifier applied to host"); 1300a9b0695fSjakob 1301a9b0695fSjakob case Q_PIM: 1302a9b0695fSjakob bpf_error("'pim' modifier applied to host"); 1303a9b0695fSjakob 1304f562933eSmpf case Q_STP: 1305f562933eSmpf bpf_error("'stp' modifier applied to host"); 1306f562933eSmpf 1307a9b0695fSjakob case Q_ATALK: 1308a9b0695fSjakob bpf_error("ATALK host filtering not implemented"); 1309a9b0695fSjakob 1310a9b0695fSjakob case Q_DECNET: 1311a9b0695fSjakob bpf_error("'decnet' modifier applied to ip6 host"); 1312a9b0695fSjakob 1313a9b0695fSjakob case Q_SCA: 1314a9b0695fSjakob bpf_error("SCA host filtering not implemented"); 1315a9b0695fSjakob 1316a9b0695fSjakob case Q_LAT: 1317a9b0695fSjakob bpf_error("LAT host filtering not implemented"); 1318a9b0695fSjakob 1319a9b0695fSjakob case Q_MOPDL: 1320a9b0695fSjakob bpf_error("MOPDL host filtering not implemented"); 1321a9b0695fSjakob 1322a9b0695fSjakob case Q_MOPRC: 1323a9b0695fSjakob bpf_error("MOPRC host filtering not implemented"); 1324a9b0695fSjakob 1325a9b0695fSjakob case Q_IPV6: 1326a9b0695fSjakob return gen_hostop6(addr, mask, dir, ETHERTYPE_IPV6, 13278d8814c2Scanacar 8, 24); 1328a9b0695fSjakob 1329a9b0695fSjakob case Q_ICMPV6: 1330a9b0695fSjakob bpf_error("'icmp6' modifier applied to host"); 1331a9b0695fSjakob 1332a9b0695fSjakob case Q_AH: 1333a9b0695fSjakob bpf_error("'ah' modifier applied to host"); 1334a9b0695fSjakob 1335a9b0695fSjakob case Q_ESP: 1336a9b0695fSjakob bpf_error("'esp' modifier applied to host"); 1337a9b0695fSjakob 1338a9b0695fSjakob default: 1339a9b0695fSjakob abort(); 1340a9b0695fSjakob } 1341a9b0695fSjakob /* NOTREACHED */ 1342a9b0695fSjakob } 1343a9b0695fSjakob #endif /*INET6*/ 1344a9b0695fSjakob 1345a9b0695fSjakob #ifndef INET6 1346df930be7Sderaadt static struct block * 1347146262eaSjsg gen_gateway(const u_char *eaddr, bpf_u_int32 **alist, int proto, int dir) 1348df930be7Sderaadt { 1349df930be7Sderaadt struct block *b0, *b1, *tmp; 1350df930be7Sderaadt 1351df930be7Sderaadt if (dir != 0) 1352df930be7Sderaadt bpf_error("direction applied to 'gateway'"); 1353df930be7Sderaadt 1354df930be7Sderaadt switch (proto) { 1355df930be7Sderaadt case Q_DEFAULT: 1356df930be7Sderaadt case Q_IP: 1357df930be7Sderaadt case Q_ARP: 1358df930be7Sderaadt case Q_RARP: 1359df930be7Sderaadt if (linktype == DLT_EN10MB) 1360df930be7Sderaadt b0 = gen_ehostop(eaddr, Q_OR); 1361df930be7Sderaadt else if (linktype == DLT_FDDI) 1362df930be7Sderaadt b0 = gen_fhostop(eaddr, Q_OR); 1363df930be7Sderaadt else 13649b113833Smickey bpf_error( 13659b113833Smickey "'gateway' supported only on ethernet or FDDI"); 1366df930be7Sderaadt 136701efc7efSderaadt b1 = gen_host(**alist++, 0xffffffff, proto, Q_OR); 1368df930be7Sderaadt while (*alist) { 136901efc7efSderaadt tmp = gen_host(**alist++, 0xffffffff, proto, Q_OR); 1370df930be7Sderaadt gen_or(b1, tmp); 1371df930be7Sderaadt b1 = tmp; 1372df930be7Sderaadt } 1373df930be7Sderaadt gen_not(b1); 1374df930be7Sderaadt gen_and(b0, b1); 1375df930be7Sderaadt return b1; 1376df930be7Sderaadt } 1377df930be7Sderaadt bpf_error("illegal modifier of 'gateway'"); 1378df930be7Sderaadt /* NOTREACHED */ 1379df930be7Sderaadt } 1380a9b0695fSjakob #endif /*INET6*/ 1381df930be7Sderaadt 1382df930be7Sderaadt struct block * 138319fef815Sderaadt gen_proto_abbrev(int proto) 1384df930be7Sderaadt { 1385a9b0695fSjakob struct block *b0 = NULL, *b1; 1386df930be7Sderaadt 1387df930be7Sderaadt switch (proto) { 1388df930be7Sderaadt 1389df930be7Sderaadt case Q_TCP: 1390a9b0695fSjakob b1 = gen_proto(IPPROTO_TCP, Q_IP, Q_DEFAULT); 1391a9b0695fSjakob #ifdef INET6 1392a9b0695fSjakob b0 = gen_proto(IPPROTO_TCP, Q_IPV6, Q_DEFAULT); 1393a9b0695fSjakob gen_or(b0, b1); 1394a9b0695fSjakob #endif 1395df930be7Sderaadt break; 1396df930be7Sderaadt 1397df930be7Sderaadt case Q_UDP: 1398a9b0695fSjakob b1 = gen_proto(IPPROTO_UDP, Q_IP, Q_DEFAULT); 1399a9b0695fSjakob #ifdef INET6 1400a9b0695fSjakob b0 = gen_proto(IPPROTO_UDP, Q_IPV6, Q_DEFAULT); 1401a9b0695fSjakob gen_or(b0, b1); 1402a9b0695fSjakob #endif 1403df930be7Sderaadt break; 1404df930be7Sderaadt 1405df930be7Sderaadt case Q_ICMP: 1406a9b0695fSjakob b1 = gen_proto(IPPROTO_ICMP, Q_IP, Q_DEFAULT); 14079b113833Smickey break; 14089b113833Smickey 1409a9b0695fSjakob #ifndef IPPROTO_IGMP 1410a9b0695fSjakob #define IPPROTO_IGMP 2 1411a9b0695fSjakob #endif 1412a9b0695fSjakob 14139b113833Smickey case Q_IGMP: 1414a9b0695fSjakob b1 = gen_proto(IPPROTO_IGMP, Q_IP, Q_DEFAULT); 1415df930be7Sderaadt break; 1416df930be7Sderaadt 141701efc7efSderaadt #ifndef IPPROTO_IGRP 141801efc7efSderaadt #define IPPROTO_IGRP 9 141901efc7efSderaadt #endif 142001efc7efSderaadt case Q_IGRP: 1421a9b0695fSjakob b1 = gen_proto(IPPROTO_IGRP, Q_IP, Q_DEFAULT); 1422a9b0695fSjakob break; 1423a9b0695fSjakob 1424a9b0695fSjakob #ifndef IPPROTO_PIM 1425a9b0695fSjakob #define IPPROTO_PIM 103 1426a9b0695fSjakob #endif 1427a9b0695fSjakob 1428a9b0695fSjakob case Q_PIM: 1429a9b0695fSjakob b1 = gen_proto(IPPROTO_PIM, Q_IP, Q_DEFAULT); 1430a9b0695fSjakob #ifdef INET6 1431a9b0695fSjakob b0 = gen_proto(IPPROTO_PIM, Q_IPV6, Q_DEFAULT); 1432a9b0695fSjakob gen_or(b0, b1); 1433a9b0695fSjakob #endif 143401efc7efSderaadt break; 143501efc7efSderaadt 1436df930be7Sderaadt case Q_IP: 1437df930be7Sderaadt b1 = gen_linktype(ETHERTYPE_IP); 1438df930be7Sderaadt break; 1439df930be7Sderaadt 1440df930be7Sderaadt case Q_ARP: 1441df930be7Sderaadt b1 = gen_linktype(ETHERTYPE_ARP); 1442df930be7Sderaadt break; 1443df930be7Sderaadt 1444df930be7Sderaadt case Q_RARP: 1445df930be7Sderaadt b1 = gen_linktype(ETHERTYPE_REVARP); 1446df930be7Sderaadt break; 1447df930be7Sderaadt 1448df930be7Sderaadt case Q_LINK: 1449df930be7Sderaadt bpf_error("link layer applied in wrong context"); 1450df930be7Sderaadt 145101efc7efSderaadt case Q_ATALK: 145201efc7efSderaadt b1 = gen_linktype(ETHERTYPE_ATALK); 145301efc7efSderaadt break; 145401efc7efSderaadt 1455df930be7Sderaadt case Q_DECNET: 1456df930be7Sderaadt b1 = gen_linktype(ETHERTYPE_DN); 1457df930be7Sderaadt break; 1458df930be7Sderaadt 145901efc7efSderaadt case Q_SCA: 146001efc7efSderaadt b1 = gen_linktype(ETHERTYPE_SCA); 146101efc7efSderaadt break; 146201efc7efSderaadt 1463df930be7Sderaadt case Q_LAT: 1464df930be7Sderaadt b1 = gen_linktype(ETHERTYPE_LAT); 1465df930be7Sderaadt break; 1466df930be7Sderaadt 1467df930be7Sderaadt case Q_MOPDL: 1468df930be7Sderaadt b1 = gen_linktype(ETHERTYPE_MOPDL); 1469df930be7Sderaadt break; 1470df930be7Sderaadt 1471df930be7Sderaadt case Q_MOPRC: 1472df930be7Sderaadt b1 = gen_linktype(ETHERTYPE_MOPRC); 1473df930be7Sderaadt break; 1474df930be7Sderaadt 1475f562933eSmpf case Q_STP: 1476f562933eSmpf b1 = gen_linktype(LLCSAP_8021D); 1477f562933eSmpf break; 1478f562933eSmpf 1479a9b0695fSjakob #ifdef INET6 1480a9b0695fSjakob case Q_IPV6: 1481a9b0695fSjakob b1 = gen_linktype(ETHERTYPE_IPV6); 1482a9b0695fSjakob break; 1483a9b0695fSjakob 1484a9b0695fSjakob #ifndef IPPROTO_ICMPV6 1485a9b0695fSjakob #define IPPROTO_ICMPV6 58 1486a9b0695fSjakob #endif 1487a9b0695fSjakob case Q_ICMPV6: 1488a9b0695fSjakob b1 = gen_proto(IPPROTO_ICMPV6, Q_IPV6, Q_DEFAULT); 1489a9b0695fSjakob break; 1490a9b0695fSjakob #endif /* INET6 */ 1491a9b0695fSjakob 1492a9b0695fSjakob #ifndef IPPROTO_AH 1493a9b0695fSjakob #define IPPROTO_AH 51 1494a9b0695fSjakob #endif 1495a9b0695fSjakob case Q_AH: 1496a9b0695fSjakob b1 = gen_proto(IPPROTO_AH, Q_IP, Q_DEFAULT); 1497a9b0695fSjakob #ifdef INET6 1498a9b0695fSjakob b0 = gen_proto(IPPROTO_AH, Q_IPV6, Q_DEFAULT); 1499a9b0695fSjakob gen_or(b0, b1); 1500a9b0695fSjakob #endif 1501a9b0695fSjakob break; 1502a9b0695fSjakob 1503a9b0695fSjakob #ifndef IPPROTO_ESP 1504a9b0695fSjakob #define IPPROTO_ESP 50 1505a9b0695fSjakob #endif 1506a9b0695fSjakob case Q_ESP: 1507a9b0695fSjakob b1 = gen_proto(IPPROTO_ESP, Q_IP, Q_DEFAULT); 1508a9b0695fSjakob #ifdef INET6 1509a9b0695fSjakob b0 = gen_proto(IPPROTO_ESP, Q_IPV6, Q_DEFAULT); 1510a9b0695fSjakob gen_or(b0, b1); 1511a9b0695fSjakob #endif 1512a9b0695fSjakob break; 1513a9b0695fSjakob 1514df930be7Sderaadt default: 1515df930be7Sderaadt abort(); 1516df930be7Sderaadt } 1517df930be7Sderaadt return b1; 1518df930be7Sderaadt } 1519df930be7Sderaadt 1520df930be7Sderaadt static struct block * 1521146262eaSjsg gen_ipfrag(void) 1522df930be7Sderaadt { 15238d8814c2Scanacar struct slist *s, *tmp; 1524df930be7Sderaadt struct block *b; 1525df930be7Sderaadt 1526df930be7Sderaadt /* not ip frag */ 15278d8814c2Scanacar if (variable_nl) { 15288d8814c2Scanacar s = nl2X_stmt(); 15298d8814c2Scanacar tmp = new_stmt(BPF_LD|BPF_H|BPF_IND); 15308d8814c2Scanacar tmp->s.k = 6; 15318d8814c2Scanacar sappend(s, tmp); 15328d8814c2Scanacar } else { 1533df930be7Sderaadt s = new_stmt(BPF_LD|BPF_H|BPF_ABS); 1534df930be7Sderaadt s->s.k = off_nl + 6; 15358d8814c2Scanacar } 1536df930be7Sderaadt b = new_block(JMP(BPF_JSET)); 1537df930be7Sderaadt b->s.k = 0x1fff; 1538df930be7Sderaadt b->stmts = s; 1539df930be7Sderaadt gen_not(b); 1540df930be7Sderaadt 1541df930be7Sderaadt return b; 1542df930be7Sderaadt } 1543df930be7Sderaadt 15448d8814c2Scanacar /* For dynamic off_nl, the BPF_LDX|BPF_MSH instruction does not work 15458d8814c2Scanacar This function generates code to set X to the start of the IP payload 15468d8814c2Scanacar X = off_nl + IP header_len. 15478d8814c2Scanacar */ 15488d8814c2Scanacar static struct slist * 15498d8814c2Scanacar iphl_to_x(void) 15508d8814c2Scanacar { 15518d8814c2Scanacar struct slist *s, *tmp; 15528d8814c2Scanacar 15538d8814c2Scanacar /* XXX clobbers A if variable_nl*/ 15548d8814c2Scanacar if (variable_nl) { 15558d8814c2Scanacar if (iphl_reg == -1) { 15568d8814c2Scanacar /* X <- off_nl */ 15578d8814c2Scanacar s = nl2X_stmt(); 15588d8814c2Scanacar 15598d8814c2Scanacar /* A = p[X+0] */ 15608d8814c2Scanacar tmp = new_stmt(BPF_LD|BPF_B|BPF_IND); 15618d8814c2Scanacar tmp->s.k = 0; 15628d8814c2Scanacar sappend(s, tmp); 15638d8814c2Scanacar 15648d8814c2Scanacar /* A = A & 0x0f */ 15658d8814c2Scanacar tmp = new_stmt(BPF_ALU|BPF_AND|BPF_K); 15668d8814c2Scanacar tmp->s.k = 0x0f; 15678d8814c2Scanacar sappend(s, tmp); 15688d8814c2Scanacar 15698d8814c2Scanacar /* A = A << 2 */ 15708d8814c2Scanacar tmp = new_stmt(BPF_ALU|BPF_LSH|BPF_K); 15718d8814c2Scanacar tmp->s.k = 2; 15728d8814c2Scanacar sappend(s, tmp); 15738d8814c2Scanacar 15742c53affbSjmc /* A = A + X (add off_nl again to compensate) */ 15758d8814c2Scanacar sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); 15768d8814c2Scanacar 15778d8814c2Scanacar /* MEM[iphl_reg] = A */ 15788d8814c2Scanacar iphl_reg = alloc_reg(); 15798d8814c2Scanacar tmp = new_stmt(BPF_ST); 15808d8814c2Scanacar tmp->s.k = iphl_reg; 15818d8814c2Scanacar sappend(s, tmp); 15828d8814c2Scanacar 15838d8814c2Scanacar sappend(init_code, s); 15848d8814c2Scanacar } 15858d8814c2Scanacar s = new_stmt(BPF_LDX|BPF_MEM); 15868d8814c2Scanacar s->s.k = iphl_reg; 15878d8814c2Scanacar 15888d8814c2Scanacar } else { 15898d8814c2Scanacar s = new_stmt(BPF_LDX|BPF_MSH|BPF_B); 15908d8814c2Scanacar s->s.k = off_nl; 15918d8814c2Scanacar } 15928d8814c2Scanacar 15938d8814c2Scanacar return s; 15948d8814c2Scanacar } 15958d8814c2Scanacar 1596df930be7Sderaadt static struct block * 159719fef815Sderaadt gen_portatom(int off, bpf_int32 v) 1598df930be7Sderaadt { 15998d8814c2Scanacar struct slist *s, *tmp; 1600df930be7Sderaadt struct block *b; 1601df930be7Sderaadt 16028d8814c2Scanacar s = iphl_to_x(); 1603df930be7Sderaadt 16048d8814c2Scanacar tmp = new_stmt(BPF_LD|BPF_IND|BPF_H); 16058d8814c2Scanacar tmp->s.k = off_nl + off; /* off_nl == 0 if variable_nl */ 16068d8814c2Scanacar sappend(s, tmp); 1607df930be7Sderaadt 1608df930be7Sderaadt b = new_block(JMP(BPF_JEQ)); 1609df930be7Sderaadt b->stmts = s; 1610df930be7Sderaadt b->s.k = v; 1611df930be7Sderaadt 1612df930be7Sderaadt return b; 1613df930be7Sderaadt } 1614df930be7Sderaadt 1615a9b0695fSjakob #ifdef INET6 1616a9b0695fSjakob static struct block * 161719fef815Sderaadt gen_portatom6(int off, bpf_int32 v) 1618a9b0695fSjakob { 16198d8814c2Scanacar return gen_cmp_nl(40 + off, BPF_H, v); 1620a9b0695fSjakob } 1621a9b0695fSjakob #endif/*INET6*/ 1622a9b0695fSjakob 1623df930be7Sderaadt struct block * 162419fef815Sderaadt gen_portop(int port, int proto, int dir) 1625df930be7Sderaadt { 1626df930be7Sderaadt struct block *b0, *b1, *tmp; 1627df930be7Sderaadt 1628df930be7Sderaadt /* ip proto 'proto' */ 16298d8814c2Scanacar tmp = gen_cmp_nl(9, BPF_B, (bpf_int32)proto); 1630df930be7Sderaadt b0 = gen_ipfrag(); 1631df930be7Sderaadt gen_and(tmp, b0); 1632df930be7Sderaadt 1633df930be7Sderaadt switch (dir) { 1634df930be7Sderaadt case Q_SRC: 16359b113833Smickey b1 = gen_portatom(0, (bpf_int32)port); 1636df930be7Sderaadt break; 1637df930be7Sderaadt 1638df930be7Sderaadt case Q_DST: 16399b113833Smickey b1 = gen_portatom(2, (bpf_int32)port); 1640df930be7Sderaadt break; 1641df930be7Sderaadt 1642df930be7Sderaadt case Q_OR: 1643df930be7Sderaadt case Q_DEFAULT: 16449b113833Smickey tmp = gen_portatom(0, (bpf_int32)port); 16459b113833Smickey b1 = gen_portatom(2, (bpf_int32)port); 1646df930be7Sderaadt gen_or(tmp, b1); 1647df930be7Sderaadt break; 1648df930be7Sderaadt 1649df930be7Sderaadt case Q_AND: 16509b113833Smickey tmp = gen_portatom(0, (bpf_int32)port); 16519b113833Smickey b1 = gen_portatom(2, (bpf_int32)port); 1652df930be7Sderaadt gen_and(tmp, b1); 1653df930be7Sderaadt break; 1654df930be7Sderaadt 1655df930be7Sderaadt default: 1656df930be7Sderaadt abort(); 1657df930be7Sderaadt } 1658df930be7Sderaadt gen_and(b0, b1); 1659df930be7Sderaadt 1660df930be7Sderaadt return b1; 1661df930be7Sderaadt } 1662df930be7Sderaadt 1663df930be7Sderaadt static struct block * 166419fef815Sderaadt gen_port(int port, int ip_proto, int dir) 1665df930be7Sderaadt { 1666df930be7Sderaadt struct block *b0, *b1, *tmp; 1667df930be7Sderaadt 1668df930be7Sderaadt /* ether proto ip */ 1669df930be7Sderaadt b0 = gen_linktype(ETHERTYPE_IP); 1670df930be7Sderaadt 1671df930be7Sderaadt switch (ip_proto) { 1672df930be7Sderaadt case IPPROTO_UDP: 1673df930be7Sderaadt case IPPROTO_TCP: 1674df930be7Sderaadt b1 = gen_portop(port, ip_proto, dir); 1675df930be7Sderaadt break; 1676df930be7Sderaadt 1677df930be7Sderaadt case PROTO_UNDEF: 1678df930be7Sderaadt tmp = gen_portop(port, IPPROTO_TCP, dir); 1679df930be7Sderaadt b1 = gen_portop(port, IPPROTO_UDP, dir); 1680df930be7Sderaadt gen_or(tmp, b1); 1681df930be7Sderaadt break; 1682df930be7Sderaadt 1683df930be7Sderaadt default: 1684df930be7Sderaadt abort(); 1685df930be7Sderaadt } 1686df930be7Sderaadt gen_and(b0, b1); 1687df930be7Sderaadt return b1; 1688df930be7Sderaadt } 1689df930be7Sderaadt 1690a9b0695fSjakob #ifdef INET6 1691a9b0695fSjakob struct block * 169219fef815Sderaadt gen_portop6(int port, int proto, int dir) 1693a9b0695fSjakob { 1694a9b0695fSjakob struct block *b0, *b1, *tmp; 1695a9b0695fSjakob 1696a9b0695fSjakob /* ip proto 'proto' */ 16978d8814c2Scanacar b0 = gen_cmp_nl(6, BPF_B, (bpf_int32)proto); 1698a9b0695fSjakob 1699a9b0695fSjakob switch (dir) { 1700a9b0695fSjakob case Q_SRC: 1701a9b0695fSjakob b1 = gen_portatom6(0, (bpf_int32)port); 1702a9b0695fSjakob break; 1703a9b0695fSjakob 1704a9b0695fSjakob case Q_DST: 1705a9b0695fSjakob b1 = gen_portatom6(2, (bpf_int32)port); 1706a9b0695fSjakob break; 1707a9b0695fSjakob 1708a9b0695fSjakob case Q_OR: 1709a9b0695fSjakob case Q_DEFAULT: 1710a9b0695fSjakob tmp = gen_portatom6(0, (bpf_int32)port); 1711a9b0695fSjakob b1 = gen_portatom6(2, (bpf_int32)port); 1712a9b0695fSjakob gen_or(tmp, b1); 1713a9b0695fSjakob break; 1714a9b0695fSjakob 1715a9b0695fSjakob case Q_AND: 1716a9b0695fSjakob tmp = gen_portatom6(0, (bpf_int32)port); 1717a9b0695fSjakob b1 = gen_portatom6(2, (bpf_int32)port); 1718a9b0695fSjakob gen_and(tmp, b1); 1719a9b0695fSjakob break; 1720a9b0695fSjakob 1721a9b0695fSjakob default: 1722a9b0695fSjakob abort(); 1723a9b0695fSjakob } 1724a9b0695fSjakob gen_and(b0, b1); 1725a9b0695fSjakob 1726a9b0695fSjakob return b1; 1727a9b0695fSjakob } 1728a9b0695fSjakob 1729a9b0695fSjakob static struct block * 173019fef815Sderaadt gen_port6(int port, int ip_proto, int dir) 1731a9b0695fSjakob { 1732a9b0695fSjakob struct block *b0, *b1, *tmp; 1733a9b0695fSjakob 1734a9b0695fSjakob /* ether proto ip */ 1735a9b0695fSjakob b0 = gen_linktype(ETHERTYPE_IPV6); 1736a9b0695fSjakob 1737a9b0695fSjakob switch (ip_proto) { 1738a9b0695fSjakob case IPPROTO_UDP: 1739a9b0695fSjakob case IPPROTO_TCP: 1740a9b0695fSjakob b1 = gen_portop6(port, ip_proto, dir); 1741a9b0695fSjakob break; 1742a9b0695fSjakob 1743a9b0695fSjakob case PROTO_UNDEF: 1744a9b0695fSjakob tmp = gen_portop6(port, IPPROTO_TCP, dir); 1745a9b0695fSjakob b1 = gen_portop6(port, IPPROTO_UDP, dir); 1746a9b0695fSjakob gen_or(tmp, b1); 1747a9b0695fSjakob break; 1748a9b0695fSjakob 1749a9b0695fSjakob default: 1750a9b0695fSjakob abort(); 1751a9b0695fSjakob } 1752a9b0695fSjakob gen_and(b0, b1); 1753a9b0695fSjakob return b1; 1754a9b0695fSjakob } 1755a9b0695fSjakob #endif /* INET6 */ 1756a9b0695fSjakob 1757df930be7Sderaadt static int 175819fef815Sderaadt lookup_proto(const char *name, int proto) 1759df930be7Sderaadt { 1760d0438536Smmcc int v; 1761df930be7Sderaadt 1762df930be7Sderaadt switch (proto) { 176301efc7efSderaadt 1764df930be7Sderaadt case Q_DEFAULT: 1765df930be7Sderaadt case Q_IP: 1766df930be7Sderaadt v = pcap_nametoproto(name); 1767df930be7Sderaadt if (v == PROTO_UNDEF) 1768df930be7Sderaadt bpf_error("unknown ip proto '%s'", name); 1769df930be7Sderaadt break; 1770df930be7Sderaadt 1771df930be7Sderaadt case Q_LINK: 1772df930be7Sderaadt /* XXX should look up h/w protocol type based on linktype */ 1773df930be7Sderaadt v = pcap_nametoeproto(name); 1774f562933eSmpf if (v == PROTO_UNDEF) { 1775f562933eSmpf v = pcap_nametollc(name); 1776df930be7Sderaadt if (v == PROTO_UNDEF) 1777df930be7Sderaadt bpf_error("unknown ether proto '%s'", name); 1778f562933eSmpf } 1779df930be7Sderaadt break; 1780df930be7Sderaadt 1781df930be7Sderaadt default: 1782df930be7Sderaadt v = PROTO_UNDEF; 1783df930be7Sderaadt break; 1784df930be7Sderaadt } 1785df930be7Sderaadt return v; 1786df930be7Sderaadt } 1787df930be7Sderaadt 1788df930be7Sderaadt static struct block * 178919fef815Sderaadt gen_protochain(int v, int proto, int dir) 1790a9b0695fSjakob { 1791a9b0695fSjakob struct block *b0, *b; 1792a9b0695fSjakob struct slist *s[100]; 1793a9b0695fSjakob int fix2, fix3, fix4, fix5; 1794a9b0695fSjakob int ahcheck, again, end; 1795a9b0695fSjakob int i, max; 1796a9b0695fSjakob int reg1 = alloc_reg(); 1797a9b0695fSjakob int reg2 = alloc_reg(); 1798a9b0695fSjakob 1799a9b0695fSjakob memset(s, 0, sizeof(s)); 1800a9b0695fSjakob fix2 = fix3 = fix4 = fix5 = 0; 1801a9b0695fSjakob 18028d8814c2Scanacar if (variable_nl) { 18038d8814c2Scanacar bpf_error("'gen_protochain' not supported for variable DLTs"); 18048d8814c2Scanacar /*NOTREACHED*/ 18058d8814c2Scanacar } 18068d8814c2Scanacar 1807a9b0695fSjakob switch (proto) { 1808a9b0695fSjakob case Q_IP: 1809a9b0695fSjakob case Q_IPV6: 1810a9b0695fSjakob break; 1811a9b0695fSjakob case Q_DEFAULT: 1812a9b0695fSjakob b0 = gen_protochain(v, Q_IP, dir); 1813a9b0695fSjakob b = gen_protochain(v, Q_IPV6, dir); 1814a9b0695fSjakob gen_or(b0, b); 1815a9b0695fSjakob return b; 1816a9b0695fSjakob default: 1817a9b0695fSjakob bpf_error("bad protocol applied for 'protochain'"); 1818a9b0695fSjakob /*NOTREACHED*/ 1819a9b0695fSjakob } 1820a9b0695fSjakob 1821a9b0695fSjakob no_optimize = 1; /*this code is not compatible with optimzer yet */ 1822a9b0695fSjakob 1823a9b0695fSjakob /* 1824a9b0695fSjakob * s[0] is a dummy entry to protect other BPF insn from damaged 1825a9b0695fSjakob * by s[fix] = foo with uninitialized variable "fix". It is somewhat 1826a9b0695fSjakob * hard to find interdependency made by jump table fixup. 1827a9b0695fSjakob */ 1828a9b0695fSjakob i = 0; 1829a9b0695fSjakob s[i] = new_stmt(0); /*dummy*/ 1830a9b0695fSjakob i++; 1831a9b0695fSjakob 1832a9b0695fSjakob switch (proto) { 1833a9b0695fSjakob case Q_IP: 1834a9b0695fSjakob b0 = gen_linktype(ETHERTYPE_IP); 1835a9b0695fSjakob 1836a9b0695fSjakob /* A = ip->ip_p */ 1837a9b0695fSjakob s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B); 1838a9b0695fSjakob s[i]->s.k = off_nl + 9; 1839a9b0695fSjakob i++; 1840a9b0695fSjakob /* X = ip->ip_hl << 2 */ 1841a9b0695fSjakob s[i] = new_stmt(BPF_LDX|BPF_MSH|BPF_B); 1842a9b0695fSjakob s[i]->s.k = off_nl; 1843a9b0695fSjakob i++; 1844a9b0695fSjakob break; 1845a9b0695fSjakob case Q_IPV6: 1846a9b0695fSjakob b0 = gen_linktype(ETHERTYPE_IPV6); 1847a9b0695fSjakob 1848a9b0695fSjakob /* A = ip6->ip_nxt */ 1849a9b0695fSjakob s[i] = new_stmt(BPF_LD|BPF_ABS|BPF_B); 1850a9b0695fSjakob s[i]->s.k = off_nl + 6; 1851a9b0695fSjakob i++; 1852a9b0695fSjakob /* X = sizeof(struct ip6_hdr) */ 1853a9b0695fSjakob s[i] = new_stmt(BPF_LDX|BPF_IMM); 1854a9b0695fSjakob s[i]->s.k = 40; 1855a9b0695fSjakob i++; 1856a9b0695fSjakob break; 1857a9b0695fSjakob default: 1858a9b0695fSjakob bpf_error("unsupported proto to gen_protochain"); 1859a9b0695fSjakob /*NOTREACHED*/ 1860a9b0695fSjakob } 1861a9b0695fSjakob 1862a9b0695fSjakob /* again: if (A == v) goto end; else fall through; */ 1863a9b0695fSjakob again = i; 1864a9b0695fSjakob s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); 1865a9b0695fSjakob s[i]->s.k = v; 1866a9b0695fSjakob s[i]->s.jt = NULL; /*later*/ 1867a9b0695fSjakob s[i]->s.jf = NULL; /*update in next stmt*/ 1868a9b0695fSjakob fix5 = i; 1869a9b0695fSjakob i++; 1870a9b0695fSjakob 1871a9b0695fSjakob /* if (A == IPPROTO_NONE) goto end */ 1872a9b0695fSjakob s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); 1873a9b0695fSjakob s[i]->s.jt = NULL; /*later*/ 1874a9b0695fSjakob s[i]->s.jf = NULL; /*update in next stmt*/ 1875a9b0695fSjakob s[i]->s.k = IPPROTO_NONE; 1876a9b0695fSjakob s[fix5]->s.jf = s[i]; 1877a9b0695fSjakob fix2 = i; 1878a9b0695fSjakob i++; 1879a9b0695fSjakob 1880a9b0695fSjakob if (proto == Q_IPV6) { 1881a9b0695fSjakob int v6start, v6end, v6advance, j; 1882a9b0695fSjakob 1883a9b0695fSjakob v6start = i; 1884a9b0695fSjakob /* if (A == IPPROTO_HOPOPTS) goto v6advance */ 1885a9b0695fSjakob s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); 1886a9b0695fSjakob s[i]->s.jt = NULL; /*later*/ 1887a9b0695fSjakob s[i]->s.jf = NULL; /*update in next stmt*/ 1888a9b0695fSjakob s[i]->s.k = IPPROTO_HOPOPTS; 1889a9b0695fSjakob s[fix2]->s.jf = s[i]; 1890a9b0695fSjakob i++; 1891a9b0695fSjakob /* if (A == IPPROTO_DSTOPTS) goto v6advance */ 1892a9b0695fSjakob s[i - 1]->s.jf = s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); 1893a9b0695fSjakob s[i]->s.jt = NULL; /*later*/ 1894a9b0695fSjakob s[i]->s.jf = NULL; /*update in next stmt*/ 1895a9b0695fSjakob s[i]->s.k = IPPROTO_DSTOPTS; 1896a9b0695fSjakob i++; 1897a9b0695fSjakob /* if (A == IPPROTO_ROUTING) goto v6advance */ 1898a9b0695fSjakob s[i - 1]->s.jf = s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); 1899a9b0695fSjakob s[i]->s.jt = NULL; /*later*/ 1900a9b0695fSjakob s[i]->s.jf = NULL; /*update in next stmt*/ 1901a9b0695fSjakob s[i]->s.k = IPPROTO_ROUTING; 1902a9b0695fSjakob i++; 1903a9b0695fSjakob /* if (A == IPPROTO_FRAGMENT) goto v6advance; else goto ahcheck; */ 1904a9b0695fSjakob s[i - 1]->s.jf = s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); 1905a9b0695fSjakob s[i]->s.jt = NULL; /*later*/ 1906a9b0695fSjakob s[i]->s.jf = NULL; /*later*/ 1907a9b0695fSjakob s[i]->s.k = IPPROTO_FRAGMENT; 1908a9b0695fSjakob fix3 = i; 1909a9b0695fSjakob v6end = i; 1910a9b0695fSjakob i++; 1911a9b0695fSjakob 1912a9b0695fSjakob /* v6advance: */ 1913a9b0695fSjakob v6advance = i; 1914a9b0695fSjakob 1915a9b0695fSjakob /* 1916a9b0695fSjakob * in short, 1917a9b0695fSjakob * A = P[X + 1]; 1918a9b0695fSjakob * X = X + (P[X] + 1) * 8; 1919a9b0695fSjakob */ 1920a9b0695fSjakob /* A = X */ 1921a9b0695fSjakob s[i] = new_stmt(BPF_MISC|BPF_TXA); 1922a9b0695fSjakob i++; 1923a9b0695fSjakob /* MEM[reg1] = A */ 1924a9b0695fSjakob s[i] = new_stmt(BPF_ST); 1925a9b0695fSjakob s[i]->s.k = reg1; 1926a9b0695fSjakob i++; 1927a9b0695fSjakob /* A += 1 */ 1928a9b0695fSjakob s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); 1929a9b0695fSjakob s[i]->s.k = 1; 1930a9b0695fSjakob i++; 1931a9b0695fSjakob /* X = A */ 1932a9b0695fSjakob s[i] = new_stmt(BPF_MISC|BPF_TAX); 1933a9b0695fSjakob i++; 1934a9b0695fSjakob /* A = P[X + packet head]; */ 1935a9b0695fSjakob s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); 1936a9b0695fSjakob s[i]->s.k = off_nl; 1937a9b0695fSjakob i++; 1938a9b0695fSjakob /* MEM[reg2] = A */ 1939a9b0695fSjakob s[i] = new_stmt(BPF_ST); 1940a9b0695fSjakob s[i]->s.k = reg2; 1941a9b0695fSjakob i++; 1942a9b0695fSjakob /* X = MEM[reg1] */ 1943a9b0695fSjakob s[i] = new_stmt(BPF_LDX|BPF_MEM); 1944a9b0695fSjakob s[i]->s.k = reg1; 1945a9b0695fSjakob i++; 1946a9b0695fSjakob /* A = P[X + packet head] */ 1947a9b0695fSjakob s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); 1948a9b0695fSjakob s[i]->s.k = off_nl; 1949a9b0695fSjakob i++; 1950a9b0695fSjakob /* A += 1 */ 1951a9b0695fSjakob s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); 1952a9b0695fSjakob s[i]->s.k = 1; 1953a9b0695fSjakob i++; 1954a9b0695fSjakob /* A *= 8 */ 1955a9b0695fSjakob s[i] = new_stmt(BPF_ALU|BPF_MUL|BPF_K); 1956a9b0695fSjakob s[i]->s.k = 8; 1957a9b0695fSjakob i++; 1958a9b0695fSjakob /* X = A; */ 1959a9b0695fSjakob s[i] = new_stmt(BPF_MISC|BPF_TAX); 1960a9b0695fSjakob i++; 1961a9b0695fSjakob /* A = MEM[reg2] */ 1962a9b0695fSjakob s[i] = new_stmt(BPF_LD|BPF_MEM); 1963a9b0695fSjakob s[i]->s.k = reg2; 1964a9b0695fSjakob i++; 1965a9b0695fSjakob 1966a9b0695fSjakob /* goto again; (must use BPF_JA for backward jump) */ 1967a9b0695fSjakob s[i] = new_stmt(BPF_JMP|BPF_JA); 1968a9b0695fSjakob s[i]->s.k = again - i - 1; 1969a9b0695fSjakob s[i - 1]->s.jf = s[i]; 1970a9b0695fSjakob i++; 1971a9b0695fSjakob 1972a9b0695fSjakob /* fixup */ 1973a9b0695fSjakob for (j = v6start; j <= v6end; j++) 1974a9b0695fSjakob s[j]->s.jt = s[v6advance]; 1975a9b0695fSjakob } else { 1976a9b0695fSjakob /* nop */ 1977a9b0695fSjakob s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); 1978a9b0695fSjakob s[i]->s.k = 0; 1979a9b0695fSjakob s[fix2]->s.jf = s[i]; 1980a9b0695fSjakob i++; 1981a9b0695fSjakob } 1982a9b0695fSjakob 1983a9b0695fSjakob /* ahcheck: */ 1984a9b0695fSjakob ahcheck = i; 1985a9b0695fSjakob /* if (A == IPPROTO_AH) then fall through; else goto end; */ 1986a9b0695fSjakob s[i] = new_stmt(BPF_JMP|BPF_JEQ|BPF_K); 1987a9b0695fSjakob s[i]->s.jt = NULL; /*later*/ 1988a9b0695fSjakob s[i]->s.jf = NULL; /*later*/ 1989a9b0695fSjakob s[i]->s.k = IPPROTO_AH; 1990a9b0695fSjakob if (fix3) 1991a9b0695fSjakob s[fix3]->s.jf = s[ahcheck]; 1992a9b0695fSjakob fix4 = i; 1993a9b0695fSjakob i++; 1994a9b0695fSjakob 1995a9b0695fSjakob /* 1996a9b0695fSjakob * in short, 1997a9b0695fSjakob * A = P[X + 1]; 1998a9b0695fSjakob * X = X + (P[X] + 2) * 4; 1999a9b0695fSjakob */ 2000a9b0695fSjakob /* A = X */ 2001a9b0695fSjakob s[i - 1]->s.jt = s[i] = new_stmt(BPF_MISC|BPF_TXA); 2002a9b0695fSjakob i++; 2003a9b0695fSjakob /* MEM[reg1] = A */ 2004a9b0695fSjakob s[i] = new_stmt(BPF_ST); 2005a9b0695fSjakob s[i]->s.k = reg1; 2006a9b0695fSjakob i++; 2007a9b0695fSjakob /* A += 1 */ 2008a9b0695fSjakob s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); 2009a9b0695fSjakob s[i]->s.k = 1; 2010a9b0695fSjakob i++; 2011a9b0695fSjakob /* X = A */ 2012a9b0695fSjakob s[i] = new_stmt(BPF_MISC|BPF_TAX); 2013a9b0695fSjakob i++; 2014a9b0695fSjakob /* A = P[X + packet head]; */ 2015a9b0695fSjakob s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); 2016a9b0695fSjakob s[i]->s.k = off_nl; 2017a9b0695fSjakob i++; 2018a9b0695fSjakob /* MEM[reg2] = A */ 2019a9b0695fSjakob s[i] = new_stmt(BPF_ST); 2020a9b0695fSjakob s[i]->s.k = reg2; 2021a9b0695fSjakob i++; 2022a9b0695fSjakob /* X = MEM[reg1] */ 2023a9b0695fSjakob s[i] = new_stmt(BPF_LDX|BPF_MEM); 2024a9b0695fSjakob s[i]->s.k = reg1; 2025a9b0695fSjakob i++; 2026a9b0695fSjakob /* A = P[X + packet head] */ 2027a9b0695fSjakob s[i] = new_stmt(BPF_LD|BPF_IND|BPF_B); 2028a9b0695fSjakob s[i]->s.k = off_nl; 2029a9b0695fSjakob i++; 2030a9b0695fSjakob /* A += 2 */ 2031a9b0695fSjakob s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); 2032a9b0695fSjakob s[i]->s.k = 2; 2033a9b0695fSjakob i++; 2034a9b0695fSjakob /* A *= 4 */ 2035a9b0695fSjakob s[i] = new_stmt(BPF_ALU|BPF_MUL|BPF_K); 2036a9b0695fSjakob s[i]->s.k = 4; 2037a9b0695fSjakob i++; 2038a9b0695fSjakob /* X = A; */ 2039a9b0695fSjakob s[i] = new_stmt(BPF_MISC|BPF_TAX); 2040a9b0695fSjakob i++; 2041a9b0695fSjakob /* A = MEM[reg2] */ 2042a9b0695fSjakob s[i] = new_stmt(BPF_LD|BPF_MEM); 2043a9b0695fSjakob s[i]->s.k = reg2; 2044a9b0695fSjakob i++; 2045a9b0695fSjakob 2046a9b0695fSjakob /* goto again; (must use BPF_JA for backward jump) */ 2047a9b0695fSjakob s[i] = new_stmt(BPF_JMP|BPF_JA); 2048a9b0695fSjakob s[i]->s.k = again - i - 1; 2049a9b0695fSjakob i++; 2050a9b0695fSjakob 2051a9b0695fSjakob /* end: nop */ 2052a9b0695fSjakob end = i; 2053a9b0695fSjakob s[i] = new_stmt(BPF_ALU|BPF_ADD|BPF_K); 2054a9b0695fSjakob s[i]->s.k = 0; 2055a9b0695fSjakob s[fix2]->s.jt = s[end]; 2056a9b0695fSjakob s[fix4]->s.jf = s[end]; 2057a9b0695fSjakob s[fix5]->s.jt = s[end]; 2058a9b0695fSjakob i++; 2059a9b0695fSjakob 2060a9b0695fSjakob /* 2061a9b0695fSjakob * make slist chain 2062a9b0695fSjakob */ 2063a9b0695fSjakob max = i; 2064a9b0695fSjakob for (i = 0; i < max - 1; i++) 2065a9b0695fSjakob s[i]->next = s[i + 1]; 2066a9b0695fSjakob s[max - 1]->next = NULL; 2067a9b0695fSjakob 2068a9b0695fSjakob /* 2069a9b0695fSjakob * emit final check 2070a9b0695fSjakob */ 2071a9b0695fSjakob b = new_block(JMP(BPF_JEQ)); 2072a9b0695fSjakob b->stmts = s[1]; /*remember, s[0] is dummy*/ 2073a9b0695fSjakob b->s.k = v; 2074a9b0695fSjakob 2075a9b0695fSjakob free_reg(reg1); 2076a9b0695fSjakob free_reg(reg2); 2077a9b0695fSjakob 2078a9b0695fSjakob gen_and(b0, b); 2079a9b0695fSjakob return b; 2080a9b0695fSjakob } 2081a9b0695fSjakob 2082a9b0695fSjakob static struct block * 208319fef815Sderaadt gen_proto(int v, int proto, int dir) 2084df930be7Sderaadt { 2085df930be7Sderaadt struct block *b0, *b1; 2086df930be7Sderaadt 2087df930be7Sderaadt if (dir != Q_DEFAULT) 2088df930be7Sderaadt bpf_error("direction applied to 'proto'"); 2089df930be7Sderaadt 2090df930be7Sderaadt switch (proto) { 2091df930be7Sderaadt case Q_DEFAULT: 2092a9b0695fSjakob #ifdef INET6 2093a9b0695fSjakob b0 = gen_proto(v, Q_IP, dir); 2094a9b0695fSjakob b1 = gen_proto(v, Q_IPV6, dir); 2095a9b0695fSjakob gen_or(b0, b1); 2096a9b0695fSjakob return b1; 2097a9b0695fSjakob #else 2098a9b0695fSjakob /*FALLTHROUGH*/ 2099a9b0695fSjakob #endif 2100df930be7Sderaadt case Q_IP: 2101df930be7Sderaadt b0 = gen_linktype(ETHERTYPE_IP); 2102a9b0695fSjakob #ifndef CHASE_CHAIN 21038d8814c2Scanacar b1 = gen_cmp_nl(9, BPF_B, (bpf_int32)v); 2104a9b0695fSjakob #else 2105a9b0695fSjakob b1 = gen_protochain(v, Q_IP); 2106a9b0695fSjakob #endif 2107df930be7Sderaadt gen_and(b0, b1); 2108df930be7Sderaadt return b1; 2109df930be7Sderaadt 2110df930be7Sderaadt case Q_ARP: 2111df930be7Sderaadt bpf_error("arp does not encapsulate another protocol"); 2112df930be7Sderaadt /* NOTREACHED */ 2113df930be7Sderaadt 2114df930be7Sderaadt case Q_RARP: 2115df930be7Sderaadt bpf_error("rarp does not encapsulate another protocol"); 2116df930be7Sderaadt /* NOTREACHED */ 2117df930be7Sderaadt 211801efc7efSderaadt case Q_ATALK: 211901efc7efSderaadt bpf_error("atalk encapsulation is not specifiable"); 212001efc7efSderaadt /* NOTREACHED */ 212101efc7efSderaadt 2122df930be7Sderaadt case Q_DECNET: 2123df930be7Sderaadt bpf_error("decnet encapsulation is not specifiable"); 2124df930be7Sderaadt /* NOTREACHED */ 2125df930be7Sderaadt 212601efc7efSderaadt case Q_SCA: 212701efc7efSderaadt bpf_error("sca does not encapsulate another protocol"); 212801efc7efSderaadt /* NOTREACHED */ 212901efc7efSderaadt 2130df930be7Sderaadt case Q_LAT: 2131df930be7Sderaadt bpf_error("lat does not encapsulate another protocol"); 2132df930be7Sderaadt /* NOTREACHED */ 2133df930be7Sderaadt 2134df930be7Sderaadt case Q_MOPRC: 2135df930be7Sderaadt bpf_error("moprc does not encapsulate another protocol"); 2136df930be7Sderaadt /* NOTREACHED */ 2137df930be7Sderaadt 2138df930be7Sderaadt case Q_MOPDL: 2139df930be7Sderaadt bpf_error("mopdl does not encapsulate another protocol"); 2140df930be7Sderaadt /* NOTREACHED */ 2141df930be7Sderaadt 2142df930be7Sderaadt case Q_LINK: 2143df930be7Sderaadt return gen_linktype(v); 2144df930be7Sderaadt 2145df930be7Sderaadt case Q_UDP: 2146df930be7Sderaadt bpf_error("'udp proto' is bogus"); 2147df930be7Sderaadt /* NOTREACHED */ 2148df930be7Sderaadt 2149df930be7Sderaadt case Q_TCP: 2150df930be7Sderaadt bpf_error("'tcp proto' is bogus"); 2151df930be7Sderaadt /* NOTREACHED */ 2152df930be7Sderaadt 2153df930be7Sderaadt case Q_ICMP: 2154df930be7Sderaadt bpf_error("'icmp proto' is bogus"); 2155df930be7Sderaadt /* NOTREACHED */ 2156df930be7Sderaadt 21579b113833Smickey case Q_IGMP: 21589b113833Smickey bpf_error("'igmp proto' is bogus"); 21599b113833Smickey /* NOTREACHED */ 21609b113833Smickey 216101efc7efSderaadt case Q_IGRP: 216201efc7efSderaadt bpf_error("'igrp proto' is bogus"); 216301efc7efSderaadt /* NOTREACHED */ 216401efc7efSderaadt 2165a9b0695fSjakob case Q_PIM: 2166a9b0695fSjakob bpf_error("'pim proto' is bogus"); 2167a9b0695fSjakob /* NOTREACHED */ 2168a9b0695fSjakob 2169f562933eSmpf case Q_STP: 2170f562933eSmpf bpf_error("'stp proto' is bogus"); 2171f562933eSmpf /* NOTREACHED */ 2172f562933eSmpf 2173a9b0695fSjakob #ifdef INET6 2174a9b0695fSjakob case Q_IPV6: 2175a9b0695fSjakob b0 = gen_linktype(ETHERTYPE_IPV6); 2176a9b0695fSjakob #ifndef CHASE_CHAIN 21778d8814c2Scanacar b1 = gen_cmp_nl(6, BPF_B, (bpf_int32)v); 2178a9b0695fSjakob #else 2179a9b0695fSjakob b1 = gen_protochain(v, Q_IPV6); 2180a9b0695fSjakob #endif 2181a9b0695fSjakob gen_and(b0, b1); 2182a9b0695fSjakob return b1; 2183a9b0695fSjakob 2184a9b0695fSjakob case Q_ICMPV6: 2185a9b0695fSjakob bpf_error("'icmp6 proto' is bogus"); 2186a9b0695fSjakob #endif /* INET6 */ 2187a9b0695fSjakob 2188a9b0695fSjakob case Q_AH: 2189a9b0695fSjakob bpf_error("'ah proto' is bogus"); 2190a9b0695fSjakob 2191a9b0695fSjakob case Q_ESP: 2192ac451769Sdenis bpf_error("'esp proto' is bogus"); 2193a9b0695fSjakob 2194df930be7Sderaadt default: 2195df930be7Sderaadt abort(); 2196df930be7Sderaadt /* NOTREACHED */ 2197df930be7Sderaadt } 2198df930be7Sderaadt /* NOTREACHED */ 2199df930be7Sderaadt } 2200df930be7Sderaadt 2201df930be7Sderaadt struct block * 220219fef815Sderaadt gen_scode(const char *name, struct qual q) 2203df930be7Sderaadt { 2204df930be7Sderaadt int proto = q.proto; 2205df930be7Sderaadt int dir = q.dir; 220601efc7efSderaadt int tproto; 2207df930be7Sderaadt u_char *eaddr; 2208a9b0695fSjakob bpf_u_int32 mask, addr; 2209a9b0695fSjakob #ifndef INET6 2210a9b0695fSjakob bpf_u_int32 **alist; 2211a9b0695fSjakob #else 2212a9b0695fSjakob int tproto6; 2213a9b0695fSjakob struct sockaddr_in *sin; 2214a9b0695fSjakob struct sockaddr_in6 *sin6; 2215a9b0695fSjakob struct addrinfo *res, *res0; 2216a9b0695fSjakob struct in6_addr mask128; 2217a9b0695fSjakob #endif /*INET6*/ 2218df930be7Sderaadt struct block *b, *tmp; 2219df930be7Sderaadt int port, real_proto; 2220df930be7Sderaadt 2221df930be7Sderaadt switch (q.addr) { 2222df930be7Sderaadt 2223df930be7Sderaadt case Q_NET: 2224df930be7Sderaadt addr = pcap_nametonetaddr(name); 2225df930be7Sderaadt if (addr == 0) 2226df930be7Sderaadt bpf_error("unknown network '%s'", name); 222701efc7efSderaadt /* Left justify network addr and calculate its network mask */ 222801efc7efSderaadt mask = 0xffffffff; 222901efc7efSderaadt while (addr && (addr & 0xff000000) == 0) { 223001efc7efSderaadt addr <<= 8; 223101efc7efSderaadt mask <<= 8; 223201efc7efSderaadt } 2233df930be7Sderaadt return gen_host(addr, mask, proto, dir); 2234df930be7Sderaadt 2235df930be7Sderaadt case Q_DEFAULT: 2236df930be7Sderaadt case Q_HOST: 2237df930be7Sderaadt if (proto == Q_LINK) { 2238df930be7Sderaadt switch (linktype) { 22399b113833Smickey 2240df930be7Sderaadt case DLT_EN10MB: 2241df930be7Sderaadt eaddr = pcap_ether_hostton(name); 2242df930be7Sderaadt if (eaddr == NULL) 22439b113833Smickey bpf_error( 22449b113833Smickey "unknown ether host '%s'", name); 2245df930be7Sderaadt return gen_ehostop(eaddr, dir); 2246df930be7Sderaadt 2247df930be7Sderaadt case DLT_FDDI: 2248df930be7Sderaadt eaddr = pcap_ether_hostton(name); 2249df930be7Sderaadt if (eaddr == NULL) 22509b113833Smickey bpf_error( 22519b113833Smickey "unknown FDDI host '%s'", name); 2252df930be7Sderaadt return gen_fhostop(eaddr, dir); 22539b113833Smickey 2254d42a50a0Sreyk case DLT_IEEE802_11: 2255d42a50a0Sreyk case DLT_IEEE802_11_RADIO: 2256d42a50a0Sreyk eaddr = pcap_ether_hostton(name); 2257d42a50a0Sreyk if (eaddr == NULL) 2258d42a50a0Sreyk bpf_error( 2259d42a50a0Sreyk "unknown 802.11 host '%s'", name); 2260d42a50a0Sreyk 2261d42a50a0Sreyk return gen_p80211_hostop(eaddr, dir); 2262d42a50a0Sreyk 2263df930be7Sderaadt default: 22649b113833Smickey bpf_error( 22659b113833Smickey "only ethernet/FDDI supports link-level host name"); 2266df930be7Sderaadt break; 2267df930be7Sderaadt } 2268df930be7Sderaadt } else if (proto == Q_DECNET) { 2269df930be7Sderaadt unsigned short dn_addr = __pcap_nametodnaddr(name); 2270df930be7Sderaadt /* 2271df930be7Sderaadt * I don't think DECNET hosts can be multihomed, so 2272df930be7Sderaadt * there is no need to build up a list of addresses 2273df930be7Sderaadt */ 2274df930be7Sderaadt return (gen_host(dn_addr, 0, proto, dir)); 2275df930be7Sderaadt } else { 2276a9b0695fSjakob #ifndef INET6 2277df930be7Sderaadt alist = pcap_nametoaddr(name); 2278df930be7Sderaadt if (alist == NULL || *alist == NULL) 2279df930be7Sderaadt bpf_error("unknown host '%s'", name); 228001efc7efSderaadt tproto = proto; 228101efc7efSderaadt if (off_linktype == -1 && tproto == Q_DEFAULT) 228201efc7efSderaadt tproto = Q_IP; 228301efc7efSderaadt b = gen_host(**alist++, 0xffffffff, tproto, dir); 2284df930be7Sderaadt while (*alist) { 228501efc7efSderaadt tmp = gen_host(**alist++, 0xffffffff, 228601efc7efSderaadt tproto, dir); 2287df930be7Sderaadt gen_or(b, tmp); 2288df930be7Sderaadt b = tmp; 2289df930be7Sderaadt } 2290df930be7Sderaadt return b; 2291a9b0695fSjakob #else 2292a9b0695fSjakob memset(&mask128, 0xff, sizeof(mask128)); 2293a9b0695fSjakob res0 = res = pcap_nametoaddrinfo(name); 2294a9b0695fSjakob if (res == NULL) 2295a9b0695fSjakob bpf_error("unknown host '%s'", name); 2296a9b0695fSjakob b = tmp = NULL; 2297a9b0695fSjakob tproto = tproto6 = proto; 2298a9b0695fSjakob if (off_linktype == -1 && tproto == Q_DEFAULT) { 2299a9b0695fSjakob tproto = Q_IP; 2300a9b0695fSjakob tproto6 = Q_IPV6; 2301a9b0695fSjakob } 2302a9b0695fSjakob for (res = res0; res; res = res->ai_next) { 2303a9b0695fSjakob switch (res->ai_family) { 2304a9b0695fSjakob case AF_INET: 2305a9b0695fSjakob if (tproto == Q_IPV6) 2306a9b0695fSjakob continue; 2307a9b0695fSjakob 2308a9b0695fSjakob sin = (struct sockaddr_in *) 2309a9b0695fSjakob res->ai_addr; 2310a9b0695fSjakob tmp = gen_host(ntohl(sin->sin_addr.s_addr), 2311a9b0695fSjakob 0xffffffff, tproto, dir); 2312a9b0695fSjakob break; 2313a9b0695fSjakob case AF_INET6: 2314a9b0695fSjakob if (tproto6 == Q_IP) 2315a9b0695fSjakob continue; 2316a9b0695fSjakob 2317a9b0695fSjakob sin6 = (struct sockaddr_in6 *) 2318a9b0695fSjakob res->ai_addr; 2319a9b0695fSjakob tmp = gen_host6(&sin6->sin6_addr, 2320a9b0695fSjakob &mask128, tproto6, dir); 2321a9b0695fSjakob break; 2322a9b0695fSjakob } 2323a9b0695fSjakob if (b) 2324a9b0695fSjakob gen_or(b, tmp); 2325a9b0695fSjakob b = tmp; 2326a9b0695fSjakob } 2327a9b0695fSjakob freeaddrinfo(res0); 2328a9b0695fSjakob if (b == NULL) { 2329a9b0695fSjakob bpf_error("unknown host '%s'%s", name, 2330a9b0695fSjakob (proto == Q_DEFAULT) 2331a9b0695fSjakob ? "" 2332a9b0695fSjakob : " for specified address family"); 2333a9b0695fSjakob } 2334a9b0695fSjakob return b; 2335a9b0695fSjakob #endif /*INET6*/ 2336df930be7Sderaadt } 2337df930be7Sderaadt 2338df930be7Sderaadt case Q_PORT: 2339df930be7Sderaadt if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP) 2340df930be7Sderaadt bpf_error("illegal qualifier of 'port'"); 2341df930be7Sderaadt if (pcap_nametoport(name, &port, &real_proto) == 0) 2342df930be7Sderaadt bpf_error("unknown port '%s'", name); 2343df930be7Sderaadt if (proto == Q_UDP) { 2344df930be7Sderaadt if (real_proto == IPPROTO_TCP) 2345df930be7Sderaadt bpf_error("port '%s' is tcp", name); 2346df930be7Sderaadt else 2347df930be7Sderaadt /* override PROTO_UNDEF */ 2348df930be7Sderaadt real_proto = IPPROTO_UDP; 2349df930be7Sderaadt } 2350df930be7Sderaadt if (proto == Q_TCP) { 2351df930be7Sderaadt if (real_proto == IPPROTO_UDP) 2352df930be7Sderaadt bpf_error("port '%s' is udp", name); 2353df930be7Sderaadt else 2354df930be7Sderaadt /* override PROTO_UNDEF */ 2355df930be7Sderaadt real_proto = IPPROTO_TCP; 2356df930be7Sderaadt } 2357a9b0695fSjakob #ifndef INET6 2358df930be7Sderaadt return gen_port(port, real_proto, dir); 2359a9b0695fSjakob #else 2360a9b0695fSjakob { 2361a9b0695fSjakob struct block *b; 2362a9b0695fSjakob b = gen_port(port, real_proto, dir); 2363a9b0695fSjakob gen_or(gen_port6(port, real_proto, dir), b); 2364a9b0695fSjakob return b; 2365a9b0695fSjakob } 2366a9b0695fSjakob #endif /* INET6 */ 2367df930be7Sderaadt 2368df930be7Sderaadt case Q_GATEWAY: 2369a9b0695fSjakob #ifndef INET6 2370df930be7Sderaadt eaddr = pcap_ether_hostton(name); 2371df930be7Sderaadt if (eaddr == NULL) 2372df930be7Sderaadt bpf_error("unknown ether host: %s", name); 2373df930be7Sderaadt 2374df930be7Sderaadt alist = pcap_nametoaddr(name); 2375df930be7Sderaadt if (alist == NULL || *alist == NULL) 2376df930be7Sderaadt bpf_error("unknown host '%s'", name); 2377df930be7Sderaadt return gen_gateway(eaddr, alist, proto, dir); 2378a9b0695fSjakob #else 2379a9b0695fSjakob bpf_error("'gateway' not supported in this configuration"); 2380a9b0695fSjakob #endif /*INET6*/ 2381df930be7Sderaadt 2382df930be7Sderaadt case Q_PROTO: 2383df930be7Sderaadt real_proto = lookup_proto(name, proto); 2384df930be7Sderaadt if (real_proto >= 0) 2385df930be7Sderaadt return gen_proto(real_proto, proto, dir); 2386df930be7Sderaadt else 2387df930be7Sderaadt bpf_error("unknown protocol: %s", name); 2388df930be7Sderaadt 2389a9b0695fSjakob case Q_PROTOCHAIN: 2390a9b0695fSjakob real_proto = lookup_proto(name, proto); 2391a9b0695fSjakob if (real_proto >= 0) 2392a9b0695fSjakob return gen_protochain(real_proto, proto, dir); 2393a9b0695fSjakob else 2394a9b0695fSjakob bpf_error("unknown protocol: %s", name); 2395a9b0695fSjakob 2396a9b0695fSjakob 2397df930be7Sderaadt case Q_UNDEF: 2398df930be7Sderaadt syntax(); 2399df930be7Sderaadt /* NOTREACHED */ 2400df930be7Sderaadt } 2401df930be7Sderaadt abort(); 2402df930be7Sderaadt /* NOTREACHED */ 2403df930be7Sderaadt } 2404df930be7Sderaadt 2405df930be7Sderaadt struct block * 240619fef815Sderaadt gen_mcode(const char *s1, const char *s2, int masklen, struct qual q) 240701efc7efSderaadt { 2408d0438536Smmcc int nlen, mlen; 240901efc7efSderaadt bpf_u_int32 n, m; 241001efc7efSderaadt 241101efc7efSderaadt nlen = __pcap_atoin(s1, &n); 241201efc7efSderaadt /* Promote short ipaddr */ 241301efc7efSderaadt n <<= 32 - nlen; 241401efc7efSderaadt 241501efc7efSderaadt if (s2 != NULL) { 241601efc7efSderaadt mlen = __pcap_atoin(s2, &m); 241701efc7efSderaadt /* Promote short ipaddr */ 241801efc7efSderaadt m <<= 32 - mlen; 241901efc7efSderaadt if ((n & ~m) != 0) 242001efc7efSderaadt bpf_error("non-network bits set in \"%s mask %s\"", 242101efc7efSderaadt s1, s2); 242201efc7efSderaadt } else { 242301efc7efSderaadt /* Convert mask len to mask */ 242401efc7efSderaadt if (masklen > 32) 242501efc7efSderaadt bpf_error("mask length must be <= 32"); 242601efc7efSderaadt m = 0xffffffff << (32 - masklen); 242701efc7efSderaadt if ((n & ~m) != 0) 242801efc7efSderaadt bpf_error("non-network bits set in \"%s/%d\"", 242901efc7efSderaadt s1, masklen); 243001efc7efSderaadt } 243101efc7efSderaadt 243201efc7efSderaadt switch (q.addr) { 243301efc7efSderaadt 243401efc7efSderaadt case Q_NET: 243501efc7efSderaadt return gen_host(n, m, q.proto, q.dir); 243601efc7efSderaadt 243701efc7efSderaadt default: 243801efc7efSderaadt bpf_error("Mask syntax for networks only"); 243901efc7efSderaadt /* NOTREACHED */ 244001efc7efSderaadt } 244101efc7efSderaadt } 244201efc7efSderaadt 244301efc7efSderaadt struct block * 244419fef815Sderaadt gen_ncode(const char *s, bpf_u_int32 v, struct qual q) 2445df930be7Sderaadt { 24469b113833Smickey bpf_u_int32 mask; 2447df930be7Sderaadt int proto = q.proto; 2448df930be7Sderaadt int dir = q.dir; 2449d0438536Smmcc int vlen; 245001efc7efSderaadt 245101efc7efSderaadt if (s == NULL) 245201efc7efSderaadt vlen = 32; 245301efc7efSderaadt else if (q.proto == Q_DECNET) 245401efc7efSderaadt vlen = __pcap_atodn(s, &v); 245501efc7efSderaadt else 245601efc7efSderaadt vlen = __pcap_atoin(s, &v); 2457df930be7Sderaadt 2458df930be7Sderaadt switch (q.addr) { 2459df930be7Sderaadt 2460df930be7Sderaadt case Q_DEFAULT: 2461df930be7Sderaadt case Q_HOST: 2462df930be7Sderaadt case Q_NET: 2463df930be7Sderaadt if (proto == Q_DECNET) 2464df930be7Sderaadt return gen_host(v, 0, proto, dir); 2465df930be7Sderaadt else if (proto == Q_LINK) { 2466df930be7Sderaadt bpf_error("illegal link layer address"); 2467df930be7Sderaadt } else { 246801efc7efSderaadt mask = 0xffffffff; 246901efc7efSderaadt if (s == NULL && q.addr == Q_NET) { 247001efc7efSderaadt /* Promote short net number */ 247101efc7efSderaadt while (v && (v & 0xff000000) == 0) { 247201efc7efSderaadt v <<= 8; 247301efc7efSderaadt mask <<= 8; 247401efc7efSderaadt } 247501efc7efSderaadt } else { 247601efc7efSderaadt /* Promote short ipaddr */ 247701efc7efSderaadt v <<= 32 - vlen; 247801efc7efSderaadt mask <<= 32 - vlen; 247901efc7efSderaadt } 2480df930be7Sderaadt return gen_host(v, mask, proto, dir); 2481df930be7Sderaadt } 2482df930be7Sderaadt 2483df930be7Sderaadt case Q_PORT: 2484df930be7Sderaadt if (proto == Q_UDP) 2485df930be7Sderaadt proto = IPPROTO_UDP; 2486df930be7Sderaadt else if (proto == Q_TCP) 2487df930be7Sderaadt proto = IPPROTO_TCP; 2488df930be7Sderaadt else if (proto == Q_DEFAULT) 2489df930be7Sderaadt proto = PROTO_UNDEF; 2490df930be7Sderaadt else 2491df930be7Sderaadt bpf_error("illegal qualifier of 'port'"); 2492df930be7Sderaadt 2493a9b0695fSjakob #ifndef INET6 2494df930be7Sderaadt return gen_port((int)v, proto, dir); 2495a9b0695fSjakob #else 2496a9b0695fSjakob { 2497a9b0695fSjakob struct block *b; 2498a9b0695fSjakob b = gen_port((int)v, proto, dir); 2499a9b0695fSjakob gen_or(gen_port6((int)v, proto, dir), b); 2500a9b0695fSjakob return b; 2501a9b0695fSjakob } 2502a9b0695fSjakob #endif /* INET6 */ 2503df930be7Sderaadt 2504df930be7Sderaadt case Q_GATEWAY: 2505df930be7Sderaadt bpf_error("'gateway' requires a name"); 2506df930be7Sderaadt /* NOTREACHED */ 2507df930be7Sderaadt 2508df930be7Sderaadt case Q_PROTO: 2509df930be7Sderaadt return gen_proto((int)v, proto, dir); 2510df930be7Sderaadt 2511a9b0695fSjakob case Q_PROTOCHAIN: 2512a9b0695fSjakob return gen_protochain((int)v, proto, dir); 2513a9b0695fSjakob 2514df930be7Sderaadt case Q_UNDEF: 2515df930be7Sderaadt syntax(); 2516df930be7Sderaadt /* NOTREACHED */ 2517df930be7Sderaadt 2518df930be7Sderaadt default: 2519df930be7Sderaadt abort(); 2520df930be7Sderaadt /* NOTREACHED */ 2521df930be7Sderaadt } 2522df930be7Sderaadt /* NOTREACHED */ 2523df930be7Sderaadt } 2524df930be7Sderaadt 2525a9b0695fSjakob #ifdef INET6 2526a9b0695fSjakob struct block * 252719fef815Sderaadt gen_mcode6(const char *s1, const char *s2, int masklen, struct qual q) 2528a9b0695fSjakob { 2529a9b0695fSjakob struct addrinfo *res; 2530a9b0695fSjakob struct in6_addr *addr; 2531a9b0695fSjakob struct in6_addr mask; 2532a9b0695fSjakob struct block *b; 2533a9b0695fSjakob u_int32_t *a, *m; 2534a9b0695fSjakob 2535a9b0695fSjakob if (s2) 2536a9b0695fSjakob bpf_error("no mask %s supported", s2); 2537a9b0695fSjakob 2538a9b0695fSjakob res = pcap_nametoaddrinfo(s1); 2539a9b0695fSjakob if (!res) 2540a9b0695fSjakob bpf_error("invalid ip6 address %s", s1); 2541a9b0695fSjakob if (res->ai_next) 2542a9b0695fSjakob bpf_error("%s resolved to multiple address", s1); 2543a9b0695fSjakob addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 2544a9b0695fSjakob 2545a9b0695fSjakob if (sizeof(mask) * 8 < masklen) 2546a9b0695fSjakob bpf_error("mask length must be <= %u", (unsigned int)(sizeof(mask) * 8)); 25475b39c4fbSbluhm memset(&mask, 0, sizeof(mask)); 2548a9b0695fSjakob memset(&mask, 0xff, masklen / 8); 2549a9b0695fSjakob if (masklen % 8) { 2550a9b0695fSjakob mask.s6_addr[masklen / 8] = 2551a9b0695fSjakob (0xff << (8 - masklen % 8)) & 0xff; 2552a9b0695fSjakob } 2553a9b0695fSjakob 2554a9b0695fSjakob a = (u_int32_t *)addr; 2555a9b0695fSjakob m = (u_int32_t *)&mask; 2556a9b0695fSjakob if ((a[0] & ~m[0]) || (a[1] & ~m[1]) 2557a9b0695fSjakob || (a[2] & ~m[2]) || (a[3] & ~m[3])) { 2558a9b0695fSjakob bpf_error("non-network bits set in \"%s/%d\"", s1, masklen); 2559a9b0695fSjakob } 2560a9b0695fSjakob 2561a9b0695fSjakob switch (q.addr) { 2562a9b0695fSjakob 2563a9b0695fSjakob case Q_DEFAULT: 2564a9b0695fSjakob case Q_HOST: 2565a9b0695fSjakob if (masklen != 128) 2566a9b0695fSjakob bpf_error("Mask syntax for networks only"); 2567a9b0695fSjakob /* FALLTHROUGH */ 2568a9b0695fSjakob 2569a9b0695fSjakob case Q_NET: 2570a9b0695fSjakob b = gen_host6(addr, &mask, q.proto, q.dir); 2571a9b0695fSjakob freeaddrinfo(res); 2572a9b0695fSjakob return b; 2573a9b0695fSjakob 2574a9b0695fSjakob default: 2575a9b0695fSjakob bpf_error("invalid qualifier against IPv6 address"); 2576a9b0695fSjakob /* NOTREACHED */ 2577a9b0695fSjakob } 2578a9b0695fSjakob } 2579a9b0695fSjakob #endif /*INET6*/ 2580a9b0695fSjakob 2581df930be7Sderaadt struct block * 258219fef815Sderaadt gen_ecode(const u_char *eaddr, struct qual q) 2583df930be7Sderaadt { 2584df930be7Sderaadt if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { 2585df930be7Sderaadt if (linktype == DLT_EN10MB) 2586df930be7Sderaadt return gen_ehostop(eaddr, (int)q.dir); 2587df930be7Sderaadt if (linktype == DLT_FDDI) 2588df930be7Sderaadt return gen_fhostop(eaddr, (int)q.dir); 2589d42a50a0Sreyk if (linktype == DLT_IEEE802_11 || 2590d42a50a0Sreyk linktype == DLT_IEEE802_11_RADIO) 2591d42a50a0Sreyk return gen_p80211_hostop(eaddr, (int)q.dir); 2592df930be7Sderaadt } 2593df930be7Sderaadt bpf_error("ethernet address used in non-ether expression"); 2594df930be7Sderaadt /* NOTREACHED */ 2595df930be7Sderaadt } 2596df930be7Sderaadt 2597df930be7Sderaadt void 259819fef815Sderaadt sappend(struct slist *s0, struct slist *s1) 2599df930be7Sderaadt { 2600df930be7Sderaadt /* 2601df930be7Sderaadt * This is definitely not the best way to do this, but the 2602df930be7Sderaadt * lists will rarely get long. 2603df930be7Sderaadt */ 2604df930be7Sderaadt while (s0->next) 2605df930be7Sderaadt s0 = s0->next; 2606df930be7Sderaadt s0->next = s1; 2607df930be7Sderaadt } 2608df930be7Sderaadt 2609df930be7Sderaadt static struct slist * 261019fef815Sderaadt xfer_to_x(struct arth *a) 2611df930be7Sderaadt { 2612df930be7Sderaadt struct slist *s; 2613df930be7Sderaadt 2614df930be7Sderaadt s = new_stmt(BPF_LDX|BPF_MEM); 2615df930be7Sderaadt s->s.k = a->regno; 2616df930be7Sderaadt return s; 2617df930be7Sderaadt } 2618df930be7Sderaadt 2619df930be7Sderaadt static struct slist * 262019fef815Sderaadt xfer_to_a(struct arth *a) 2621df930be7Sderaadt { 2622df930be7Sderaadt struct slist *s; 2623df930be7Sderaadt 2624df930be7Sderaadt s = new_stmt(BPF_LD|BPF_MEM); 2625df930be7Sderaadt s->s.k = a->regno; 2626df930be7Sderaadt return s; 2627df930be7Sderaadt } 2628df930be7Sderaadt 2629df930be7Sderaadt struct arth * 263019fef815Sderaadt gen_load(int proto, struct arth *index, int size) 2631df930be7Sderaadt { 2632df930be7Sderaadt struct slist *s, *tmp; 2633df930be7Sderaadt struct block *b; 2634df930be7Sderaadt int regno = alloc_reg(); 2635df930be7Sderaadt 2636df930be7Sderaadt free_reg(index->regno); 2637df930be7Sderaadt switch (size) { 2638df930be7Sderaadt 2639df930be7Sderaadt default: 2640df930be7Sderaadt bpf_error("data size must be 1, 2, or 4"); 2641df930be7Sderaadt 2642df930be7Sderaadt case 1: 2643df930be7Sderaadt size = BPF_B; 2644df930be7Sderaadt break; 2645df930be7Sderaadt 2646df930be7Sderaadt case 2: 2647df930be7Sderaadt size = BPF_H; 2648df930be7Sderaadt break; 2649df930be7Sderaadt 2650df930be7Sderaadt case 4: 2651df930be7Sderaadt size = BPF_W; 2652df930be7Sderaadt break; 2653df930be7Sderaadt } 2654df930be7Sderaadt switch (proto) { 2655df930be7Sderaadt default: 2656df930be7Sderaadt bpf_error("unsupported index operation"); 2657df930be7Sderaadt 2658df930be7Sderaadt case Q_LINK: 2659df930be7Sderaadt s = xfer_to_x(index); 2660df930be7Sderaadt tmp = new_stmt(BPF_LD|BPF_IND|size); 2661df930be7Sderaadt sappend(s, tmp); 2662df930be7Sderaadt sappend(index->s, s); 2663df930be7Sderaadt break; 2664df930be7Sderaadt 2665df930be7Sderaadt case Q_IP: 2666df930be7Sderaadt case Q_ARP: 2667df930be7Sderaadt case Q_RARP: 266801efc7efSderaadt case Q_ATALK: 2669df930be7Sderaadt case Q_DECNET: 267001efc7efSderaadt case Q_SCA: 2671df930be7Sderaadt case Q_LAT: 2672df930be7Sderaadt case Q_MOPRC: 2673df930be7Sderaadt case Q_MOPDL: 2674a9b0695fSjakob #ifdef INET6 2675a9b0695fSjakob case Q_IPV6: 2676a9b0695fSjakob #endif 2677a9b0695fSjakob /* XXX Note that we assume a fixed link header here. */ 26788d8814c2Scanacar if (variable_nl) { 26798d8814c2Scanacar s = nl2X_stmt(); 26808d8814c2Scanacar sappend(s, xfer_to_a(index)); 26818d8814c2Scanacar sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); 26828d8814c2Scanacar sappend(s, new_stmt(BPF_MISC|BPF_TAX)); 26838d8814c2Scanacar } else { 2684df930be7Sderaadt s = xfer_to_x(index); 26858d8814c2Scanacar } 2686df930be7Sderaadt tmp = new_stmt(BPF_LD|BPF_IND|size); 26878d8814c2Scanacar tmp->s.k = off_nl; /* off_nl == 0 for variable_nl */ 2688df930be7Sderaadt sappend(s, tmp); 2689df930be7Sderaadt sappend(index->s, s); 2690df930be7Sderaadt 2691df930be7Sderaadt b = gen_proto_abbrev(proto); 2692df930be7Sderaadt if (index->b) 2693df930be7Sderaadt gen_and(index->b, b); 2694df930be7Sderaadt index->b = b; 2695df930be7Sderaadt break; 2696df930be7Sderaadt 2697df930be7Sderaadt case Q_TCP: 2698df930be7Sderaadt case Q_UDP: 2699df930be7Sderaadt case Q_ICMP: 27009b113833Smickey case Q_IGMP: 270101efc7efSderaadt case Q_IGRP: 2702a9b0695fSjakob case Q_PIM: 27038d8814c2Scanacar s = iphl_to_x(); 2704df930be7Sderaadt sappend(s, xfer_to_a(index)); 2705df930be7Sderaadt sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X)); 2706df930be7Sderaadt sappend(s, new_stmt(BPF_MISC|BPF_TAX)); 2707df930be7Sderaadt sappend(s, tmp = new_stmt(BPF_LD|BPF_IND|size)); 27088d8814c2Scanacar tmp->s.k = off_nl; /* off_nl is 0 if variable_nl */ 2709df930be7Sderaadt sappend(index->s, s); 2710df930be7Sderaadt 2711df930be7Sderaadt gen_and(gen_proto_abbrev(proto), b = gen_ipfrag()); 2712df930be7Sderaadt if (index->b) 2713df930be7Sderaadt gen_and(index->b, b); 2714a9b0695fSjakob #ifdef INET6 2715a9b0695fSjakob gen_and(gen_proto_abbrev(Q_IP), b); 2716a9b0695fSjakob #endif 2717df930be7Sderaadt index->b = b; 2718df930be7Sderaadt break; 2719a9b0695fSjakob #ifdef INET6 2720a9b0695fSjakob case Q_ICMPV6: 2721a9b0695fSjakob bpf_error("IPv6 upper-layer protocol is not supported by proto[x]"); 2722a9b0695fSjakob /*NOTREACHED*/ 2723a9b0695fSjakob #endif 2724df930be7Sderaadt } 2725df930be7Sderaadt index->regno = regno; 2726df930be7Sderaadt s = new_stmt(BPF_ST); 2727df930be7Sderaadt s->s.k = regno; 2728df930be7Sderaadt sappend(index->s, s); 2729df930be7Sderaadt 2730df930be7Sderaadt return index; 2731df930be7Sderaadt } 2732df930be7Sderaadt 2733df930be7Sderaadt struct block * 273419fef815Sderaadt gen_relation(int code, struct arth *a0, struct arth *a1, int reversed) 2735df930be7Sderaadt { 2736df930be7Sderaadt struct slist *s0, *s1, *s2; 2737df930be7Sderaadt struct block *b, *tmp; 2738df930be7Sderaadt 2739df930be7Sderaadt s0 = xfer_to_x(a1); 2740df930be7Sderaadt s1 = xfer_to_a(a0); 2741df930be7Sderaadt s2 = new_stmt(BPF_ALU|BPF_SUB|BPF_X); 2742df930be7Sderaadt b = new_block(JMP(code)); 27439b113833Smickey if (code == BPF_JGT || code == BPF_JGE) { 27449b113833Smickey reversed = !reversed; 27459b113833Smickey b->s.k = 0x80000000; 27469b113833Smickey } 2747df930be7Sderaadt if (reversed) 2748df930be7Sderaadt gen_not(b); 2749df930be7Sderaadt 2750df930be7Sderaadt sappend(s1, s2); 2751df930be7Sderaadt sappend(s0, s1); 2752df930be7Sderaadt sappend(a1->s, s0); 2753df930be7Sderaadt sappend(a0->s, a1->s); 2754df930be7Sderaadt 2755df930be7Sderaadt b->stmts = a0->s; 2756df930be7Sderaadt 2757df930be7Sderaadt free_reg(a0->regno); 2758df930be7Sderaadt free_reg(a1->regno); 2759df930be7Sderaadt 2760df930be7Sderaadt /* 'and' together protocol checks */ 2761df930be7Sderaadt if (a0->b) { 2762df930be7Sderaadt if (a1->b) { 2763df930be7Sderaadt gen_and(a0->b, tmp = a1->b); 2764df930be7Sderaadt } 2765df930be7Sderaadt else 2766df930be7Sderaadt tmp = a0->b; 2767df930be7Sderaadt } else 2768df930be7Sderaadt tmp = a1->b; 2769df930be7Sderaadt 2770df930be7Sderaadt if (tmp) 2771df930be7Sderaadt gen_and(tmp, b); 2772df930be7Sderaadt 2773df930be7Sderaadt return b; 2774df930be7Sderaadt } 2775df930be7Sderaadt 2776df930be7Sderaadt struct arth * 2777146262eaSjsg gen_loadlen(void) 2778df930be7Sderaadt { 2779df930be7Sderaadt int regno = alloc_reg(); 2780df930be7Sderaadt struct arth *a = (struct arth *)newchunk(sizeof(*a)); 2781df930be7Sderaadt struct slist *s; 2782df930be7Sderaadt 2783df930be7Sderaadt s = new_stmt(BPF_LD|BPF_LEN); 2784df930be7Sderaadt s->next = new_stmt(BPF_ST); 2785df930be7Sderaadt s->next->s.k = regno; 2786df930be7Sderaadt a->s = s; 2787df930be7Sderaadt a->regno = regno; 2788df930be7Sderaadt 2789df930be7Sderaadt return a; 2790df930be7Sderaadt } 2791df930be7Sderaadt 2792df930be7Sderaadt struct arth * 2793146262eaSjsg gen_loadrnd(void) 2794a8e9f808Sdlg { 2795a8e9f808Sdlg int regno = alloc_reg(); 2796a8e9f808Sdlg struct arth *a = (struct arth *)newchunk(sizeof(*a)); 2797a8e9f808Sdlg struct slist *s; 2798a8e9f808Sdlg 2799a8e9f808Sdlg s = new_stmt(BPF_LD|BPF_RND); 2800a8e9f808Sdlg s->next = new_stmt(BPF_ST); 2801a8e9f808Sdlg s->next->s.k = regno; 2802a8e9f808Sdlg a->s = s; 2803a8e9f808Sdlg a->regno = regno; 2804a8e9f808Sdlg 2805a8e9f808Sdlg return a; 2806a8e9f808Sdlg } 2807a8e9f808Sdlg 2808a8e9f808Sdlg struct arth * 280919fef815Sderaadt gen_loadi(int val) 2810df930be7Sderaadt { 2811df930be7Sderaadt struct arth *a; 2812df930be7Sderaadt struct slist *s; 2813df930be7Sderaadt int reg; 2814df930be7Sderaadt 2815df930be7Sderaadt a = (struct arth *)newchunk(sizeof(*a)); 2816df930be7Sderaadt 2817df930be7Sderaadt reg = alloc_reg(); 2818df930be7Sderaadt 2819df930be7Sderaadt s = new_stmt(BPF_LD|BPF_IMM); 2820df930be7Sderaadt s->s.k = val; 2821df930be7Sderaadt s->next = new_stmt(BPF_ST); 2822df930be7Sderaadt s->next->s.k = reg; 2823df930be7Sderaadt a->s = s; 2824df930be7Sderaadt a->regno = reg; 2825df930be7Sderaadt 2826df930be7Sderaadt return a; 2827df930be7Sderaadt } 2828df930be7Sderaadt 2829df930be7Sderaadt struct arth * 283019fef815Sderaadt gen_neg(struct arth *a) 2831df930be7Sderaadt { 2832df930be7Sderaadt struct slist *s; 2833df930be7Sderaadt 2834df930be7Sderaadt s = xfer_to_a(a); 2835df930be7Sderaadt sappend(a->s, s); 2836df930be7Sderaadt s = new_stmt(BPF_ALU|BPF_NEG); 2837df930be7Sderaadt s->s.k = 0; 2838df930be7Sderaadt sappend(a->s, s); 2839df930be7Sderaadt s = new_stmt(BPF_ST); 2840df930be7Sderaadt s->s.k = a->regno; 2841df930be7Sderaadt sappend(a->s, s); 2842df930be7Sderaadt 2843df930be7Sderaadt return a; 2844df930be7Sderaadt } 2845df930be7Sderaadt 2846df930be7Sderaadt struct arth * 284719fef815Sderaadt gen_arth(int code, struct arth *a0, struct arth *a1) 2848df930be7Sderaadt { 2849df930be7Sderaadt struct slist *s0, *s1, *s2; 2850df930be7Sderaadt 2851df930be7Sderaadt s0 = xfer_to_x(a1); 2852df930be7Sderaadt s1 = xfer_to_a(a0); 2853df930be7Sderaadt s2 = new_stmt(BPF_ALU|BPF_X|code); 2854df930be7Sderaadt 2855df930be7Sderaadt sappend(s1, s2); 2856df930be7Sderaadt sappend(s0, s1); 2857df930be7Sderaadt sappend(a1->s, s0); 2858df930be7Sderaadt sappend(a0->s, a1->s); 2859df930be7Sderaadt 2860df930be7Sderaadt free_reg(a1->regno); 2861df930be7Sderaadt 2862df930be7Sderaadt s0 = new_stmt(BPF_ST); 2863df930be7Sderaadt a0->regno = s0->s.k = alloc_reg(); 2864df930be7Sderaadt sappend(a0->s, s0); 2865df930be7Sderaadt 2866df930be7Sderaadt return a0; 2867df930be7Sderaadt } 2868df930be7Sderaadt 2869df930be7Sderaadt /* 2870df930be7Sderaadt * Here we handle simple allocation of the scratch registers. 2871df930be7Sderaadt * If too many registers are alloc'd, the allocator punts. 2872df930be7Sderaadt */ 2873df930be7Sderaadt static int regused[BPF_MEMWORDS]; 2874df930be7Sderaadt static int curreg; 2875df930be7Sderaadt 2876df930be7Sderaadt /* 2877df930be7Sderaadt * Return the next free register. 2878df930be7Sderaadt */ 2879df930be7Sderaadt static int 2880146262eaSjsg alloc_reg(void) 2881df930be7Sderaadt { 2882df930be7Sderaadt int n = BPF_MEMWORDS; 2883df930be7Sderaadt 2884df930be7Sderaadt while (--n >= 0) { 2885df930be7Sderaadt if (regused[curreg]) 2886df930be7Sderaadt curreg = (curreg + 1) % BPF_MEMWORDS; 2887df930be7Sderaadt else { 2888df930be7Sderaadt regused[curreg] = 1; 2889df930be7Sderaadt return curreg; 2890df930be7Sderaadt } 2891df930be7Sderaadt } 2892df930be7Sderaadt bpf_error("too many registers needed to evaluate expression"); 2893df930be7Sderaadt /* NOTREACHED */ 2894df930be7Sderaadt } 2895df930be7Sderaadt 2896df930be7Sderaadt /* 2897df930be7Sderaadt * Return a register to the table so it can 2898df930be7Sderaadt * be used later. 2899df930be7Sderaadt */ 2900df930be7Sderaadt static void 290119fef815Sderaadt free_reg(int n) 2902df930be7Sderaadt { 2903df930be7Sderaadt regused[n] = 0; 2904df930be7Sderaadt } 2905df930be7Sderaadt 2906df930be7Sderaadt static struct block * 290719fef815Sderaadt gen_len(int jmp, int n) 2908df930be7Sderaadt { 2909df930be7Sderaadt struct slist *s; 2910df930be7Sderaadt struct block *b; 2911df930be7Sderaadt 2912df930be7Sderaadt s = new_stmt(BPF_LD|BPF_LEN); 2913df930be7Sderaadt b = new_block(JMP(jmp)); 2914df930be7Sderaadt b->stmts = s; 29159b113833Smickey b->s.k = n; 2916df930be7Sderaadt 2917df930be7Sderaadt return b; 2918df930be7Sderaadt } 2919df930be7Sderaadt 2920df930be7Sderaadt struct block * 292119fef815Sderaadt gen_greater(int n) 2922df930be7Sderaadt { 2923df930be7Sderaadt return gen_len(BPF_JGE, n); 2924df930be7Sderaadt } 2925df930be7Sderaadt 2926df930be7Sderaadt struct block * 292719fef815Sderaadt gen_less(int n) 2928df930be7Sderaadt { 2929df930be7Sderaadt struct block *b; 2930df930be7Sderaadt 2931df930be7Sderaadt b = gen_len(BPF_JGT, n); 2932df930be7Sderaadt gen_not(b); 2933df930be7Sderaadt 2934df930be7Sderaadt return b; 2935df930be7Sderaadt } 2936df930be7Sderaadt 2937df930be7Sderaadt struct block * 293819fef815Sderaadt gen_byteop(int op, int idx, int val) 2939df930be7Sderaadt { 2940df930be7Sderaadt struct block *b; 2941df930be7Sderaadt struct slist *s; 2942df930be7Sderaadt 2943df930be7Sderaadt switch (op) { 2944df930be7Sderaadt default: 2945df930be7Sderaadt abort(); 2946df930be7Sderaadt 2947df930be7Sderaadt case '=': 29489b113833Smickey return gen_cmp((u_int)idx, BPF_B, (bpf_int32)val); 2949df930be7Sderaadt 2950df930be7Sderaadt case '<': 29519b113833Smickey b = gen_cmp((u_int)idx, BPF_B, (bpf_int32)val); 2952df930be7Sderaadt b->s.code = JMP(BPF_JGE); 2953df930be7Sderaadt gen_not(b); 2954df930be7Sderaadt return b; 2955df930be7Sderaadt 2956df930be7Sderaadt case '>': 29579b113833Smickey b = gen_cmp((u_int)idx, BPF_B, (bpf_int32)val); 2958df930be7Sderaadt b->s.code = JMP(BPF_JGT); 2959df930be7Sderaadt return b; 2960df930be7Sderaadt 2961df930be7Sderaadt case '|': 2962df930be7Sderaadt s = new_stmt(BPF_ALU|BPF_OR|BPF_K); 2963df930be7Sderaadt break; 2964df930be7Sderaadt 2965df930be7Sderaadt case '&': 2966df930be7Sderaadt s = new_stmt(BPF_ALU|BPF_AND|BPF_K); 2967df930be7Sderaadt break; 2968df930be7Sderaadt } 2969df930be7Sderaadt s->s.k = val; 2970df930be7Sderaadt b = new_block(JMP(BPF_JEQ)); 2971df930be7Sderaadt b->stmts = s; 2972df930be7Sderaadt gen_not(b); 2973df930be7Sderaadt 2974df930be7Sderaadt return b; 2975df930be7Sderaadt } 2976df930be7Sderaadt 2977df930be7Sderaadt struct block * 297819fef815Sderaadt gen_broadcast(int proto) 2979df930be7Sderaadt { 29809b113833Smickey bpf_u_int32 hostmask; 2981df930be7Sderaadt struct block *b0, *b1, *b2; 2982df930be7Sderaadt static u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 2983df930be7Sderaadt 2984df930be7Sderaadt switch (proto) { 2985df930be7Sderaadt 2986df930be7Sderaadt case Q_DEFAULT: 2987df930be7Sderaadt case Q_LINK: 2988df930be7Sderaadt if (linktype == DLT_EN10MB) 2989df930be7Sderaadt return gen_ehostop(ebroadcast, Q_DST); 2990df930be7Sderaadt if (linktype == DLT_FDDI) 2991df930be7Sderaadt return gen_fhostop(ebroadcast, Q_DST); 2992d42a50a0Sreyk if (linktype == DLT_IEEE802_11 || 2993d42a50a0Sreyk linktype == DLT_IEEE802_11_RADIO) 2994d42a50a0Sreyk return gen_p80211_hostop(ebroadcast, Q_DST); 2995df930be7Sderaadt bpf_error("not a broadcast link"); 2996df930be7Sderaadt break; 2997df930be7Sderaadt 2998df930be7Sderaadt case Q_IP: 2999ff78d6edSsthen /* 3000ff78d6edSsthen * We treat a netmask of PCAP_NETMASK_UNKNOWN (0xffffffff) 3001ff78d6edSsthen * as an indication that we don't know the netmask, and fail 3002ff78d6edSsthen * in that case. 3003ff78d6edSsthen */ 3004ff78d6edSsthen if (netmask == PCAP_NETMASK_UNKNOWN) 3005ff78d6edSsthen bpf_error("netmask not known, so 'ip broadcast' not supported"); 3006df930be7Sderaadt b0 = gen_linktype(ETHERTYPE_IP); 3007df930be7Sderaadt hostmask = ~netmask; 30088d8814c2Scanacar b1 = gen_mcmp_nl(16, BPF_W, (bpf_int32)0, hostmask); 30098d8814c2Scanacar b2 = gen_mcmp_nl(16, BPF_W, 30109b113833Smickey (bpf_int32)(~0 & hostmask), hostmask); 3011df930be7Sderaadt gen_or(b1, b2); 3012df930be7Sderaadt gen_and(b0, b2); 3013df930be7Sderaadt return b2; 3014df930be7Sderaadt } 3015df930be7Sderaadt bpf_error("only ether/ip broadcast filters supported"); 3016df930be7Sderaadt } 3017df930be7Sderaadt 3018df930be7Sderaadt struct block * 301919fef815Sderaadt gen_multicast(int proto) 3020df930be7Sderaadt { 3021d0438536Smmcc struct block *b0, *b1; 3022d0438536Smmcc struct slist *s; 3023df930be7Sderaadt 3024df930be7Sderaadt switch (proto) { 3025df930be7Sderaadt 3026df930be7Sderaadt case Q_DEFAULT: 3027df930be7Sderaadt case Q_LINK: 3028df930be7Sderaadt if (linktype == DLT_EN10MB) { 3029df930be7Sderaadt /* ether[0] & 1 != 0 */ 3030df930be7Sderaadt s = new_stmt(BPF_LD|BPF_B|BPF_ABS); 3031df930be7Sderaadt s->s.k = 0; 3032df930be7Sderaadt b0 = new_block(JMP(BPF_JSET)); 3033df930be7Sderaadt b0->s.k = 1; 3034df930be7Sderaadt b0->stmts = s; 3035df930be7Sderaadt return b0; 3036df930be7Sderaadt } 3037df930be7Sderaadt 3038df930be7Sderaadt if (linktype == DLT_FDDI) { 3039df930be7Sderaadt /* XXX TEST THIS: MIGHT NOT PORT PROPERLY XXX */ 3040df930be7Sderaadt /* fddi[1] & 1 != 0 */ 3041df930be7Sderaadt s = new_stmt(BPF_LD|BPF_B|BPF_ABS); 3042df930be7Sderaadt s->s.k = 1; 3043df930be7Sderaadt b0 = new_block(JMP(BPF_JSET)); 3044df930be7Sderaadt b0->s.k = 1; 3045df930be7Sderaadt b0->stmts = s; 3046df930be7Sderaadt return b0; 3047df930be7Sderaadt } 3048df930be7Sderaadt /* Link not known to support multicasts */ 3049df930be7Sderaadt break; 3050df930be7Sderaadt 3051df930be7Sderaadt case Q_IP: 3052df930be7Sderaadt b0 = gen_linktype(ETHERTYPE_IP); 30538d8814c2Scanacar b1 = gen_cmp_nl(16, BPF_B, (bpf_int32)224); 3054df930be7Sderaadt b1->s.code = JMP(BPF_JGE); 3055df930be7Sderaadt gen_and(b0, b1); 3056df930be7Sderaadt return b1; 3057a9b0695fSjakob 3058a9b0695fSjakob #ifdef INET6 3059a9b0695fSjakob case Q_IPV6: 3060a9b0695fSjakob b0 = gen_linktype(ETHERTYPE_IPV6); 30618d8814c2Scanacar b1 = gen_cmp_nl(24, BPF_B, (bpf_int32)255); 3062a9b0695fSjakob gen_and(b0, b1); 3063a9b0695fSjakob return b1; 3064a9b0695fSjakob #endif /* INET6 */ 3065df930be7Sderaadt } 3066df930be7Sderaadt bpf_error("only IP multicast filters supported on ethernet/FDDI"); 3067df930be7Sderaadt } 3068df930be7Sderaadt 3069df930be7Sderaadt /* 3070df930be7Sderaadt * generate command for inbound/outbound. It's here so we can 3071df930be7Sderaadt * make it link-type specific. 'dir' = 0 implies "inbound", 3072df930be7Sderaadt * = 1 implies "outbound". 3073df930be7Sderaadt */ 3074df930be7Sderaadt struct block * 307519fef815Sderaadt gen_inbound(int dir) 3076df930be7Sderaadt { 3077d0438536Smmcc struct block *b0; 3078df930be7Sderaadt 3079a9b0695fSjakob /* 3080a9b0695fSjakob * Only SLIP and old-style PPP data link types support 3081a9b0695fSjakob * inbound/outbound qualifiers. 3082a9b0695fSjakob */ 3083a9b0695fSjakob switch (linktype) { 3084a9b0695fSjakob case DLT_SLIP: 3085a9b0695fSjakob case DLT_PPP: 3086e83aed87Sfrantzen b0 = gen_relation(BPF_JEQ, 3087e83aed87Sfrantzen gen_load(Q_LINK, gen_loadi(0), 1), 3088e83aed87Sfrantzen gen_loadi(0), 3089e83aed87Sfrantzen dir); 3090e83aed87Sfrantzen break; 3091e83aed87Sfrantzen 3092e83aed87Sfrantzen case DLT_PFLOG: 3093263bcd0cScanacar b0 = gen_cmp(offsetof(struct pfloghdr, dir), BPF_B, 3094263bcd0cScanacar (bpf_int32)((dir == 0) ? PF_IN : PF_OUT)); 3095263bcd0cScanacar break; 3096263bcd0cScanacar 3097a9b0695fSjakob default: 3098abbdc6b6Sreyk bpf_error("inbound/outbound not supported on linktype 0x%x", 3099a9b0695fSjakob linktype); 3100a9b0695fSjakob /* NOTREACHED */ 3101a9b0695fSjakob } 3102a9b0695fSjakob 3103e83aed87Sfrantzen return (b0); 3104e83aed87Sfrantzen } 3105e83aed87Sfrantzen 3106e83aed87Sfrantzen 3107e83aed87Sfrantzen /* PF firewall log matched interface */ 3108e83aed87Sfrantzen struct block * 3109e83aed87Sfrantzen gen_pf_ifname(char *ifname) 3110e83aed87Sfrantzen { 3111e83aed87Sfrantzen struct block *b0; 3112263bcd0cScanacar u_int len, off; 3113e83aed87Sfrantzen 3114263bcd0cScanacar if (linktype == DLT_PFLOG) { 3115263bcd0cScanacar len = sizeof(((struct pfloghdr *)0)->ifname); 3116263bcd0cScanacar off = offsetof(struct pfloghdr, ifname); 3117263bcd0cScanacar } else { 3118abbdc6b6Sreyk bpf_error("ifname not supported on linktype 0x%x", linktype); 3119e83aed87Sfrantzen /* NOTREACHED */ 3120e83aed87Sfrantzen } 3121263bcd0cScanacar if (strlen(ifname) >= len) { 3122abbdc6b6Sreyk bpf_error("ifname interface names can only be %d characters", 3123263bcd0cScanacar len - 1); 3124e83aed87Sfrantzen /* NOTREACHED */ 3125e83aed87Sfrantzen } 3126daa036abSdlg b0 = gen_bcmp(off, strlen(ifname) + 1, ifname); 3127263bcd0cScanacar return (b0); 3128263bcd0cScanacar } 3129263bcd0cScanacar 3130263bcd0cScanacar 313163c47f2fSjoel /* PF firewall log ruleset name */ 3132263bcd0cScanacar struct block * 3133263bcd0cScanacar gen_pf_ruleset(char *ruleset) 3134263bcd0cScanacar { 3135263bcd0cScanacar struct block *b0; 3136263bcd0cScanacar 3137263bcd0cScanacar if (linktype != DLT_PFLOG) { 3138abbdc6b6Sreyk bpf_error("ruleset not supported on linktype 0x%x", linktype); 3139263bcd0cScanacar /* NOTREACHED */ 3140263bcd0cScanacar } 3141263bcd0cScanacar if (strlen(ruleset) >= sizeof(((struct pfloghdr *)0)->ruleset)) { 31421717b5a3Schl bpf_error("ruleset names can only be %zu characters", 3143263bcd0cScanacar sizeof(((struct pfloghdr *)0)->ruleset) - 1); 3144263bcd0cScanacar /* NOTREACHED */ 3145263bcd0cScanacar } 3146263bcd0cScanacar b0 = gen_bcmp(offsetof(struct pfloghdr, ruleset), 3147263bcd0cScanacar strlen(ruleset), ruleset); 3148e83aed87Sfrantzen return (b0); 3149e83aed87Sfrantzen } 3150e83aed87Sfrantzen 3151e83aed87Sfrantzen 3152e83aed87Sfrantzen /* PF firewall log rule number */ 3153e83aed87Sfrantzen struct block * 3154e83aed87Sfrantzen gen_pf_rnr(int rnr) 3155e83aed87Sfrantzen { 3156e83aed87Sfrantzen struct block *b0; 3157e83aed87Sfrantzen 3158263bcd0cScanacar if (linktype == DLT_PFLOG) { 3159263bcd0cScanacar b0 = gen_cmp(offsetof(struct pfloghdr, rulenr), BPF_W, 3160263bcd0cScanacar (bpf_int32)rnr); 3161263bcd0cScanacar } else { 3162abbdc6b6Sreyk bpf_error("rnr not supported on linktype 0x%x", linktype); 3163e83aed87Sfrantzen /* NOTREACHED */ 3164e83aed87Sfrantzen } 3165e83aed87Sfrantzen 3166263bcd0cScanacar return (b0); 3167263bcd0cScanacar } 3168263bcd0cScanacar 3169263bcd0cScanacar 3170263bcd0cScanacar /* PF firewall log sub-rule number */ 3171263bcd0cScanacar struct block * 3172263bcd0cScanacar gen_pf_srnr(int srnr) 3173263bcd0cScanacar { 3174263bcd0cScanacar struct block *b0; 3175263bcd0cScanacar 3176263bcd0cScanacar if (linktype != DLT_PFLOG) { 3177abbdc6b6Sreyk bpf_error("srnr not supported on linktype 0x%x", linktype); 3178263bcd0cScanacar /* NOTREACHED */ 3179263bcd0cScanacar } 3180263bcd0cScanacar 3181263bcd0cScanacar b0 = gen_cmp(offsetof(struct pfloghdr, subrulenr), BPF_W, 3182263bcd0cScanacar (bpf_int32)srnr); 3183e83aed87Sfrantzen return (b0); 3184e83aed87Sfrantzen } 3185e83aed87Sfrantzen 3186e83aed87Sfrantzen /* PF firewall log reason code */ 3187e83aed87Sfrantzen struct block * 3188e83aed87Sfrantzen gen_pf_reason(int reason) 3189e83aed87Sfrantzen { 3190e83aed87Sfrantzen struct block *b0; 3191e83aed87Sfrantzen 3192263bcd0cScanacar if (linktype == DLT_PFLOG) { 3193263bcd0cScanacar b0 = gen_cmp(offsetof(struct pfloghdr, reason), BPF_B, 3194263bcd0cScanacar (bpf_int32)reason); 3195263bcd0cScanacar } else { 3196abbdc6b6Sreyk bpf_error("reason not supported on linktype 0x%x", linktype); 3197e83aed87Sfrantzen /* NOTREACHED */ 3198e83aed87Sfrantzen } 3199e83aed87Sfrantzen 3200e83aed87Sfrantzen return (b0); 3201e83aed87Sfrantzen } 3202e83aed87Sfrantzen 3203e83aed87Sfrantzen /* PF firewall log action */ 3204e83aed87Sfrantzen struct block * 3205e83aed87Sfrantzen gen_pf_action(int action) 3206e83aed87Sfrantzen { 3207e83aed87Sfrantzen struct block *b0; 3208e83aed87Sfrantzen 3209263bcd0cScanacar if (linktype == DLT_PFLOG) { 3210263bcd0cScanacar b0 = gen_cmp(offsetof(struct pfloghdr, action), BPF_B, 3211263bcd0cScanacar (bpf_int32)action); 3212263bcd0cScanacar } else { 3213abbdc6b6Sreyk bpf_error("action not supported on linktype 0x%x", linktype); 3214e83aed87Sfrantzen /* NOTREACHED */ 3215e83aed87Sfrantzen } 3216e83aed87Sfrantzen 3217df930be7Sderaadt return (b0); 3218df930be7Sderaadt } 3219d42a50a0Sreyk 3220d42a50a0Sreyk /* IEEE 802.11 wireless header */ 3221d42a50a0Sreyk struct block * 3222d42a50a0Sreyk gen_p80211_type(int type, int mask) 3223d42a50a0Sreyk { 3224d42a50a0Sreyk struct block *b0; 3225d42a50a0Sreyk u_int offset; 3226d42a50a0Sreyk 3227d42a50a0Sreyk if (!(linktype == DLT_IEEE802_11 || 3228d42a50a0Sreyk linktype == DLT_IEEE802_11_RADIO)) { 3229d42a50a0Sreyk bpf_error("type not supported on linktype 0x%x", 3230d42a50a0Sreyk linktype); 3231d42a50a0Sreyk /* NOTREACHED */ 3232d42a50a0Sreyk } 3233d42a50a0Sreyk offset = (u_int)offsetof(struct ieee80211_frame, i_fc[0]); 3234d42a50a0Sreyk if (linktype == DLT_IEEE802_11_RADIO) 3235d42a50a0Sreyk offset += IEEE80211_RADIOTAP_HDRLEN; 3236d42a50a0Sreyk 3237d42a50a0Sreyk b0 = gen_mcmp(offset, BPF_B, (bpf_int32)type, (bpf_u_int32)mask); 3238d42a50a0Sreyk 3239d42a50a0Sreyk return (b0); 3240d42a50a0Sreyk } 3241d42a50a0Sreyk 3242febc6dcdSdtucker static struct block * 324319fef815Sderaadt gen_ahostop(const u_char *eaddr, int dir) 3244febc6dcdSdtucker { 3245d0438536Smmcc struct block *b0, *b1; 3246febc6dcdSdtucker 3247febc6dcdSdtucker switch (dir) { 3248febc6dcdSdtucker /* src comes first, different from Ethernet */ 3249febc6dcdSdtucker case Q_SRC: 3250febc6dcdSdtucker return gen_bcmp(0, 1, eaddr); 3251febc6dcdSdtucker 3252febc6dcdSdtucker case Q_DST: 3253febc6dcdSdtucker return gen_bcmp(1, 1, eaddr); 3254febc6dcdSdtucker 3255febc6dcdSdtucker case Q_AND: 3256febc6dcdSdtucker b0 = gen_ahostop(eaddr, Q_SRC); 3257febc6dcdSdtucker b1 = gen_ahostop(eaddr, Q_DST); 3258febc6dcdSdtucker gen_and(b0, b1); 3259febc6dcdSdtucker return b1; 3260febc6dcdSdtucker 3261febc6dcdSdtucker case Q_DEFAULT: 3262febc6dcdSdtucker case Q_OR: 3263febc6dcdSdtucker b0 = gen_ahostop(eaddr, Q_SRC); 3264febc6dcdSdtucker b1 = gen_ahostop(eaddr, Q_DST); 3265febc6dcdSdtucker gen_or(b0, b1); 3266febc6dcdSdtucker return b1; 3267febc6dcdSdtucker } 3268febc6dcdSdtucker abort(); 3269febc6dcdSdtucker /* NOTREACHED */ 3270febc6dcdSdtucker } 3271febc6dcdSdtucker 32726b5a0ec1Sderaadt struct block * 327319fef815Sderaadt gen_acode(const u_char *eaddr, struct qual q) 32746b5a0ec1Sderaadt { 32756b5a0ec1Sderaadt if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { 32766b5a0ec1Sderaadt if (linktype == DLT_ARCNET) 32776b5a0ec1Sderaadt return gen_ahostop(eaddr, (int)q.dir); 32786b5a0ec1Sderaadt } 32796b5a0ec1Sderaadt bpf_error("ARCnet address used in non-arc expression"); 32806b5a0ec1Sderaadt /* NOTREACHED */ 32816b5a0ec1Sderaadt } 32826b5a0ec1Sderaadt 3283ff52dd4aSdenis struct block * 328419fef815Sderaadt gen_mpls(int label) 3285ff52dd4aSdenis { 3286ff52dd4aSdenis struct block *b0; 3287ff52dd4aSdenis 3288ff52dd4aSdenis if (label > MPLS_LABEL_MAX) 3289ff52dd4aSdenis bpf_error("invalid MPLS label : %d", label); 3290ff52dd4aSdenis 3291ff52dd4aSdenis if (mpls_stack > 0) /* Bottom-Of-Label-Stack bit ? */ 3292ff52dd4aSdenis b0 = gen_mcmp(off_nl-2, BPF_B, (bpf_int32)0, 0x1); 3293ff52dd4aSdenis else 3294ff52dd4aSdenis b0 = gen_linktype(ETHERTYPE_MPLS); 3295ff52dd4aSdenis 3296ff52dd4aSdenis if (label >= 0) { 3297ff52dd4aSdenis struct block *b1; 3298ff52dd4aSdenis 3299ff52dd4aSdenis b1 = gen_mcmp(off_nl, BPF_W, (bpf_int32)(label << 12), 3300ff52dd4aSdenis MPLS_LABEL_MASK); 3301ff52dd4aSdenis gen_and(b0, b1); 3302ff52dd4aSdenis b0 = b1; 3303ff52dd4aSdenis } 3304ff52dd4aSdenis off_nl += 4; 3305ff52dd4aSdenis off_linktype += 4; 3306ff52dd4aSdenis mpls_stack++; 3307ff52dd4aSdenis return (b0); 3308ff52dd4aSdenis } 3309ff52dd4aSdenis 3310febc6dcdSdtucker /* 3311febc6dcdSdtucker * support IEEE 802.1Q VLAN trunk over ethernet 3312febc6dcdSdtucker */ 3313febc6dcdSdtucker struct block * 331419fef815Sderaadt gen_vlan(int vlan_num) 3315febc6dcdSdtucker { 3316febc6dcdSdtucker struct block *b0; 3317febc6dcdSdtucker 33188d8814c2Scanacar if (variable_nl) { 33198d8814c2Scanacar bpf_error("'vlan' not supported for variable DLTs"); 33208d8814c2Scanacar /*NOTREACHED*/ 33218d8814c2Scanacar } 33228d8814c2Scanacar 33234f6bb374Sdenis if (vlan_num > 4095) { 33244f6bb374Sdenis bpf_error("invalid VLAN number : %d", vlan_num); 33254f6bb374Sdenis /*NOTREACHED*/ 33264f6bb374Sdenis } 33274f6bb374Sdenis 3328febc6dcdSdtucker /* 3329febc6dcdSdtucker * Change the offsets to point to the type and data fields within 3330febc6dcdSdtucker * the VLAN packet. This is somewhat of a kludge. 3331febc6dcdSdtucker */ 3332febc6dcdSdtucker if (orig_nl == (u_int)-1) { 3333febc6dcdSdtucker orig_linktype = off_linktype; /* save original values */ 3334febc6dcdSdtucker orig_nl = off_nl; 3335febc6dcdSdtucker orig_nl_nosnap = off_nl_nosnap; 3336febc6dcdSdtucker 3337febc6dcdSdtucker switch (linktype) { 3338febc6dcdSdtucker 3339febc6dcdSdtucker case DLT_EN10MB: 3340febc6dcdSdtucker off_linktype = 16; 3341febc6dcdSdtucker off_nl_nosnap = 18; 3342febc6dcdSdtucker off_nl = 18; 3343febc6dcdSdtucker break; 3344febc6dcdSdtucker 3345febc6dcdSdtucker default: 3346febc6dcdSdtucker bpf_error("no VLAN support for data link type %d", 3347febc6dcdSdtucker linktype); 3348febc6dcdSdtucker /*NOTREACHED*/ 3349febc6dcdSdtucker } 3350febc6dcdSdtucker } 3351febc6dcdSdtucker 3352febc6dcdSdtucker /* check for VLAN */ 3353febc6dcdSdtucker b0 = gen_cmp(orig_linktype, BPF_H, (bpf_int32)ETHERTYPE_8021Q); 3354febc6dcdSdtucker 3355febc6dcdSdtucker /* If a specific VLAN is requested, check VLAN id */ 3356febc6dcdSdtucker if (vlan_num >= 0) { 3357febc6dcdSdtucker struct block *b1; 3358febc6dcdSdtucker 33594f6bb374Sdenis b1 = gen_mcmp(orig_nl, BPF_H, (bpf_int32)vlan_num, 0x0FFF); 3360febc6dcdSdtucker gen_and(b0, b1); 3361febc6dcdSdtucker b0 = b1; 3362febc6dcdSdtucker } 3363febc6dcdSdtucker 3364febc6dcdSdtucker return (b0); 3365febc6dcdSdtucker } 3366febc6dcdSdtucker 3367febc6dcdSdtucker struct block * 33682cba36b5Sdlg gen_sample(int rate) 33692cba36b5Sdlg { 33702cba36b5Sdlg struct block *b0; 33712cba36b5Sdlg long long threshold = 0x100000000LL; /* 0xffffffff + 1 */ 33722cba36b5Sdlg 33732cba36b5Sdlg if (rate < 2) { 33742cba36b5Sdlg bpf_error("sample %d is too low", rate); 33752cba36b5Sdlg /*NOTREACHED*/ 33762cba36b5Sdlg } 33772cba36b5Sdlg if (rate > (1 << 20)) { 33782cba36b5Sdlg bpf_error("sample %d is too high", rate); 33792cba36b5Sdlg /*NOTREACHED*/ 33802cba36b5Sdlg } 33812cba36b5Sdlg 33822cba36b5Sdlg threshold /= rate; 33832cba36b5Sdlg b0 = gen_relation(BPF_JGT, gen_loadrnd(), gen_loadi(threshold), 1); 33842cba36b5Sdlg 33852cba36b5Sdlg return (b0); 33862cba36b5Sdlg } 33872cba36b5Sdlg 33882cba36b5Sdlg struct block * 3389d42a50a0Sreyk gen_p80211_fcdir(int fcdir) 3390d42a50a0Sreyk { 3391d42a50a0Sreyk struct block *b0; 3392d42a50a0Sreyk u_int offset; 3393d42a50a0Sreyk 3394d42a50a0Sreyk if (!(linktype == DLT_IEEE802_11 || 3395d42a50a0Sreyk linktype == DLT_IEEE802_11_RADIO)) { 3396d42a50a0Sreyk bpf_error("frame direction not supported on linktype 0x%x", 3397d42a50a0Sreyk linktype); 3398d42a50a0Sreyk /* NOTREACHED */ 3399d42a50a0Sreyk } 3400d42a50a0Sreyk offset = (u_int)offsetof(struct ieee80211_frame, i_fc[1]); 3401d42a50a0Sreyk if (linktype == DLT_IEEE802_11_RADIO) 3402d42a50a0Sreyk offset += IEEE80211_RADIOTAP_HDRLEN; 3403d42a50a0Sreyk 3404d42a50a0Sreyk b0 = gen_mcmp(offset, BPF_B, (bpf_int32)fcdir, 3405d42a50a0Sreyk (bpf_u_int32)IEEE80211_FC1_DIR_MASK); 3406d42a50a0Sreyk 3407d42a50a0Sreyk return (b0); 3408d42a50a0Sreyk } 3409d42a50a0Sreyk 3410d42a50a0Sreyk static struct block * 3411d42a50a0Sreyk gen_p80211_hostop(const u_char *lladdr, int dir) 3412d42a50a0Sreyk { 3413d42a50a0Sreyk struct block *b0, *b1, *b2, *b3, *b4; 3414d42a50a0Sreyk u_int offset = 0; 3415d42a50a0Sreyk 3416d42a50a0Sreyk if (linktype == DLT_IEEE802_11_RADIO) 3417d42a50a0Sreyk offset = IEEE80211_RADIOTAP_HDRLEN; 3418d42a50a0Sreyk 3419d42a50a0Sreyk switch (dir) { 3420d42a50a0Sreyk case Q_SRC: 3421d42a50a0Sreyk b0 = gen_p80211_addr(IEEE80211_FC1_DIR_NODS, offset + 3422d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame, i_addr2), 3423d42a50a0Sreyk lladdr); 3424d42a50a0Sreyk b1 = gen_p80211_addr(IEEE80211_FC1_DIR_TODS, offset + 3425d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame, i_addr2), 3426d42a50a0Sreyk lladdr); 3427d42a50a0Sreyk b2 = gen_p80211_addr(IEEE80211_FC1_DIR_FROMDS, offset + 3428d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame, i_addr3), 3429d42a50a0Sreyk lladdr); 3430d42a50a0Sreyk b3 = gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset + 3431d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame_addr4, i_addr4), 3432d42a50a0Sreyk lladdr); 3433d42a50a0Sreyk b4 = gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset + 3434d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame_addr4, i_addr2), 3435d42a50a0Sreyk lladdr); 3436d42a50a0Sreyk 3437d42a50a0Sreyk gen_or(b0, b1); 3438d42a50a0Sreyk gen_or(b1, b2); 3439d42a50a0Sreyk gen_or(b2, b3); 3440d42a50a0Sreyk gen_or(b3, b4); 3441d42a50a0Sreyk return (b4); 3442d42a50a0Sreyk 3443d42a50a0Sreyk case Q_DST: 3444d42a50a0Sreyk b0 = gen_p80211_addr(IEEE80211_FC1_DIR_NODS, offset + 3445d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame, i_addr1), 3446d42a50a0Sreyk lladdr); 3447d42a50a0Sreyk b1 = gen_p80211_addr(IEEE80211_FC1_DIR_TODS, offset + 3448d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame, i_addr3), 3449d42a50a0Sreyk lladdr); 3450d42a50a0Sreyk b2 = gen_p80211_addr(IEEE80211_FC1_DIR_FROMDS, offset + 3451d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame, i_addr1), 3452d42a50a0Sreyk lladdr); 3453d42a50a0Sreyk b3 = gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset + 3454d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame_addr4, i_addr3), 3455d42a50a0Sreyk lladdr); 3456d42a50a0Sreyk b4 = gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset + 3457d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame_addr4, i_addr1), 3458d42a50a0Sreyk lladdr); 3459d42a50a0Sreyk 3460d42a50a0Sreyk gen_or(b0, b1); 3461d42a50a0Sreyk gen_or(b1, b2); 3462d42a50a0Sreyk gen_or(b2, b3); 3463d42a50a0Sreyk gen_or(b3, b4); 3464d42a50a0Sreyk return (b4); 3465d42a50a0Sreyk 3466d42a50a0Sreyk case Q_ADDR1: 3467d42a50a0Sreyk return (gen_bcmp(offset + 3468d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame, 3469d42a50a0Sreyk i_addr1), IEEE80211_ADDR_LEN, lladdr)); 3470d42a50a0Sreyk 3471d42a50a0Sreyk case Q_ADDR2: 3472d42a50a0Sreyk return (gen_bcmp(offset + 3473d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame, 3474d42a50a0Sreyk i_addr2), IEEE80211_ADDR_LEN, lladdr)); 3475d42a50a0Sreyk 3476d42a50a0Sreyk case Q_ADDR3: 3477d42a50a0Sreyk return (gen_bcmp(offset + 3478d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame, 3479d42a50a0Sreyk i_addr3), IEEE80211_ADDR_LEN, lladdr)); 3480d42a50a0Sreyk 3481d42a50a0Sreyk case Q_ADDR4: 3482d42a50a0Sreyk return (gen_p80211_addr(IEEE80211_FC1_DIR_DSTODS, offset + 3483d42a50a0Sreyk (u_int)offsetof(struct ieee80211_frame_addr4, i_addr4), 3484d42a50a0Sreyk lladdr)); 3485d42a50a0Sreyk 3486d42a50a0Sreyk case Q_AND: 3487d42a50a0Sreyk b0 = gen_p80211_hostop(lladdr, Q_SRC); 3488d42a50a0Sreyk b1 = gen_p80211_hostop(lladdr, Q_DST); 3489d42a50a0Sreyk gen_and(b0, b1); 3490d42a50a0Sreyk return (b1); 3491d42a50a0Sreyk 3492d42a50a0Sreyk case Q_DEFAULT: 3493d42a50a0Sreyk case Q_OR: 3494d42a50a0Sreyk b0 = gen_p80211_hostop(lladdr, Q_ADDR1); 3495d42a50a0Sreyk b1 = gen_p80211_hostop(lladdr, Q_ADDR2); 3496d42a50a0Sreyk b2 = gen_p80211_hostop(lladdr, Q_ADDR3); 3497d42a50a0Sreyk b3 = gen_p80211_hostop(lladdr, Q_ADDR4); 3498d42a50a0Sreyk gen_or(b0, b1); 3499d42a50a0Sreyk gen_or(b1, b2); 3500d42a50a0Sreyk gen_or(b2, b3); 3501d42a50a0Sreyk return (b3); 3502d42a50a0Sreyk 3503d42a50a0Sreyk default: 3504d42a50a0Sreyk bpf_error("direction not supported on linktype 0x%x", 3505d42a50a0Sreyk linktype); 3506d42a50a0Sreyk } 3507d42a50a0Sreyk /* NOTREACHED */ 3508d42a50a0Sreyk } 3509d42a50a0Sreyk 3510d42a50a0Sreyk static struct block * 3511d42a50a0Sreyk gen_p80211_addr(int fcdir, u_int offset, const u_char *lladdr) 3512d42a50a0Sreyk { 3513d42a50a0Sreyk struct block *b0, *b1; 3514d42a50a0Sreyk 3515d42a50a0Sreyk b0 = gen_mcmp(offset, BPF_B, (bpf_int32)fcdir, IEEE80211_FC1_DIR_MASK); 3516d42a50a0Sreyk b1 = gen_bcmp(offset, IEEE80211_ADDR_LEN, lladdr); 3517d42a50a0Sreyk gen_and(b0, b1); 3518d42a50a0Sreyk 3519d42a50a0Sreyk return (b1); 3520d42a50a0Sreyk } 3521