FreeBSD/sys/netpfil/ipfw/ip_fw_sockopt.c
/*
 * Add new rule(s) to the list possibly creating rule number for each.
 * Update the rule_number in the input struct so the caller knows it as well.
 * Must be called without IPFW_UH held
 */
Add new rule(s) to the list possibly creating rule number for each.
Update the rule_number in the input struct so the caller knows it as well.
Must be called without IPFW_UH held
Add new rule ( s ) to the list possibly creating rule number for each . Update the rule_number in the input struct so the caller knows it as well . Must be called without IPFW_UH held
static int
commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, int count)
{
	int error, i, insert_before, tcount;
	uint16_t rulenum, *pnum;
	struct rule_check_info *ci;
	struct ip_fw *krule;
	struct ip_fw **map;	
	tcount = 0;
	for (ci = rci, i = 0; i < count; ci++, i++) {
		if (ci->object_opcodes == 0)
			continue;
		error = rewrite_rule_uidx(chain, ci);
		if (error != 0) {
			if (tcount > 0) {
				IPFW_UH_WLOCK(chain);
				while (ci != rci) {
					ci--;
					if (ci->object_opcodes == 0)
						continue;
					unref_rule_objects(chain,ci->krule);
				}
				IPFW_UH_WUNLOCK(chain);
			}
			return (error);
		}
		tcount++;
	}
	map = get_map(chain, count, 0 );
	if (map == NULL) {
		if (tcount > 0) {
			IPFW_UH_WLOCK(chain);
			for (ci = rci, i = 0; i < count; ci++, i++) {
				if (ci->object_opcodes == 0)
					continue;
				unref_rule_objects(chain, ci->krule);
			}
			IPFW_UH_WUNLOCK(chain);
		}
		return (ENOSPC);
	}
	if (V_autoinc_step < 1)
		V_autoinc_step = 1;
	else if (V_autoinc_step > 1000)
		V_autoinc_step = 1000;
	ci = rci;
	krule = ci->krule;
	rulenum = krule->rulenum;
	insert_before = rulenum ? rulenum + 1 : IPFW_DEFAULT_RULE;
	i = ipfw_find_rule(chain, insert_before, 0);
	if (i > 0)
		bcopy(chain->map, map, i * sizeof(struct ip_fw *));
	map[i] = krule;
	bcopy(chain->map + i, map + i + 1,
		sizeof(struct ip_fw *) *(chain->n_rules - i));
	if (rulenum == 0) {
		rulenum = i > 0 ? map[i-1]->rulenum : 0;
		if (rulenum < IPFW_DEFAULT_RULE - V_autoinc_step)
			rulenum += V_autoinc_step;
		krule->rulenum = rulenum;
		pnum = (uint16_t *)((caddr_t)ci->urule + ci->urule_numoff);
		*pnum = rulenum;
	}
	krule->id = chain->id + 1;
	update_skipto_cache(chain, map);
	map = swap_map(chain, map, chain->n_rules + 1);
	chain->static_len += RULEUSIZE0(krule);
	IPFW_UH_WUNLOCK(chain);
	if (map)
		free(map, M_IPFW);
	return (0);
}
static int commit_rules ( struct ip_fw_chain * chain , struct rule_check_info * rci , int count ) { int error , i , insert_before , tcount ; uint16_t rulenum , * pnum ; struct rule_check_info * ci ; struct ip_fw * krule ; struct ip_fw * * map ; tcount = 0 ; for ( ci = rci , i = 0 ; i < count ; ci ++ , i ++ ) { if ( ci -> object_opcodes == 0 ) continue ; error = rewrite_rule_uidx ( chain , ci ) ; if ( error != 0 ) { if ( tcount > 0 ) { IPFW_UH_WLOCK ( chain ) ; while ( ci != rci ) { ci -- ; if ( ci -> object_opcodes == 0 ) continue ; unref_rule_objects ( chain , ci -> krule ) ; } IPFW_UH_WUNLOCK ( chain ) ; } return ( error ) ; } tcount ++ ; } map = get_map ( chain , count , 0 ) ; if ( map == NULL ) { if ( tcount > 0 ) { IPFW_UH_WLOCK ( chain ) ; for ( ci = rci , i = 0 ; i < count ; ci ++ , i ++ ) { if ( ci -> object_opcodes == 0 ) continue ; unref_rule_objects ( chain , ci -> krule ) ; } IPFW_UH_WUNLOCK ( chain ) ; } return ( ENOSPC ) ; } if ( V_autoinc_step < 1 ) V_autoinc_step = 1 ; else if ( V_autoinc_step > 1000 ) V_autoinc_step = 1000 ; ci = rci ; krule = ci -> krule ; rulenum = krule -> rulenum ; insert_before = rulenum ? rulenum + 1 : IPFW_DEFAULT_RULE ; i = ipfw_find_rule ( chain , insert_before , 0 ) ; if ( i > 0 ) bcopy ( chain -> map , map , i * sizeof ( struct ip_fw * ) ) ; map [ i ] = krule ; bcopy ( chain -> map + i , map + i + 1 , sizeof ( struct ip_fw * ) * ( chain -> n_rules - i ) ) ; if ( rulenum == 0 ) { rulenum = i > 0 ? map [ i - 1 ] -> rulenum : 0 ; if ( rulenum < IPFW_DEFAULT_RULE - V_autoinc_step ) rulenum += V_autoinc_step ; krule -> rulenum = rulenum ; pnum = ( uint16_t * ) ( ( caddr_t ) ci -> urule + ci -> urule_numoff ) ; * pnum = rulenum ; } krule -> id = chain -> id + 1 ; update_skipto_cache ( chain , map ) ; map = swap_map ( chain , map , chain -> n_rules + 1 ) ; chain -> static_len += RULEUSIZE0 ( krule ) ; IPFW_UH_WUNLOCK ( chain ) ; if ( map ) free ( map , M_IPFW ) ; return ( 0 ) ; }
Add new rule(s) to the list possibly creating rule number for each.
Add new rule ( s ) to the list possibly creating rule number for each .
/* the new array of pointers */ /* Check if we need to do table/obj index remap */ /*
		 * Rule has some object opcodes.
		 * We need to find (and create non-existing)
		 * kernel objects, and reference existing ones.
		 */ /*
			 * rewrite failed, state for current rule
			 * has been reverted. Check if we need to
			 * revert more.
			 */ /*
				 * We have some more table rules
				 * we need to rollback.
				 */ /* get_map returns with IPFW_UH_WLOCK if successful */ /* not locked */ /* Unbind tables */ /* FIXME: Handle count > 1 */ /* find the insertion point, we will insert before */ /* duplicate first part */ /* duplicate remaining part, we always have the default rule */ /* Compute rule number and write it back */ /* Save number to userland rule */