gencode.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,268 行 · 第 1/2 页
C
1,268 行
/* * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * SCCSID: @(#)gencode.c 4.1 ULTRIX 1/25/91 * Based on: * rcsid[] = "@(#) $Header: gencode.c,v 1.21 91/01/10 17:23:41 mccanne Exp $ (LBL)" */#ifdef __STDC__#include <stdlib.h>#endif#include <sys/types.h>#include <sys/socket.h>#include <net/if.h>#include <netinet/in.h>#include <netinet/if_ether.h>#include <sys/time.h>#include <net/bpf.h>#include "interface.h"#include "gencode.h"#include "nametoaddr.h"#include "extract.h"extern struct bpf_insn *icode_to_fcode();extern u_long net_mask();static void init_linktype();static int alloc_reg();static void free_reg();static struct block *root;/* * We divy out chunks of memory rather than call malloc each time so * we don't have to worry about leaking memory. It's probably * not a big deal if all this memory was wasted but it this ever * goes into a library that would probably not be a good idea. */#define NCHUNKS 16#define CHUNK0SIZE 1024struct chunk { u_int n_left; void *m;};static struct chunk chunks[NCHUNKS];static int cur_chunk;static void *newchunk(n) u_int n;{ struct chunk *cp; int k, size; /* XXX Round up to nearest long. */ n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1); cp = &chunks[cur_chunk]; if (n > cp->n_left) { ++cp, k = ++cur_chunk; if (k >= NCHUNKS) error("newchunk: out of chunks"); size = CHUNK0SIZE << k; cp->m = (void *)malloc(size); bzero((char *)cp->m, size); cp->n_left = size; if (n > size) error("newchunk: request too big"); } cp->n_left -= n; return (void *)((char *)cp->m + cp->n_left);}static voidfreechunks(){ int i; for (i = 0; i < NCHUNKS; ++i) if (chunks[i].m) free(chunks[i].m);}static inline struct block *new_block(code) enum bpf_code code;{ struct block *p; p = (struct block *)newchunk(sizeof(*p)); p->s.code = code; p->head = p; return p;}static inline struct slist *new_stmt(code) enum bpf_code code;{ struct slist *p; p = (struct slist *)newchunk(sizeof(*p)); p->s.code = code; return p;}static struct block *gen_retblk(v) int v;{ struct block *b = new_block(RetOp); b->s.k = v; return b;}struct bpf_program *parse(buf, Oflag, linktype) char *buf; int Oflag; int linktype;{ extern int n_errors; static struct bpf_program F; struct bpf_insn *p; int len; F.bf_insns = 0; F.bf_len = 0; lex_init(buf ? buf : ""); init_linktype(linktype); yyparse(); if (n_errors) error("expression syntax error"); if (root == 0) root = gen_retblk(snaplen); if (Oflag) { optimize(&root); if (root == 0 || (root->s.code == RetOp && root->s.k == 0)) error("expression rejects all packets"); } p = icode_to_fcode(root, &len); F.bf_insns = p; F.bf_len = len; freechunks(); return &F;}/* * Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates * which of the jt and jf fields has been resolved and which is a pointer * back to another unresolved block (or nil). At least one of the fields * in each block is already resolved. */static voidbackpatch(list, target) struct block *list, *target;{ struct block *next; while (list) { if (!list->sense) { next = list->jt; list->jt = target; } else { next = list->jf; list->jf = target; } list = next; }}/* * Merge the lists in b0 and b1, using the 'sense' field to indicate * which of jt and jf is the link. */static voidmerge(b0, b1) struct block *b0, *b1;{ register struct block **p = &b0; /* Find end of list. */ while (*p) p = !((*p)->sense) ? &(*p)->jt : &(*p)->jf; /* Concatenate the lists. */ *p = b1;}voidfinish_parse(p) struct block *p;{ backpatch(p, gen_retblk(snaplen)); p->sense = !p->sense; backpatch(p, gen_retblk(0)); root = p->head;}voidgen_and(b0, b1) struct block *b0, *b1;{ backpatch(b0, b1->head); b0->sense = !b0->sense; b1->sense = !b1->sense; merge(b1, b0); b1->sense = !b1->sense; b1->head = b0->head;}voidgen_or(b0, b1) struct block *b0, *b1;{ b0->sense = !b0->sense; backpatch(b0, b1->head); b0->sense = !b0->sense; merge(b1, b0); b1->head = b0->head;}voidgen_not(b) struct block *b;{ b->sense = !b->sense;}static enum bpf_code ldop_from_size[] = { NopOp, LdBOp, LdHOp, NopOp, LdOp };static enum bpf_code ildop_from_size[] = { NopOp, ILdBOp, ILdHOp, NopOp, ILdOp };static struct block *gen_cmp(offset, size, v) u_int offset, size; long v;{ struct slist *s; struct block *b; s = new_stmt(ldop_from_size[size]); s->s.k = offset; b = new_block(EQOp); b->stmts = s; b->s.k = v; return b;}struct block *gen_mcmp(offset, size, v, mask) u_int offset, size; long v; u_long mask;{ struct block *b = gen_cmp(offset, size, v); struct slist *s; if (mask != 0xffffffff) { s = new_stmt(AndIOp); s->s.k = mask; b->stmts->next = s; } return b;}struct block *gen_bcmp(offset, size, v) u_int offset; u_int size; u_char *v;{ struct block *b, *tmp; int k; b = 0; while (size >= 4) { k = size - 4; tmp = gen_cmp(offset + k, 4, EXTRACT_LONG(&v[k])); if (b != 0) gen_and(b, tmp); b = tmp; size -= 4; } while (size >= 2) { k = size - 2; tmp = gen_cmp(offset + k, 2, (long)EXTRACT_SHORT(&v[k])); if (b != 0) gen_and(b, tmp); b = tmp; size -= 2; } if (size > 0) { tmp = gen_cmp(offset, 1, (long)v[0]); if (b != 0) gen_and(b, tmp); b = tmp; } return b;}/* * Various code contructs need to know the layout of the data link * layer. These variables give the necessary offsets. */static u_int off_linktype;static u_int off_nl;static int linktype;static voidinit_linktype(type) int type;{ linktype = type; switch (type) { case DLT_EN10MB: off_linktype = 12; off_nl = 14; return; case DLT_SLIP: /* * SLIP doesn't have a link level type. The 16 byte * header is hacked into our SLIP driver. */ off_linktype = -1; off_nl = 16; return; case DLT_PPP: /* Put on PPP's link level type */ off_linktype = -1; off_nl = 4; return; } error("unknown data link type %x", linktype); /* NOTREACHED */}static struct block *gen_uncond(rsense) int rsense;{ struct block *b; struct slist *s; s = new_stmt(LdIOp); s->s.k = !rsense; b = new_block(EQOp); b->stmts = s; return b;}static inline struct block *gen_true(){ return gen_uncond(1);}static inline struct block *gen_false(){ return gen_uncond(0);}struct block *gen_linktype(proto) int proto;{ if (linktype == DLT_SLIP) { if (proto == ETHERTYPE_IP) return gen_true(); else return gen_false(); } return gen_cmp(off_linktype, 2, (long)proto);}static struct block *gen_hostop(addr, mask, dir, proto, src_off, dst_off) u_long addr; u_long mask; int dir, proto; u_int src_off, dst_off;{ struct block *b0, *b1; u_int offset; switch (dir) { case Q_SRC: offset = src_off; break; case Q_DST: offset = dst_off; break; case Q_AND: b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off); b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off); gen_and(b0, b1); return b1; case Q_OR: case Q_DEFAULT: b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off); b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off); gen_or(b0, b1); return b1; default: abort(); } b0 = gen_linktype(proto); b1 = gen_mcmp(offset, 4, (long)addr, mask); gen_and(b0, b1); return b1;}static struct block *gen_ehostop(eaddr, dir) u_char *eaddr; int dir;{ struct block *b0, *b1; switch (dir) { case Q_SRC: return gen_bcmp(6, 6, eaddr); case Q_DST: return gen_bcmp(0, 6, eaddr); case Q_AND: b0 = gen_ehostop(eaddr, Q_SRC); b1 = gen_ehostop(eaddr, Q_DST); gen_and(b0, b1); return b1; case Q_DEFAULT: case Q_OR: b0 = gen_ehostop(eaddr, Q_SRC); b1 = gen_ehostop(eaddr, Q_DST); gen_or(b0, b1); return b1; } abort(); /* NOTREACHED */}static struct block *gen_host(addr, mask, proto, dir) u_long addr; u_long mask; int proto; int dir;{ struct block *b0, *b1; switch (proto) { case Q_DEFAULT: b0 = gen_host(addr, mask, Q_IP, dir); b1 = gen_host(addr, mask, Q_ARP, dir); gen_or(b0, b1); b0 = gen_host(addr, mask, Q_RARP, dir); gen_or(b1, b0); return b0; case Q_IP: return gen_hostop(addr, mask, dir, ETHERTYPE_IP, off_nl + 12, off_nl + 16); case Q_RARP: return gen_hostop(addr, mask, dir, ETHERTYPE_REVARP, off_nl + 14, off_nl + 24); case Q_ARP: return gen_hostop(addr, mask, dir, ETHERTYPE_ARP, off_nl + 14, off_nl + 24); case Q_TCP: error("'tcp' modifier applied to host"); case Q_UDP: error("'udp' modifier applied to host"); case Q_ETHER: error("'ether' modifier applied to host"); } abort(); /* NOTREACHED */}static struct block *gen_gateway(eaddr, alist, proto, dir) u_char *eaddr; u_long **alist; int proto; int dir;{ struct block *b0, *b1, *tmp; if (dir != 0) error("direction applied to 'gateway'"); switch (proto) { case Q_DEFAULT: case Q_IP: case Q_ARP: case Q_RARP: b0 = gen_ehostop(eaddr, Q_OR); b1 = gen_host(**alist++, 0xffffffffL, proto, Q_OR); while (*alist) { tmp = gen_host(**alist++, 0xffffffffL, proto, Q_OR); gen_or(b1, tmp); b1 = tmp; } gen_not(b1); gen_and(b0, b1); return b1; } error("illegal modifier of 'gateway'"); /* NOTREACHED */}struct block *gen_proto_abbrev(proto) int proto;{ struct block *b0, *b1; switch (proto) { case Q_TCP: b0 = gen_linktype(ETHERTYPE_IP); b1 = gen_cmp(off_nl + 9, 1, (long)IPPROTO_TCP); gen_and(b0, b1); break; case Q_UDP: b0 = gen_linktype(ETHERTYPE_IP); b1 = gen_cmp(off_nl + 9, 1, (long)IPPROTO_UDP); gen_and(b0, b1); break; case Q_IP: b1 = gen_linktype(ETHERTYPE_IP); break; case Q_ARP: b1 = gen_linktype(ETHERTYPE_ARP); break; case Q_RARP: b1 = gen_linktype(ETHERTYPE_REVARP); break; case Q_ETHER: error("'ether' keyword used incorrectly"); default: abort(); } return b1;}static struct block *gen_ipfrag(){ struct slist *s; struct block *b; /* not ip frag */ s = new_stmt(LdHOp); s->s.k = off_nl + 6; s->next = new_stmt(AndIOp); s->next->s.k = 0x1fff; b = new_block(EQOp); b->stmts = s; return b;}static struct block *gen_portatom(off, v) int off; long v;{ struct slist *s; struct block *b; s = new_stmt(LdxmsOp); s->s.k = off_nl; s->next = new_stmt(ILdHOp); s->next->s.k = off_nl + off; b = new_block(EQOp);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?