Example #1
0
int
in6_detachhead(void **head, int off)
{

	callout_drain(&V_rtq_mtutimer);
	return (rn_detachhead(head));
}
Example #2
0
void
ipfw_destroy_tables(struct ip_fw_chain *ch)
{
	uint16_t tbl;
	struct radix_node_head *rnh;

	IPFW_WLOCK_ASSERT(ch);

	for (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++) {
		ipfw_flush_table(ch, tbl);
		rnh = ch->tables[tbl];
		rn_detachhead((void **)&rnh);
	}
}
Example #3
0
int
ipfw_flush_table(struct ip_fw_chain *ch, uint16_t tbl)
{
	struct radix_node_head *rnh, *xrnh;

	if (tbl >= V_fw_tables_max)
		return (EINVAL);

	/*
	 * We free both (IPv4 and extended) radix trees and
	 * clear table type here to permit table to be reused
	 * for different type without module reload
	 */

	IPFW_WLOCK(ch);
	/* Set IPv4 table pointer to zero */
	if ((rnh = ch->tables[tbl]) != NULL)
		ch->tables[tbl] = NULL;
	/* Set extended table pointer to zero */
	if ((xrnh = ch->xtables[tbl]) != NULL)
		ch->xtables[tbl] = NULL;
	/* Zero table type */
	ch->tabletype[tbl] = 0;
	IPFW_WUNLOCK(ch);

	if (rnh != NULL) {
		rnh->rnh_walktree(rnh, flush_table_entry, rnh);
		rn_detachhead((void **)&rnh);
	}

	if (xrnh != NULL) {
		xrnh->rnh_walktree(xrnh, flush_table_entry, xrnh);
		rn_detachhead((void **)&xrnh);
	}

	return (0);
}
Example #4
0
int
in_detachhead(void **head, int off)
{

	return (rn_detachhead(head));
}
Example #5
0
int
ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables)
{
	struct radix_node_head **tables, **xtables, *rnh;
	struct radix_node_head **tables_old, **xtables_old;
	uint8_t *tabletype, *tabletype_old;
	unsigned int ntables_old, tbl;

	/* Check new value for validity */
	if (ntables > IPFW_TABLES_MAX)
		ntables = IPFW_TABLES_MAX;

	/* Allocate new pointers */
	tables = malloc(ntables * sizeof(void *), M_IPFW, M_WAITOK | M_ZERO);
	xtables = malloc(ntables * sizeof(void *), M_IPFW, M_WAITOK | M_ZERO);
	tabletype = malloc(ntables * sizeof(uint8_t), M_IPFW, M_WAITOK | M_ZERO);

	IPFW_WLOCK(ch);

	tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables;

	/* Copy old table pointers */
	memcpy(tables, ch->tables, sizeof(void *) * tbl);
	memcpy(xtables, ch->xtables, sizeof(void *) * tbl);
	memcpy(tabletype, ch->tabletype, sizeof(uint8_t) * tbl);

	/* Change pointers and number of tables */
	tables_old = ch->tables;
	xtables_old = ch->xtables;
	tabletype_old = ch->tabletype;
	ch->tables = tables;
	ch->xtables = xtables;
	ch->tabletype = tabletype;

	ntables_old = V_fw_tables_max;
	V_fw_tables_max = ntables;

	IPFW_WUNLOCK(ch);

	/* Check if we need to destroy radix trees */
	if (ntables < ntables_old) {
		for (tbl = ntables; tbl < ntables_old; tbl++) {
			if ((rnh = tables_old[tbl]) != NULL) {
				rnh->rnh_walktree(rnh, flush_table_entry, rnh);
				rn_detachhead((void **)&rnh);
			}

			if ((rnh = xtables_old[tbl]) != NULL) {
				rnh->rnh_walktree(rnh, flush_table_entry, rnh);
				rn_detachhead((void **)&rnh);
			}
		}
	}

	/* Free old pointers */
	free(tables_old, M_IPFW);
	free(xtables_old, M_IPFW);
	free(tabletype_old, M_IPFW);

	return (0);
}
Example #6
0
int
ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
    uint8_t plen, uint8_t mlen, uint8_t type, uint32_t value)
{
	struct radix_node_head *rnh, **rnh_ptr;
	struct table_entry *ent;
	struct table_xentry *xent;
	struct radix_node *rn;
	in_addr_t addr;
	int offset;
	void *ent_ptr;
	struct sockaddr *addr_ptr, *mask_ptr;
	char c;

	if (tbl >= V_fw_tables_max)
		return (EINVAL);

	switch (type) {
	case IPFW_TABLE_CIDR:
		if (plen == sizeof(in_addr_t)) {
#ifdef INET
			/* IPv4 case */
			if (mlen > 32)
				return (EINVAL);
			ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
			ent->value = value;
			/* Set 'total' structure length */
			KEY_LEN(ent->addr) = KEY_LEN_INET;
			KEY_LEN(ent->mask) = KEY_LEN_INET;
			/* Set offset of IPv4 address in bits */
			offset = OFF_LEN_INET;
			ent->mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
			addr = *((in_addr_t *)paddr);
			ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr;
			/* Set pointers */
			rnh_ptr = &ch->tables[tbl];
			ent_ptr = ent;
			addr_ptr = (struct sockaddr *)&ent->addr;
			mask_ptr = (struct sockaddr *)&ent->mask;
#endif
#ifdef INET6
		} else if (plen == sizeof(struct in6_addr)) {
			/* IPv6 case */
			if (mlen > 128)
				return (EINVAL);
			xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
			xent->value = value;
			/* Set 'total' structure length */
			KEY_LEN(xent->a.addr6) = KEY_LEN_INET6;
			KEY_LEN(xent->m.mask6) = KEY_LEN_INET6;
			/* Set offset of IPv6 address in bits */
			offset = OFF_LEN_INET6;
			ipv6_writemask(&xent->m.mask6.sin6_addr, mlen);
			memcpy(&xent->a.addr6.sin6_addr, paddr, sizeof(struct in6_addr));
			APPLY_MASK(&xent->a.addr6.sin6_addr, &xent->m.mask6.sin6_addr);
			/* Set pointers */
			rnh_ptr = &ch->xtables[tbl];
			ent_ptr = xent;
			addr_ptr = (struct sockaddr *)&xent->a.addr6;
			mask_ptr = (struct sockaddr *)&xent->m.mask6;
#endif
		} else {
			/* Unknown CIDR type */
			return (EINVAL);
		}
		break;
	
	case IPFW_TABLE_INTERFACE:
		/* Check if string is terminated */
		c = ((char *)paddr)[IF_NAMESIZE - 1];
		((char *)paddr)[IF_NAMESIZE - 1] = '\0';
		if (((mlen = strlen((char *)paddr)) == IF_NAMESIZE - 1) && (c != '\0'))
			return (EINVAL);

		/* Include last \0 into comparison */
		mlen++;

		xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
		xent->value = value;
		/* Set 'total' structure length */
		KEY_LEN(xent->a.iface) = KEY_LEN_IFACE + mlen;
		KEY_LEN(xent->m.ifmask) = KEY_LEN_IFACE + mlen;
		/* Set offset of interface name in bits */
		offset = OFF_LEN_IFACE;
		memcpy(xent->a.iface.ifname, paddr, mlen);
		/* Assume direct match */
		/* TODO: Add interface pattern matching */
#if 0
		memset(xent->m.ifmask.ifname, 0xFF, IF_NAMESIZE);
		mask_ptr = (struct sockaddr *)&xent->m.ifmask;
#endif
		/* Set pointers */
		rnh_ptr = &ch->xtables[tbl];
		ent_ptr = xent;
		addr_ptr = (struct sockaddr *)&xent->a.iface;
		mask_ptr = NULL;
		break;

	default:
		return (EINVAL);
	}

	IPFW_WLOCK(ch);

	/* Check if tabletype is valid */
	if ((ch->tabletype[tbl] != 0) && (ch->tabletype[tbl] != type)) {
		IPFW_WUNLOCK(ch);
		free(ent_ptr, M_IPFW_TBL);
		return (EINVAL);
	}

	/* Check if radix tree exists */
	if ((rnh = *rnh_ptr) == NULL) {
		IPFW_WUNLOCK(ch);
		/* Create radix for a new table */
		if (!rn_inithead((void **)&rnh, offset)) {
			free(ent_ptr, M_IPFW_TBL);
			return (ENOMEM);
		}

		IPFW_WLOCK(ch);
		if (*rnh_ptr != NULL) {
			/* Tree is already attached by other thread */
			rn_detachhead((void **)&rnh);
			rnh = *rnh_ptr;
			/* Check table type another time */
			if (ch->tabletype[tbl] != type) {
				IPFW_WUNLOCK(ch);
				free(ent_ptr, M_IPFW_TBL);
				return (EINVAL);
			}
		} else {
			*rnh_ptr = rnh;
			/* 
			 * Set table type. It can be set already
			 * (if we have IPv6-only table) but setting
			 * it another time does not hurt
			 */
			ch->tabletype[tbl] = type;
		}
	}

	rn = rnh->rnh_addaddr(addr_ptr, mask_ptr, rnh, ent_ptr);
	IPFW_WUNLOCK(ch);

	if (rn == NULL) {
		free(ent_ptr, M_IPFW_TBL);
		return (EEXIST);
	}
	return (0);
}