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 + -
显示快捷键?