Annotation of embedaddon/bird2/lib/flowspec.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  *     BIRD Library -- Flow specification (RFC 5575)
        !             3:  *
        !             4:  *     (c) 2016 CZ.NIC z.s.p.o.
        !             5:  *
        !             6:  *     Can be freely distributed and used under the terms of the GNU GPL.
        !             7:  */
        !             8: 
        !             9: /**
        !            10:  * DOC: Flow specification (flowspec)
        !            11:  *
        !            12:  * Flowspec are rules (RFC 5575) for firewalls disseminated using BGP protocol.
        !            13:  * The |flowspec.c| is a library for handling flowspec binary streams and
        !            14:  * flowspec data structures. You will find there functions for validation
        !            15:  * incoming flowspec binary streams, iterators for jumping over components,
        !            16:  * functions for handling a length and functions for formatting flowspec data
        !            17:  * structure into user-friendly text representation.
        !            18:  *
        !            19:  * In this library, you will find also flowspec builder. In |confbase.Y|, there
        !            20:  * are grammar's rules for parsing and building new flowspec data structure
        !            21:  * from BIRD's configuration files and from BIRD's command line interface.
        !            22:  * Finalize function will assemble final &net_addr_flow4 or &net_addr_flow6
        !            23:  * data structure.
        !            24:  *
        !            25:  * The data structures &net_addr_flow4 and &net_addr_flow6 are defined in
        !            26:  * |net.h| file. The attribute length is size of whole data structure plus
        !            27:  * binary stream representation of flowspec including a compressed encoded
        !            28:  * length of flowspec.
        !            29:  *
        !            30:  * Sometimes in code, it is used expression flowspec type, it should mean
        !            31:  * flowspec component type.
        !            32:  */
        !            33: 
        !            34: #include "nest/bird.h"
        !            35: #include "lib/flowspec.h"
        !            36: #include "conf/conf.h"
        !            37: 
        !            38: 
        !            39: static const char* flow4_type_str[] = {
        !            40:   [FLOW_TYPE_DST_PREFIX]       = "dst",
        !            41:   [FLOW_TYPE_SRC_PREFIX]       = "src",
        !            42:   [FLOW_TYPE_IP_PROTOCOL]      = "proto",
        !            43:   [FLOW_TYPE_PORT]             = "port",
        !            44:   [FLOW_TYPE_DST_PORT]         = "dport",
        !            45:   [FLOW_TYPE_SRC_PORT]         = "sport",
        !            46:   [FLOW_TYPE_ICMP_TYPE]                = "icmp type",
        !            47:   [FLOW_TYPE_ICMP_CODE]                = "icmp code",
        !            48:   [FLOW_TYPE_TCP_FLAGS]                = "tcp flags",
        !            49:   [FLOW_TYPE_PACKET_LENGTH]    = "length",
        !            50:   [FLOW_TYPE_DSCP]             = "dscp",
        !            51:   [FLOW_TYPE_FRAGMENT]         = "fragment"
        !            52: };
        !            53: 
        !            54: static const char* flow6_type_str[] = {
        !            55:   [FLOW_TYPE_DST_PREFIX]       = "dst",
        !            56:   [FLOW_TYPE_SRC_PREFIX]       = "src",
        !            57:   [FLOW_TYPE_NEXT_HEADER]      = "next header",
        !            58:   [FLOW_TYPE_PORT]             = "port",
        !            59:   [FLOW_TYPE_DST_PORT]         = "dport",
        !            60:   [FLOW_TYPE_SRC_PORT]         = "sport",
        !            61:   [FLOW_TYPE_ICMP_TYPE]                = "icmp type",
        !            62:   [FLOW_TYPE_ICMP_CODE]                = "icmp code",
        !            63:   [FLOW_TYPE_TCP_FLAGS]                = "tcp flags",
        !            64:   [FLOW_TYPE_PACKET_LENGTH]    = "length",
        !            65:   [FLOW_TYPE_DSCP]             = "dscp",
        !            66:   [FLOW_TYPE_FRAGMENT]         = "fragment",
        !            67:   [FLOW_TYPE_LABEL]            = "label"
        !            68: };
        !            69: 
        !            70: /**
        !            71:  * flow_type_str - get stringified flowspec name of component
        !            72:  * @type: flowspec component type
        !            73:  * @ipv6: IPv4/IPv6 decide flag, use zero for IPv4 and one for IPv6
        !            74:  *
        !            75:  * This function returns flowspec name of component @type in string.
        !            76:  */
        !            77: const char *
        !            78: flow_type_str(enum flow_type type, int ipv6)
        !            79: {
        !            80:   return ipv6 ? flow6_type_str[type] : flow4_type_str[type];
        !            81: }
        !            82: 
        !            83: /*
        !            84:  *     Length
        !            85:  */
        !            86: 
        !            87: /**
        !            88:  * flow_write_length - write compressed length value
        !            89:  * @data: destination buffer to write
        !            90:  * @len: the value of the length (0 to 0xfff) for writing
        !            91:  *
        !            92:  * This function writes appropriate as (1- or 2-bytes) the value of @len into
        !            93:  * buffer @data. The function returns number of written bytes, thus 1 or 2 bytes.
        !            94:  */
        !            95: uint
        !            96: flow_write_length(byte *data, u16 len)
        !            97: {
        !            98:   if (len >= 0xf0)
        !            99:   {
        !           100:     put_u16(data, len | 0xf000);
        !           101:     return 2;
        !           102:   }
        !           103: 
        !           104:   *data = len;
        !           105:   return 1;
        !           106: }
        !           107: 
        !           108: inline static uint
        !           109: get_value_length(const byte *op)
        !           110: {
        !           111:   return (1 << ((*op & 0x30) >> 4));
        !           112: }
        !           113: 
        !           114: 
        !           115: 
        !           116: /*
        !           117:  *     Flowspec iterators
        !           118:  */
        !           119: 
        !           120: static inline u8  num_op(const byte *op)    { return  (*op & 0x07); }
        !           121: static inline int isset_and(const byte *op) { return ((*op & 0x40) == 0x40); }
        !           122: static inline int isset_end(const byte *op) { return ((*op & 0x80) == 0x80); }
        !           123: 
        !           124: static const byte *
        !           125: flow_first_part(const byte *data)
        !           126: {
        !           127:   if (!data || flow_read_length(data) == 0)
        !           128:     return NULL;
        !           129: 
        !           130:   /* It is allowed to encode the value of length less then 240 into 2-bytes too */
        !           131:   if ((data[0] & 0xf0) == 0xf0)
        !           132:     return data + 2;
        !           133: 
        !           134:   return data + 1;
        !           135: }
        !           136: 
        !           137: /**
        !           138:  * flow4_first_part - get position of the first flowspec component
        !           139:  * @f: flowspec data structure &net_addr_flow4
        !           140:  *
        !           141:  * This function return a position to the beginning of the first flowspec
        !           142:  * component in IPv4 flowspec @f.
        !           143:  */
        !           144: inline const byte *
        !           145: flow4_first_part(const net_addr_flow4 *f)
        !           146: {
        !           147:   return f ? flow_first_part(f->data) : NULL;
        !           148: }
        !           149: 
        !           150: /**
        !           151:  * flow6_first_part - get position of the first flowspec component
        !           152:  * @f: flowspec data structure &net_addr_flow6
        !           153:  *
        !           154:  * This function return a position to the beginning of the first flowspec
        !           155:  * component in IPv6 flowspec @f.
        !           156:  */
        !           157: inline const byte *
        !           158: flow6_first_part(const net_addr_flow6 *f)
        !           159: {
        !           160:   return f ? flow_first_part(f->data) : NULL;
        !           161: }
        !           162: 
        !           163: static const byte *
        !           164: flow_next_part(const byte *pos, const byte *end, int ipv6)
        !           165: {
        !           166:   switch (*pos++)
        !           167:   {
        !           168:   case FLOW_TYPE_DST_PREFIX:
        !           169:   case FLOW_TYPE_SRC_PREFIX:
        !           170:   {
        !           171:     uint pxlen = *pos++;
        !           172:     uint bytes = BYTES(pxlen);
        !           173:     if (ipv6)
        !           174:     {
        !           175:       uint offset = *pos++ / 8;
        !           176:       pos += bytes - offset;
        !           177:     }
        !           178:     else
        !           179:     {
        !           180:       pos += bytes;
        !           181:     }
        !           182:     break;
        !           183:   }
        !           184: 
        !           185:   case FLOW_TYPE_IP_PROTOCOL: /* == FLOW_TYPE_NEXT_HEADER */
        !           186:   case FLOW_TYPE_PORT:
        !           187:   case FLOW_TYPE_DST_PORT:
        !           188:   case FLOW_TYPE_SRC_PORT:
        !           189:   case FLOW_TYPE_ICMP_TYPE:
        !           190:   case FLOW_TYPE_ICMP_CODE:
        !           191:   case FLOW_TYPE_TCP_FLAGS:
        !           192:   case FLOW_TYPE_PACKET_LENGTH:
        !           193:   case FLOW_TYPE_DSCP:
        !           194:   case FLOW_TYPE_FRAGMENT:
        !           195:   case FLOW_TYPE_LABEL:
        !           196:   {
        !           197:     /* Is this the end of list operator-value pair? */
        !           198:     uint last = 0;
        !           199: 
        !           200:     while (!last)
        !           201:     {
        !           202:       last = isset_end(pos);
        !           203: 
        !           204:       /* Value length of operator */
        !           205:       uint len = get_value_length(pos);
        !           206:       pos += 1+len;
        !           207:     }
        !           208:     break;
        !           209:   }
        !           210:   default:
        !           211:     return NULL;
        !           212:   }
        !           213: 
        !           214:   return (pos < end) ? pos : NULL;
        !           215: }
        !           216: 
        !           217: /**
        !           218:  * flow4_next_part - an iterator over flowspec components in flowspec binary stream
        !           219:  * @pos: the beginning of a previous or the first component in flowspec binary
        !           220:  *       stream
        !           221:  * @end: the last valid byte in scanned flowspec binary stream
        !           222:  *
        !           223:  * This function returns a position to the beginning of the next component
        !           224:  * (to a component type byte) in flowspec binary stream or %NULL for the end.
        !           225:  */
        !           226: inline const byte *
        !           227: flow4_next_part(const byte *pos, const byte *end)
        !           228: {
        !           229:   return flow_next_part(pos, end, 0);
        !           230: }
        !           231: 
        !           232: /**
        !           233:  * flow6_next_part - an iterator over flowspec components in flowspec binary stream
        !           234:  * @pos: the beginning of a previous or the first component in flowspec binary
        !           235:  *       stream
        !           236:  * @end: the last valid byte in scanned flowspec binary stream
        !           237:  *
        !           238:  * This function returns a position to the beginning of the next component
        !           239:  * (to a component type byte) in flowspec binary stream or %NULL for the end.
        !           240:  */
        !           241: inline const byte *
        !           242: flow6_next_part(const byte *pos, const byte *end)
        !           243: {
        !           244:   return flow_next_part(pos, end, 1);
        !           245: }
        !           246: 
        !           247: 
        !           248: /*
        !           249:  *     Flowspec validation
        !           250:  */
        !           251: 
        !           252: static const char* flow_validated_state_str_[] = {
        !           253:   [FLOW_ST_UNKNOWN_COMPONENT]          = "Unknown component",
        !           254:   [FLOW_ST_VALID]                      = "Valid",
        !           255:   [FLOW_ST_NOT_COMPLETE]               = "Not complete",
        !           256:   [FLOW_ST_EXCEED_MAX_PREFIX_LENGTH]   = "Exceed maximal prefix length",
        !           257:   [FLOW_ST_EXCEED_MAX_PREFIX_OFFSET]   = "Exceed maximal prefix offset",
        !           258:   [FLOW_ST_EXCEED_MAX_VALUE_LENGTH]    = "Exceed maximal value length",
        !           259:   [FLOW_ST_BAD_TYPE_ORDER]             = "Bad component order",
        !           260:   [FLOW_ST_AND_BIT_SHOULD_BE_UNSET]    = "The AND-bit should be unset",
        !           261:   [FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED]   = "The Zero-bit should be unset",
        !           262:   [FLOW_ST_DEST_PREFIX_REQUIRED]       = "Destination prefix is missing",
        !           263:   [FLOW_ST_INVALID_TCP_FLAGS]          = "TCP flags exceeding 0xfff",
        !           264:   [FLOW_ST_CANNOT_USE_DONT_FRAGMENT]    = "Cannot use Don't fragment flag in IPv6 flow"
        !           265: };
        !           266: 
        !           267: /**
        !           268:  * flow_validated_state_str - return a textual description of validation process
        !           269:  * @code: validation result
        !           270:  *
        !           271:  * This function return well described validation state in string.
        !           272:  */
        !           273: const char *
        !           274: flow_validated_state_str(enum flow_validated_state code)
        !           275: {
        !           276:   return flow_validated_state_str_[code];
        !           277: }
        !           278: 
        !           279: static const u8 flow4_max_value_length[] = {
        !           280:   [FLOW_TYPE_DST_PREFIX]       = 0,
        !           281:   [FLOW_TYPE_SRC_PREFIX]       = 0,
        !           282:   [FLOW_TYPE_IP_PROTOCOL]      = 1,
        !           283:   [FLOW_TYPE_PORT]             = 2,
        !           284:   [FLOW_TYPE_DST_PORT]         = 2,
        !           285:   [FLOW_TYPE_SRC_PORT]         = 2,
        !           286:   [FLOW_TYPE_ICMP_TYPE]                = 1,
        !           287:   [FLOW_TYPE_ICMP_CODE]                = 1,
        !           288:   [FLOW_TYPE_TCP_FLAGS]                = 2,
        !           289:   [FLOW_TYPE_PACKET_LENGTH]    = 2,
        !           290:   [FLOW_TYPE_DSCP]             = 1,
        !           291:   [FLOW_TYPE_FRAGMENT]         = 1     /* XXX */
        !           292: };
        !           293: 
        !           294: static const u8 flow6_max_value_length[] = {
        !           295:   [FLOW_TYPE_DST_PREFIX]       = 0,
        !           296:   [FLOW_TYPE_SRC_PREFIX]       = 0,
        !           297:   [FLOW_TYPE_NEXT_HEADER]      = 1,
        !           298:   [FLOW_TYPE_PORT]             = 2,
        !           299:   [FLOW_TYPE_DST_PORT]         = 2,
        !           300:   [FLOW_TYPE_SRC_PORT]         = 2,
        !           301:   [FLOW_TYPE_ICMP_TYPE]                = 1,
        !           302:   [FLOW_TYPE_ICMP_CODE]                = 1,
        !           303:   [FLOW_TYPE_TCP_FLAGS]                = 2,
        !           304:   [FLOW_TYPE_PACKET_LENGTH]    = 2,
        !           305:   [FLOW_TYPE_DSCP]             = 1,
        !           306:   [FLOW_TYPE_FRAGMENT]         = 1,    /* XXX */
        !           307:   [FLOW_TYPE_LABEL]            = 4
        !           308: };
        !           309: 
        !           310: static u8
        !           311: flow_max_value_length(enum flow_type type, int ipv6)
        !           312: {
        !           313:   return ipv6 ? flow6_max_value_length[type] : flow4_max_value_length[type];
        !           314: }
        !           315: 
        !           316: /**
        !           317:  * flow_check_cf_bmk_values - check value/bitmask part of flowspec component
        !           318:  * @fb: flow builder instance
        !           319:  * @neg: negation operand
        !           320:  * @val: value from value/mask pair
        !           321:  * @mask: bitmap mask from value/mask pair
        !           322:  *
        !           323:  * This function checks value/bitmask pair. If some problem will appear, the
        !           324:  * function calls cf_error() function with a textual description of reason
        !           325:  * to failing of validation.
        !           326:  */
        !           327: void
        !           328: flow_check_cf_bmk_values(struct flow_builder *fb, u8 neg, u32 val, u32 mask)
        !           329: {
        !           330:   flow_check_cf_value_length(fb, val);
        !           331:   flow_check_cf_value_length(fb, mask);
        !           332: 
        !           333:   if (neg && !(val == 0 || val == mask))
        !           334:     cf_error("For negation, value must be zero or bitmask");
        !           335: 
        !           336:   if ((fb->this_type == FLOW_TYPE_TCP_FLAGS) && (mask & 0xf000))
        !           337:     cf_error("Invalid mask 0x%x, must not exceed 0xfff", mask);
        !           338: 
        !           339:   if ((fb->this_type == FLOW_TYPE_FRAGMENT) && fb->ipv6 && (mask & 0x01))
        !           340:     cf_error("Invalid mask 0x%x, bit 0 must be 0", mask);
        !           341: 
        !           342:   if (val & ~mask)
        !           343:     cf_error("Value 0x%x outside bitmask 0x%x", val, mask);
        !           344: }
        !           345: 
        !           346: /**
        !           347:  * flow_check_cf_value_length - check value by flowspec component type
        !           348:  * @fb: flow builder instance
        !           349:  * @val: value
        !           350:  *
        !           351:  * This function checks if the value is in range of component's type support.
        !           352:  * If some problem will appear, the function calls cf_error() function with
        !           353:  * a textual description of reason to failing of validation.
        !           354:  */
        !           355: void
        !           356: flow_check_cf_value_length(struct flow_builder *fb, u32 val)
        !           357: {
        !           358:   enum flow_type t = fb->this_type;
        !           359:   u8 max = flow_max_value_length(t, fb->ipv6);
        !           360: 
        !           361:   if (t == FLOW_TYPE_DSCP && val > 0x3f)
        !           362:     cf_error("%s value %u out of range (0-63)", flow_type_str(t, fb->ipv6), val);
        !           363: 
        !           364:   if (max == 1 && (val > 0xff))
        !           365:     cf_error("%s value %u out of range (0-255)", flow_type_str(t, fb->ipv6), val);
        !           366: 
        !           367:   if (max == 2 && (val > 0xffff))
        !           368:     cf_error("%s value %u out of range (0-65535)", flow_type_str(t, fb->ipv6), val);
        !           369: }
        !           370: 
        !           371: static enum flow_validated_state
        !           372: flow_validate(const byte *nlri, uint len, int ipv6)
        !           373: {
        !           374:   enum flow_type type = 0;
        !           375:   const byte *pos = nlri;
        !           376:   const byte *end = nlri + len;
        !           377:   int met_dst_pfx = 0;
        !           378: 
        !           379:   while (pos < end)
        !           380:   {
        !           381:     /* Check increasing type ordering */
        !           382:     if (*pos <= type)
        !           383:       return FLOW_ST_BAD_TYPE_ORDER;
        !           384:     type = *pos++;
        !           385: 
        !           386:     switch (type)
        !           387:     {
        !           388:     case FLOW_TYPE_DST_PREFIX:
        !           389:       met_dst_pfx = 1;
        !           390:       /* Fall through */
        !           391:     case FLOW_TYPE_SRC_PREFIX:
        !           392:     {
        !           393:       uint pxlen = *pos++;
        !           394:       if (pxlen > (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH))
        !           395:        return FLOW_ST_EXCEED_MAX_PREFIX_LENGTH;
        !           396: 
        !           397:       uint bytes = BYTES(pxlen);
        !           398:       if (ipv6)
        !           399:       {
        !           400:         uint pxoffset = *pos++;
        !           401:         if (pxoffset > IP6_MAX_PREFIX_LENGTH || pxoffset > pxlen)
        !           402:           return FLOW_ST_EXCEED_MAX_PREFIX_OFFSET;
        !           403:         bytes -= pxoffset / 8;
        !           404:       }
        !           405:       pos += bytes;
        !           406: 
        !           407:       break;
        !           408:     }
        !           409: 
        !           410:     case FLOW_TYPE_LABEL:
        !           411:       if (!ipv6)
        !           412:        return FLOW_ST_UNKNOWN_COMPONENT;
        !           413:       /* fall through */
        !           414:     case FLOW_TYPE_IP_PROTOCOL: /* == FLOW_TYPE_NEXT_HEADER */
        !           415:     case FLOW_TYPE_PORT:
        !           416:     case FLOW_TYPE_DST_PORT:
        !           417:     case FLOW_TYPE_SRC_PORT:
        !           418:     case FLOW_TYPE_ICMP_TYPE:
        !           419:     case FLOW_TYPE_ICMP_CODE:
        !           420:     case FLOW_TYPE_TCP_FLAGS:
        !           421:     case FLOW_TYPE_PACKET_LENGTH:
        !           422:     case FLOW_TYPE_DSCP:
        !           423:     case FLOW_TYPE_FRAGMENT:
        !           424:     {
        !           425:       uint last = 0;
        !           426:       uint first = 1;
        !           427: 
        !           428:       while (!last)
        !           429:       {
        !           430:        /*
        !           431:         *    0   1   2   3   4   5   6   7
        !           432:         *  +---+---+---+---+---+---+---+---+
        !           433:         *  | e | a |  len  | 0 |lt |gt |eq |
        !           434:         *  +---+---+---+---+---+---+---+---+
        !           435:         *
        !           436:         *           Numeric operator
        !           437:         */
        !           438: 
        !           439:        last = isset_end(pos);
        !           440: 
        !           441:        /* The AND bit should in the first operator byte of a sequence */
        !           442:        if (first && isset_and(pos))
        !           443:          return FLOW_ST_AND_BIT_SHOULD_BE_UNSET;
        !           444: 
        !           445:        /* This bit should be zero */
        !           446:        if (*pos & 0x08)
        !           447:          return FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED;
        !           448: 
        !           449:        if (type == FLOW_TYPE_TCP_FLAGS || type == FLOW_TYPE_FRAGMENT)
        !           450:        {
        !           451:          /*
        !           452:           *    0   1   2   3   4   5   6   7
        !           453:           *  +---+---+---+---+---+---+---+---+
        !           454:           *  | e | a |  len  | 0 | 0 |not| m |
        !           455:           *  +---+---+---+---+---+---+---+---+
        !           456:           *
        !           457:           *           Bitmask operand
        !           458:           */
        !           459:          if (*pos & 0x04)
        !           460:            return FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED;
        !           461:        }
        !           462: 
        !           463:        /* Value length of operator */
        !           464:        uint len = get_value_length(pos);
        !           465:        if (len > flow_max_value_length(type, ipv6))
        !           466:          return FLOW_ST_EXCEED_MAX_VALUE_LENGTH;
        !           467: 
        !           468:        /* TCP Flags component must not check highest nibble (just 12 valid bits) */
        !           469:        if ((type == FLOW_TYPE_TCP_FLAGS) && (len == 2) && (pos[1] & 0xf0))
        !           470:          return FLOW_ST_INVALID_TCP_FLAGS;
        !           471: 
        !           472:        /* Bit-7 must be 0 [draft-ietf-idr-flow-spec-v6] */
        !           473:        if ((type == FLOW_TYPE_FRAGMENT) && ipv6 && (pos[1] & 0x01))
        !           474:          return FLOW_ST_CANNOT_USE_DONT_FRAGMENT;
        !           475:        /* XXX: Could be a fragment component encoded in 2-bytes? */
        !           476: 
        !           477:        pos += 1+len;
        !           478: 
        !           479:        if (pos > end && !last)
        !           480:          return FLOW_ST_NOT_COMPLETE;
        !           481: 
        !           482:        if (pos > (end+1))
        !           483:          return FLOW_ST_NOT_COMPLETE;
        !           484: 
        !           485:        first = 0;
        !           486:       }
        !           487:       break;
        !           488:     }
        !           489:     default:
        !           490:       return FLOW_ST_UNKNOWN_COMPONENT;
        !           491:     }
        !           492:   }
        !           493: 
        !           494:   if (pos != end)
        !           495:     return FLOW_ST_NOT_COMPLETE;
        !           496: 
        !           497:   if (!ipv6 && !met_dst_pfx)
        !           498:     return FLOW_ST_DEST_PREFIX_REQUIRED;
        !           499: 
        !           500:   return FLOW_ST_VALID;
        !           501: }
        !           502: 
        !           503: /**
        !           504:  * flow4_validate - check untrustworthy IPv4 flowspec data stream
        !           505:  * @nlri: flowspec data stream without compressed encoded length value
        !           506:  * @len: length of @nlri
        !           507:  *
        !           508:  * This function checks meaningfulness of binary flowspec. It should return
        !           509:  * %FLOW_ST_VALID or %FLOW_ST_UNKNOWN_COMPONENT. If some problem appears, it
        !           510:  * returns some other %FLOW_ST_xxx state.
        !           511:  */
        !           512: inline enum flow_validated_state
        !           513: flow4_validate(const byte *nlri, uint len)
        !           514: {
        !           515:   return flow_validate(nlri, len, 0);
        !           516: }
        !           517: 
        !           518: /**
        !           519:  * flow6_validate - check untrustworthy IPv6 flowspec data stream
        !           520:  * @nlri: flowspec binary stream without encoded length value
        !           521:  * @len: length of @nlri
        !           522:  *
        !           523:  * This function checks meaningfulness of binary flowspec. It should return
        !           524:  * %FLOW_ST_VALID or %FLOW_ST_UNKNOWN_COMPONENT. If some problem appears, it
        !           525:  * returns some other %FLOW_ST_xxx state.
        !           526:  */
        !           527: inline enum flow_validated_state
        !           528: flow6_validate(const byte *nlri, uint len)
        !           529: {
        !           530:   return flow_validate(nlri, len, 1);
        !           531: }
        !           532: 
        !           533: /**
        !           534:  * flow4_validate_cf - validate flowspec data structure &net_addr_flow4 in parsing time
        !           535:  * @f: flowspec data structure &net_addr_flow4
        !           536:  *
        !           537:  * Check if @f is valid flowspec data structure. Can call cf_error() function
        !           538:  * with a textual description of reason to failing of validation.
        !           539:  */
        !           540: void
        !           541: flow4_validate_cf(net_addr_flow4 *f)
        !           542: {
        !           543:   enum flow_validated_state r = flow4_validate(flow4_first_part(f), flow_read_length(f->data));
        !           544: 
        !           545:   if (r != FLOW_ST_VALID)
        !           546:     cf_error("Invalid flow route: %s", flow_validated_state_str(r));
        !           547: }
        !           548: 
        !           549: /**
        !           550:  * flow6_validate_cf - validate flowspec data structure &net_addr_flow6 in parsing time
        !           551:  * @f: flowspec data structure &net_addr_flow6
        !           552:  *
        !           553:  * Check if @f is valid flowspec data structure. Can call cf_error() function
        !           554:  * with a textual description of reason to failing of validation.
        !           555:  */
        !           556: void
        !           557: flow6_validate_cf(net_addr_flow6 *f)
        !           558: {
        !           559:   enum flow_validated_state r = flow6_validate(flow6_first_part(f), flow_read_length(f->data));
        !           560: 
        !           561:   if (r != FLOW_ST_VALID)
        !           562:     cf_error("Invalid flow route: %s", flow_validated_state_str(r));
        !           563: }
        !           564: 
        !           565: 
        !           566: /*
        !           567:  *     Flowspec Builder
        !           568:  */
        !           569: 
        !           570: /**
        !           571:  * flow_builder_init - constructor for flowspec builder instance
        !           572:  * @pool: memory pool
        !           573:  *
        !           574:  * This function prepares flowspec builder instance using memory pool @pool.
        !           575:  */
        !           576: struct flow_builder *
        !           577: flow_builder_init(pool *pool)
        !           578: {
        !           579:   struct flow_builder *fb = mb_allocz(pool, sizeof(struct flow_builder));
        !           580:   BUFFER_INIT(fb->data, pool, 4);
        !           581:   return fb;
        !           582: }
        !           583: 
        !           584: static int
        !           585: is_stackable_type(enum flow_type type)
        !           586: {
        !           587:   switch (type)
        !           588:   {
        !           589:   case FLOW_TYPE_IP_PROTOCOL:
        !           590:   case FLOW_TYPE_PORT:
        !           591:   case FLOW_TYPE_DST_PORT:
        !           592:   case FLOW_TYPE_SRC_PORT:
        !           593:   case FLOW_TYPE_ICMP_TYPE:
        !           594:   case FLOW_TYPE_ICMP_CODE:
        !           595:   case FLOW_TYPE_TCP_FLAGS:
        !           596:   case FLOW_TYPE_PACKET_LENGTH:
        !           597:   case FLOW_TYPE_DSCP:
        !           598:   case FLOW_TYPE_FRAGMENT:
        !           599:   case FLOW_TYPE_LABEL:
        !           600:     return 1;
        !           601: 
        !           602:   default:
        !           603:     /* The unknown components are not stack-able in default */
        !           604:     return 0;
        !           605:   }
        !           606: }
        !           607: 
        !           608: static int
        !           609: builder_add_prepare(struct flow_builder *fb)
        !           610: {
        !           611:   if (fb->parts[fb->this_type].length)
        !           612:   {
        !           613:     if (fb->last_type != fb->this_type)
        !           614:       return 0;
        !           615: 
        !           616:     if (!is_stackable_type(fb->this_type))
        !           617:       return 0;
        !           618:   }
        !           619:   else
        !           620:   {
        !           621:     fb->parts[fb->this_type].offset = fb->data.used;
        !           622:   }
        !           623: 
        !           624:   return 1;
        !           625: }
        !           626: 
        !           627: static void
        !           628: builder_add_finish(struct flow_builder *fb)
        !           629: {
        !           630:   fb->parts[fb->this_type].length = fb->data.used - fb->parts[fb->this_type].offset;
        !           631:   flow_builder_set_type(fb, fb->this_type);
        !           632: }
        !           633: 
        !           634: static void
        !           635: push_pfx_to_buffer(struct flow_builder *fb, u8 pxlen_bytes, byte *ip)
        !           636: {
        !           637:   for (int i = 0; i < pxlen_bytes; i++)
        !           638:     BUFFER_PUSH(fb->data) = *ip++;
        !           639: }
        !           640: 
        !           641: /**
        !           642:  * flow_builder4_add_pfx - add IPv4 prefix
        !           643:  * @fb: flowspec builder instance
        !           644:  * @n4: net address of type IPv4
        !           645:  *
        !           646:  * This function add IPv4 prefix into flowspec builder instance.
        !           647:  */
        !           648: int
        !           649: flow_builder4_add_pfx(struct flow_builder *fb, const net_addr_ip4 *n4)
        !           650: {
        !           651:   if (!builder_add_prepare(fb))
        !           652:     return 0;
        !           653: 
        !           654:   ip4_addr ip4 = ip4_hton(n4->prefix);
        !           655: 
        !           656:   BUFFER_PUSH(fb->data) = fb->this_type;
        !           657:   BUFFER_PUSH(fb->data) = n4->pxlen;
        !           658:   push_pfx_to_buffer(fb, BYTES(n4->pxlen), (byte *) &ip4);
        !           659: 
        !           660:   builder_add_finish(fb);
        !           661:   return 1;
        !           662: }
        !           663: 
        !           664: /**
        !           665:  * flow_builder6_add_pfx - add IPv6 prefix
        !           666:  * @fb: flowspec builder instance
        !           667:  * @n6: net address of type IPv4
        !           668:  * @pxoffset: prefix offset for @n6
        !           669:  *
        !           670:  * This function add IPv4 prefix into flowspec builder instance. This function
        !           671:  * should return 1 for successful adding, otherwise returns %0.
        !           672:  */
        !           673: int
        !           674: flow_builder6_add_pfx(struct flow_builder *fb, const net_addr_ip6 *n6, u32 pxoffset)
        !           675: {
        !           676:   if (!builder_add_prepare(fb))
        !           677:     return 0;
        !           678: 
        !           679:   ip6_addr ip6 = ip6_hton(n6->prefix);
        !           680: 
        !           681:   BUFFER_PUSH(fb->data) = fb->this_type;
        !           682:   BUFFER_PUSH(fb->data) = n6->pxlen;
        !           683:   BUFFER_PUSH(fb->data) = pxoffset;
        !           684:   push_pfx_to_buffer(fb, BYTES(n6->pxlen) - (pxoffset / 8), ((byte *) &ip6) + (pxoffset / 8));
        !           685: 
        !           686:   builder_add_finish(fb);
        !           687:   return 1;
        !           688: }
        !           689: 
        !           690: /**
        !           691:  * flow_builder_add_op_val - add operator/value pair
        !           692:  * @fb: flowspec builder instance
        !           693:  * @op: operator
        !           694:  * @value: value
        !           695:  *
        !           696:  * This function add operator/value pair as a part of a flowspec component. It
        !           697:  * is required to set appropriate flowspec component type using function
        !           698:  * flow_builder_set_type(). This function should return 1 for successful
        !           699:  * adding, otherwise returns 0.
        !           700:  */
        !           701: int
        !           702: flow_builder_add_op_val(struct flow_builder *fb, byte op, u32 value)
        !           703: {
        !           704:   if (!builder_add_prepare(fb))
        !           705:     return 0;
        !           706: 
        !           707:   if (fb->this_type == fb->last_type)
        !           708:   {
        !           709:     /* Remove the end-bit from last operand-value pair of the component */
        !           710:     fb->data.data[fb->last_op_offset] &= 0x7f;
        !           711:   }
        !           712:   else
        !           713:   {
        !           714:     BUFFER_PUSH(fb->data) = fb->this_type;
        !           715:   }
        !           716: 
        !           717:   fb->last_op_offset = fb->data.used;
        !           718: 
        !           719:   /* Set the end-bit for operand-value pair of the component */
        !           720:   op |= 0x80;
        !           721: 
        !           722:   if (value & 0xff00)
        !           723:   {
        !           724:     BUFFER_PUSH(fb->data) = op | 0x10;
        !           725:     put_u16(BUFFER_INC(fb->data, 2), value);
        !           726:   }
        !           727:   else
        !           728:   {
        !           729:     BUFFER_PUSH(fb->data) = op;
        !           730:     BUFFER_PUSH(fb->data) = (u8) value;
        !           731:   }
        !           732: 
        !           733:   builder_add_finish(fb);
        !           734:   return 1;
        !           735: }
        !           736: 
        !           737: /**
        !           738:  * flow_builder_add_val_mask - add value/bitmask pair
        !           739:  * @fb: flowspec builder instance
        !           740:  * @op: operator
        !           741:  * @value: value
        !           742:  * @mask: bitmask
        !           743:  *
        !           744:  * It is required to set appropriate flowspec component type using function
        !           745:  * flow_builder_set_type(). This function should return 1 for successful adding,
        !           746:  * otherwise returns 0.
        !           747:  */
        !           748: int
        !           749: flow_builder_add_val_mask(struct flow_builder *fb, byte op, u32 value, u32 mask)
        !           750: {
        !           751:   u32 a =  value & mask;
        !           752:   u32 b = ~value & mask;
        !           753: 
        !           754:   if (a)
        !           755:   {
        !           756:     flow_builder_add_op_val(fb, op ^ 0x01, a);
        !           757:     op |= FLOW_OP_AND;
        !           758:   }
        !           759: 
        !           760:   if (b)
        !           761:     flow_builder_add_op_val(fb, op ^ 0x02, b);
        !           762: 
        !           763:   return 1;
        !           764: }
        !           765: 
        !           766: 
        !           767: /**
        !           768:  * flow_builder_set_type - set type of next flowspec component
        !           769:  * @fb: flowspec builder instance
        !           770:  * @type: flowspec component type
        !           771:  *
        !           772:  * This function sets type of next flowspec component. It is necessary to call
        !           773:  * this function before each changing of adding flowspec component.
        !           774:  */
        !           775: void
        !           776: flow_builder_set_type(struct flow_builder *fb, enum flow_type type)
        !           777: {
        !           778:   fb->last_type = fb->this_type;
        !           779:   fb->this_type = type;
        !           780: }
        !           781: 
        !           782: static ip4_addr
        !           783: flow_read_ip4(const byte *px, uint pxlen)
        !           784: {
        !           785:   ip4_addr ip = IP4_NONE;
        !           786:   memcpy(&ip, px, BYTES(pxlen));
        !           787:   return ip4_ntoh(ip);
        !           788: }
        !           789: 
        !           790: static ip6_addr
        !           791: flow_read_ip6(const byte *px, uint pxlen, uint pxoffset)
        !           792: {
        !           793:   uint floor_offset = BYTES(pxoffset - (pxoffset % 8));
        !           794:   uint ceil_len = BYTES(pxlen);
        !           795:   ip6_addr ip = IP6_NONE;
        !           796: 
        !           797:   memcpy(((byte *) &ip) + floor_offset, px, ceil_len - floor_offset);
        !           798: 
        !           799:   return ip6_ntoh(ip);
        !           800: }
        !           801: 
        !           802: static void
        !           803: builder_write_parts(struct flow_builder *fb, byte *buf)
        !           804: {
        !           805:   for (int i = 1; i < FLOW_TYPE_MAX; i++)
        !           806:   {
        !           807:     if (fb->parts[i].length)
        !           808:     {
        !           809:       memcpy(buf, fb->data.data + fb->parts[i].offset, fb->parts[i].length);
        !           810:       buf += fb->parts[i].length;
        !           811:     }
        !           812:   }
        !           813: }
        !           814: 
        !           815: /**
        !           816:  * flow_builder4_finalize - assemble final flowspec data structure &net_addr_flow4
        !           817:  * @fb: flowspec builder instance
        !           818:  * @lpool: linear memory pool
        !           819:  *
        !           820:  * This function returns final flowspec data structure &net_addr_flow4 allocated
        !           821:  * onto @lpool linear memory pool.
        !           822:  */
        !           823: net_addr_flow4 *
        !           824: flow_builder4_finalize(struct flow_builder *fb, linpool *lpool)
        !           825: {
        !           826:   uint data_len = fb->data.used + (fb->data.used < 0xf0 ? 1 : 2);
        !           827:   net_addr_flow4 *f = lp_alloc(lpool, sizeof(struct net_addr_flow4) + data_len);
        !           828: 
        !           829:   ip4_addr prefix = IP4_NONE;
        !           830:   uint pxlen = 0;
        !           831: 
        !           832:   if (fb->parts[FLOW_TYPE_DST_PREFIX].length)
        !           833:   {
        !           834:     byte *p = fb->data.data + fb->parts[FLOW_TYPE_DST_PREFIX].offset + 1;
        !           835:     pxlen = *p++;
        !           836:     prefix = flow_read_ip4(p, pxlen);
        !           837:   }
        !           838:   *f = NET_ADDR_FLOW4(prefix, pxlen, data_len);
        !           839: 
        !           840:   builder_write_parts(fb, f->data + flow_write_length(f->data, fb->data.used));
        !           841: 
        !           842:   return f;
        !           843: }
        !           844: 
        !           845: /**
        !           846:  * flow_builder6_finalize - assemble final flowspec data structure &net_addr_flow6
        !           847:  * @fb: flowspec builder instance
        !           848:  * @lpool: linear memory pool for allocation of
        !           849:  *
        !           850:  * This function returns final flowspec data structure &net_addr_flow6 allocated
        !           851:  * onto @lpool linear memory pool.
        !           852:  */
        !           853: net_addr_flow6 *
        !           854: flow_builder6_finalize(struct flow_builder *fb, linpool *lpool)
        !           855: {
        !           856:   uint data_len =  fb->data.used + (fb->data.used < 0xf0 ? 1 : 2);
        !           857:   net_addr_flow6 *n = lp_alloc(lpool, sizeof(net_addr_flow6) + data_len);
        !           858: 
        !           859:   ip6_addr prefix = IP6_NONE;
        !           860:   uint pxlen = 0;
        !           861: 
        !           862:   if (fb->parts[FLOW_TYPE_DST_PREFIX].length)
        !           863:   {
        !           864:     byte *p = fb->data.data + fb->parts[FLOW_TYPE_DST_PREFIX].offset + 1;
        !           865:     pxlen = *p++;
        !           866:     uint pxoffset = *p++;
        !           867:     prefix = flow_read_ip6(p, pxlen, pxoffset);
        !           868:   }
        !           869:   *n = NET_ADDR_FLOW6(prefix, pxlen, data_len);
        !           870: 
        !           871:   builder_write_parts(fb, n->data + flow_write_length(n->data, fb->data.used));
        !           872: 
        !           873:   return n;
        !           874: }
        !           875: 
        !           876: /**
        !           877:  * flow_builder_clear - flush flowspec builder instance for another flowspec creation
        !           878:  * @fb: flowspec builder instance
        !           879:  *
        !           880:  * This function flushes all data from builder but it maintains pre-allocated
        !           881:  * buffer space.
        !           882:  */
        !           883: void
        !           884: flow_builder_clear(struct flow_builder *fb)
        !           885: {
        !           886:   BUFFER(byte) data;
        !           887:   BUFFER_FLUSH(fb->data);
        !           888: 
        !           889:   BUFFER_SHALLOW_COPY(data, fb->data);
        !           890:   memset(fb, 0, sizeof(struct flow_builder));
        !           891:   BUFFER_SHALLOW_COPY(fb->data, data);
        !           892: }
        !           893: 
        !           894: 
        !           895: /*
        !           896:  *     Net Formatting
        !           897:  */
        !           898: 
        !           899: /* Flowspec operators for [op, value]+ pairs */
        !           900: 
        !           901: static const char *
        !           902: num_op_str(const byte *op)
        !           903: {
        !           904:   switch (*op & 0x07)
        !           905:   {
        !           906:   case FLOW_OP_TRUE:   return "true";
        !           907:   case FLOW_OP_EQ:     return "=";
        !           908:   case FLOW_OP_GT:     return ">";
        !           909:   case FLOW_OP_GEQ:    return ">=";
        !           910:   case FLOW_OP_LT:     return "<";
        !           911:   case FLOW_OP_LEQ:    return "<=";
        !           912:   case FLOW_OP_NEQ:    return "!=";
        !           913:   case FLOW_OP_FALSE:  return "false";
        !           914:   }
        !           915: 
        !           916:   return NULL;
        !           917: }
        !           918: 
        !           919: static uint
        !           920: get_value(const byte *val, u8 len)
        !           921: {
        !           922:   switch (len)
        !           923:   {
        !           924:   case 1: return *val;
        !           925:   case 2: return get_u16(val);
        !           926:   case 4: return get_u32(val);
        !           927:   // No component may have length 8
        !           928:   // case 8: return get_u64(val);
        !           929:   }
        !           930: 
        !           931:   return 0;
        !           932: }
        !           933: 
        !           934: static const char *
        !           935: fragment_val_str(u8 val)
        !           936: {
        !           937:   switch (val)
        !           938:   {
        !           939:   case 1: return "dont_fragment";
        !           940:   case 2: return "is_fragment";
        !           941:   case 4: return "first_fragment";
        !           942:   case 8: return "last_fragment";
        !           943:   }
        !           944:   return "???";
        !           945: }
        !           946: 
        !           947: static void
        !           948: net_format_flow_ip(buffer *b, const byte *part, int ipv6)
        !           949: {
        !           950:   uint pxlen = *(part+1);
        !           951:   if (ipv6)
        !           952:   {
        !           953:     uint pxoffset = *(part+2);
        !           954:     if (pxoffset)
        !           955:       buffer_print(b, "%I6/%u offset %u; ", flow_read_ip6(part+3,pxlen,pxoffset), pxlen, pxoffset);
        !           956:     else
        !           957:       buffer_print(b, "%I6/%u; ", flow_read_ip6(part+3,pxlen,0), pxlen);
        !           958:   }
        !           959:   else
        !           960:   {
        !           961:     buffer_print(b, "%I4/%u; ", flow_read_ip4(part+2,pxlen), pxlen);
        !           962:   }
        !           963: }
        !           964: 
        !           965: static void
        !           966: net_format_flow_num(buffer *b, const byte *part)
        !           967: {
        !           968:   const byte *last_op = NULL;
        !           969:   const byte *op = part+1;
        !           970:   uint val;
        !           971:   uint len;
        !           972:   uint first = 1;
        !           973: 
        !           974:   while (1)
        !           975:   {
        !           976:     if (!first)
        !           977:     {
        !           978:       /* XXX: I don't like this so complicated if-tree */
        !           979:       if (!isset_and(op) &&
        !           980:          ((num_op(     op) == FLOW_OP_EQ) || (num_op(     op) == FLOW_OP_GEQ)) &&
        !           981:          ((num_op(last_op) == FLOW_OP_EQ) || (num_op(last_op) == FLOW_OP_LEQ)))
        !           982:       {
        !           983:        b->pos--; /* Remove last char (it is a space) */
        !           984:        buffer_puts(b, ",");
        !           985:       }
        !           986:       else
        !           987:       {
        !           988:        buffer_puts(b, isset_and(op) ? "&& " : "|| ");
        !           989:       }
        !           990:     }
        !           991:     first = 0;
        !           992: 
        !           993:     len = get_value_length(op);
        !           994:     val = get_value(op+1, len);
        !           995: 
        !           996:     if (!isset_end(op) && !isset_and(op) && isset_and(op+1+len) &&
        !           997:        (num_op(op) == FLOW_OP_GEQ) && (num_op(op+1+len) == FLOW_OP_LEQ))
        !           998:     {
        !           999:       /* Display interval */
        !          1000:       buffer_print(b, "%u..", val);
        !          1001:       op += 1 + len;
        !          1002:       len = get_value_length(op);
        !          1003:       val = get_value(op+1, len);
        !          1004:       buffer_print(b, "%u", val);
        !          1005:     }
        !          1006:     else if (num_op(op) == FLOW_OP_EQ)
        !          1007:     {
        !          1008:       buffer_print(b, "%u", val);
        !          1009:     }
        !          1010:     else
        !          1011:     {
        !          1012:       buffer_print(b, "%s %u", num_op_str(op), val);
        !          1013:     }
        !          1014: 
        !          1015:     if (isset_end(op))
        !          1016:     {
        !          1017:       buffer_puts(b, "; ");
        !          1018:       break;
        !          1019:     }
        !          1020:     else
        !          1021:     {
        !          1022:       buffer_puts(b, " ");
        !          1023:     }
        !          1024: 
        !          1025:     last_op = op;
        !          1026:     op += 1 + len;
        !          1027:   }
        !          1028: }
        !          1029: 
        !          1030: static void
        !          1031: net_format_flow_bitmask(buffer *b, const byte *part)
        !          1032: {
        !          1033:   const byte *op = part+1;
        !          1034:   uint val;
        !          1035:   uint len;
        !          1036:   uint first = 1;
        !          1037: 
        !          1038:   while (1)
        !          1039:   {
        !          1040:     if (!first)
        !          1041:     {
        !          1042:       if (isset_and(op))
        !          1043:       {
        !          1044:        b->pos--; /* Remove last char (it is a space) */
        !          1045:        buffer_puts(b, ",");
        !          1046:       }
        !          1047:       else
        !          1048:       {
        !          1049:        buffer_puts(b, "|| ");
        !          1050:       }
        !          1051:     }
        !          1052:     first = 0;
        !          1053: 
        !          1054:     len = get_value_length(op);
        !          1055:     val = get_value(op+1, len);
        !          1056: 
        !          1057:     /*
        !          1058:      *   Not Match  Show
        !          1059:      *  ------------------
        !          1060:      *    0    0    !0/B
        !          1061:      *    0    1     B/B
        !          1062:      *    1    0     0/B
        !          1063:      *    1    1    !B/B
        !          1064:      */
        !          1065: 
        !          1066:     if ((*op & 0x3) == 0x3 || (*op & 0x3) == 0)
        !          1067:       buffer_puts(b, "!");
        !          1068: 
        !          1069:     if (*part == FLOW_TYPE_FRAGMENT && (val == 1 || val == 2 || val == 4 || val == 8))
        !          1070:       buffer_print(b, "%s%s", ((*op & 0x1) ? "" : "!"), fragment_val_str(val));
        !          1071:     else
        !          1072:       buffer_print(b, "0x%x/0x%x", ((*op & 0x1) ? val : 0), val);
        !          1073: 
        !          1074:     if (isset_end(op))
        !          1075:     {
        !          1076:       buffer_puts(b, "; ");
        !          1077:       break;
        !          1078:     }
        !          1079:     else
        !          1080:     {
        !          1081:       buffer_puts(b, " ");
        !          1082:     }
        !          1083: 
        !          1084:     op += 1 + len;
        !          1085:   }
        !          1086: }
        !          1087: 
        !          1088: static uint
        !          1089: net_format_flow(char *buf, uint blen, const byte *data, uint dlen, int ipv6)
        !          1090: {
        !          1091:   buffer b = {
        !          1092:     .start = buf,
        !          1093:     .pos = buf,
        !          1094:     .end = buf + blen,
        !          1095:   };
        !          1096: 
        !          1097:   const byte *part = flow_first_part(data);
        !          1098:   *buf = 0;
        !          1099: 
        !          1100:   if (ipv6)
        !          1101:     buffer_puts(&b, "flow6 { ");
        !          1102:   else
        !          1103:     buffer_puts(&b, "flow4 { ");
        !          1104: 
        !          1105:   while (part)
        !          1106:   {
        !          1107:     buffer_print(&b, "%s ", flow_type_str(*part, ipv6));
        !          1108: 
        !          1109:     switch (*part)
        !          1110:     {
        !          1111:     case FLOW_TYPE_DST_PREFIX:
        !          1112:     case FLOW_TYPE_SRC_PREFIX:
        !          1113:       net_format_flow_ip(&b, part, ipv6);
        !          1114:       break;
        !          1115:     case FLOW_TYPE_IP_PROTOCOL: /* == FLOW_TYPE_NEXT_HEADER */
        !          1116:     case FLOW_TYPE_PORT:
        !          1117:     case FLOW_TYPE_DST_PORT:
        !          1118:     case FLOW_TYPE_SRC_PORT:
        !          1119:     case FLOW_TYPE_ICMP_TYPE:
        !          1120:     case FLOW_TYPE_ICMP_CODE:
        !          1121:     case FLOW_TYPE_PACKET_LENGTH:
        !          1122:     case FLOW_TYPE_DSCP:
        !          1123:       net_format_flow_num(&b, part);
        !          1124:       break;
        !          1125:     case FLOW_TYPE_TCP_FLAGS:
        !          1126:     case FLOW_TYPE_FRAGMENT:
        !          1127:     case FLOW_TYPE_LABEL:
        !          1128:       net_format_flow_bitmask(&b, part);
        !          1129:       break;
        !          1130:     }
        !          1131: 
        !          1132:     part = flow_next_part(part, data+dlen, ipv6);
        !          1133:   }
        !          1134: 
        !          1135:   buffer_puts(&b, "}");
        !          1136: 
        !          1137:   if (b.pos == b.end)
        !          1138:   {
        !          1139:     b.pos = b.start + MIN(blen - 6, strlen(b.start));
        !          1140:     buffer_puts(&b, " ...}");
        !          1141:   }
        !          1142: 
        !          1143:   return b.pos - b.start;
        !          1144: }
        !          1145: 
        !          1146: /**
        !          1147:  * flow4_net_format - stringify flowspec data structure &net_addr_flow4
        !          1148:  * @buf: pre-allocated buffer for writing a stringify net address flowspec
        !          1149:  * @blen: free allocated space in @buf
        !          1150:  * @f: flowspec data structure &net_addr_flow4 for stringify
        !          1151:  *
        !          1152:  * This function writes stringified @f into @buf. The function returns number
        !          1153:  * of written chars. If final string is too large, the string will ends the with
        !          1154:  * ' ...}' sequence and zero-terminator.
        !          1155:  */
        !          1156: uint
        !          1157: flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f)
        !          1158: {
        !          1159:   return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow4), 0);
        !          1160: }
        !          1161: 
        !          1162: /**
        !          1163:  * flow6_net_format - stringify flowspec data structure &net_addr_flow6
        !          1164:  * @buf: pre-allocated buffer for writing a stringify net address flowspec
        !          1165:  * @blen: free allocated space in @buf
        !          1166:  * @f: flowspec data structure &net_addr_flow4 for stringify
        !          1167:  *
        !          1168:  * This function writes stringified @f into @buf. The function returns number
        !          1169:  * of written chars. If final string is too large, the string will ends the with
        !          1170:  * ' ...}' sequence and zero-terminator.
        !          1171:  */
        !          1172: uint
        !          1173: flow6_net_format(char *buf, uint blen, const net_addr_flow6 *f)
        !          1174: {
        !          1175:   return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow6), 1);
        !          1176: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>