Annotation of embedaddon/bird/proto/babel/packets.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  *     BIRD -- The Babel protocol
        !             3:  *
        !             4:  *     Copyright (c) 2015--2016 Toke Hoiland-Jorgensen
        !             5:  *
        !             6:  *     Can be freely distributed and used under the terms of the GNU GPL.
        !             7:  *
        !             8:  *     This file contains the packet and TLV handling code for the protocol.
        !             9:  */
        !            10: 
        !            11: #include "babel.h"
        !            12: 
        !            13: 
        !            14: struct babel_pkt_header {
        !            15:   u8 magic;
        !            16:   u8 version;
        !            17:   u16 length;
        !            18: } PACKED;
        !            19: 
        !            20: struct babel_tlv {
        !            21:   u8 type;
        !            22:   u8 length;
        !            23:   u8 value[0];
        !            24: } PACKED;
        !            25: 
        !            26: struct babel_tlv_ack_req {
        !            27:   u8 type;
        !            28:   u8 length;
        !            29:   u16 reserved;
        !            30:   u16 nonce;
        !            31:   u16 interval;
        !            32: } PACKED;
        !            33: 
        !            34: struct babel_tlv_ack {
        !            35:   u8 type;
        !            36:   u8 length;
        !            37:   u16 nonce;
        !            38: } PACKED;
        !            39: 
        !            40: struct babel_tlv_hello {
        !            41:   u8 type;
        !            42:   u8 length;
        !            43:   u16 reserved;
        !            44:   u16 seqno;
        !            45:   u16 interval;
        !            46: } PACKED;
        !            47: 
        !            48: struct babel_tlv_ihu {
        !            49:   u8 type;
        !            50:   u8 length;
        !            51:   u8 ae;
        !            52:   u8 reserved;
        !            53:   u16 rxcost;
        !            54:   u16 interval;
        !            55:   u8 addr[0];
        !            56: } PACKED;
        !            57: 
        !            58: struct babel_tlv_router_id {
        !            59:   u8 type;
        !            60:   u8 length;
        !            61:   u16 reserved;
        !            62:   u64 router_id;
        !            63: } PACKED;
        !            64: 
        !            65: struct babel_tlv_next_hop {
        !            66:   u8 type;
        !            67:   u8 length;
        !            68:   u8 ae;
        !            69:   u8 reserved;
        !            70:   u8 addr[0];
        !            71: } PACKED;
        !            72: 
        !            73: struct babel_tlv_update {
        !            74:   u8 type;
        !            75:   u8 length;
        !            76:   u8 ae;
        !            77:   u8 flags;
        !            78:   u8 plen;
        !            79:   u8 omitted;
        !            80:   u16 interval;
        !            81:   u16 seqno;
        !            82:   u16 metric;
        !            83:   u8 addr[0];
        !            84: } PACKED;
        !            85: 
        !            86: struct babel_tlv_route_request {
        !            87:   u8 type;
        !            88:   u8 length;
        !            89:   u8 ae;
        !            90:   u8 plen;
        !            91:   u8 addr[0];
        !            92: } PACKED;
        !            93: 
        !            94: struct babel_tlv_seqno_request {
        !            95:   u8 type;
        !            96:   u8 length;
        !            97:   u8 ae;
        !            98:   u8 plen;
        !            99:   u16 seqno;
        !           100:   u8 hop_count;
        !           101:   u8 reserved;
        !           102:   u64 router_id;
        !           103:   u8 addr[0];
        !           104: } PACKED;
        !           105: 
        !           106: 
        !           107: #define BABEL_FLAG_DEF_PREFIX  0x80
        !           108: #define BABEL_FLAG_ROUTER_ID   0x40
        !           109: 
        !           110: 
        !           111: struct babel_parse_state {
        !           112:   struct babel_proto *proto;
        !           113:   struct babel_iface *ifa;
        !           114:   ip_addr saddr;
        !           115:   ip_addr next_hop;
        !           116:   u64 router_id;               /* Router ID used in subsequent updates */
        !           117:   u8 def_ip6_prefix[16];       /* Implicit IPv6 prefix in network order */
        !           118:   u8 def_ip4_prefix[4];                /* Implicit IPv4 prefix in network order */
        !           119:   u8 router_id_seen;           /* router_id field is valid */
        !           120:   u8 def_ip6_prefix_seen;      /* def_ip6_prefix is valid */
        !           121:   u8 def_ip4_prefix_seen;      /* def_ip4_prefix is valid */
        !           122: };
        !           123: 
        !           124: enum parse_result {
        !           125:   PARSE_SUCCESS,
        !           126:   PARSE_ERROR,
        !           127:   PARSE_IGNORE,
        !           128: };
        !           129: 
        !           130: struct babel_write_state {
        !           131:   u64 router_id;
        !           132:   u8 router_id_seen;
        !           133: //  ip_addr next_hop;
        !           134: };
        !           135: 
        !           136: 
        !           137: #define DROP(DSC,VAL) do { err_dsc = DSC; err_val = VAL; goto drop; } while(0)
        !           138: #define DROP1(DSC) do { err_dsc = DSC; goto drop; } while(0)
        !           139: #define LOG_PKT(msg, args...) \
        !           140:   log_rl(&p->log_pkt_tbf, L_REMOTE "%s: " msg, p->p.name, args)
        !           141: 
        !           142: #define FIRST_TLV(p) ((struct babel_tlv *) (((struct babel_pkt_header *) p) + 1))
        !           143: #define NEXT_TLV(t) ((struct babel_tlv *) (((byte *) t) + TLV_LENGTH(t)))
        !           144: #define TLV_LENGTH(t) (t->type == BABEL_TLV_PAD1 ? 1 : t->length + sizeof(struct babel_tlv))
        !           145: #define TLV_OPT_LENGTH(t) (t->length + sizeof(struct babel_tlv) - sizeof(*t))
        !           146: #define TLV_HDR(tlv,t,l) ({ tlv->type = t; tlv->length = l - sizeof(struct babel_tlv); })
        !           147: #define TLV_HDR0(tlv,t) TLV_HDR(tlv, t, tlv_data[t].min_length)
        !           148: 
        !           149: #define BYTES(n) ((((uint) n) + 7) / 8)
        !           150: 
        !           151: static inline u16
        !           152: get_time16(const void *p)
        !           153: {
        !           154:   u16 v = get_u16(p) / BABEL_TIME_UNITS;
        !           155:   return MAX(1, v);
        !           156: }
        !           157: 
        !           158: static inline void
        !           159: put_time16(void *p, u16 v)
        !           160: {
        !           161:   put_u16(p, v * BABEL_TIME_UNITS);
        !           162: }
        !           163: 
        !           164: static inline ip6_addr
        !           165: get_ip6_px(const void *p, uint plen)
        !           166: {
        !           167:   ip6_addr addr = IPA_NONE;
        !           168:   memcpy(&addr, p, BYTES(plen));
        !           169:   return ip6_ntoh(addr);
        !           170: }
        !           171: 
        !           172: static inline void
        !           173: put_ip6_px(void *p, ip6_addr addr, uint plen)
        !           174: {
        !           175:   addr = ip6_hton(addr);
        !           176:   memcpy(p, &addr, BYTES(plen));
        !           177: }
        !           178: 
        !           179: static inline ip6_addr
        !           180: get_ip6_ll(const void *p)
        !           181: {
        !           182:   return ip6_build(0xfe800000, 0, get_u32(p+0), get_u32(p+4));
        !           183: }
        !           184: 
        !           185: static inline void
        !           186: put_ip6_ll(void *p, ip6_addr addr)
        !           187: {
        !           188:   put_u32(p+0, _I2(addr));
        !           189:   put_u32(p+4, _I3(addr));
        !           190: }
        !           191: 
        !           192: 
        !           193: /*
        !           194:  *     TLV read/write functions
        !           195:  */
        !           196: 
        !           197: static int babel_read_ack_req(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
        !           198: static int babel_read_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
        !           199: static int babel_read_ihu(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
        !           200: static int babel_read_router_id(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
        !           201: static int babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
        !           202: static int babel_read_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
        !           203: static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
        !           204: static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
        !           205: 
        !           206: static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
        !           207: static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
        !           208: static uint babel_write_ihu(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
        !           209: static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
        !           210: static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
        !           211: static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
        !           212: 
        !           213: struct babel_tlv_data {
        !           214:   u8 min_length;
        !           215:   int (*read_tlv)(struct babel_tlv *hdr, union babel_msg *m, struct babel_parse_state *state);
        !           216:   uint (*write_tlv)(struct babel_tlv *hdr, union babel_msg *m, struct babel_write_state *state, uint max_len);
        !           217:   void (*handle_tlv)(union babel_msg *m, struct babel_iface *ifa);
        !           218: };
        !           219: 
        !           220: static const struct babel_tlv_data tlv_data[BABEL_TLV_MAX] = {
        !           221:   [BABEL_TLV_ACK_REQ] = {
        !           222:     sizeof(struct babel_tlv_ack_req),
        !           223:     babel_read_ack_req,
        !           224:     NULL,
        !           225:     babel_handle_ack_req
        !           226:   },
        !           227:   [BABEL_TLV_ACK] = {
        !           228:     sizeof(struct babel_tlv_ack),
        !           229:     NULL,
        !           230:     babel_write_ack,
        !           231:     NULL
        !           232:   },
        !           233:   [BABEL_TLV_HELLO] = {
        !           234:     sizeof(struct babel_tlv_hello),
        !           235:     babel_read_hello,
        !           236:     babel_write_hello,
        !           237:     babel_handle_hello
        !           238:   },
        !           239:   [BABEL_TLV_IHU] = {
        !           240:     sizeof(struct babel_tlv_ihu),
        !           241:     babel_read_ihu,
        !           242:     babel_write_ihu,
        !           243:     babel_handle_ihu
        !           244:   },
        !           245:   [BABEL_TLV_ROUTER_ID] = {
        !           246:     sizeof(struct babel_tlv_router_id),
        !           247:     babel_read_router_id,
        !           248:     NULL,
        !           249:     NULL
        !           250:   },
        !           251:   [BABEL_TLV_NEXT_HOP] = {
        !           252:     sizeof(struct babel_tlv_next_hop),
        !           253:     babel_read_next_hop,
        !           254:     NULL,
        !           255:     NULL
        !           256:   },
        !           257:   [BABEL_TLV_UPDATE] = {
        !           258:     sizeof(struct babel_tlv_update),
        !           259:     babel_read_update,
        !           260:     babel_write_update,
        !           261:     babel_handle_update
        !           262:   },
        !           263:   [BABEL_TLV_ROUTE_REQUEST] = {
        !           264:     sizeof(struct babel_tlv_route_request),
        !           265:     babel_read_route_request,
        !           266:     babel_write_route_request,
        !           267:     babel_handle_route_request
        !           268:   },
        !           269:   [BABEL_TLV_SEQNO_REQUEST] = {
        !           270:     sizeof(struct babel_tlv_seqno_request),
        !           271:     babel_read_seqno_request,
        !           272:     babel_write_seqno_request,
        !           273:     babel_handle_seqno_request
        !           274:   },
        !           275: };
        !           276: 
        !           277: static int
        !           278: babel_read_ack_req(struct babel_tlv *hdr, union babel_msg *m,
        !           279:                   struct babel_parse_state *state)
        !           280: {
        !           281:   struct babel_tlv_ack_req *tlv = (void *) hdr;
        !           282:   struct babel_msg_ack_req *msg = &m->ack_req;
        !           283: 
        !           284:   msg->type = BABEL_TLV_ACK_REQ;
        !           285:   msg->nonce = get_u16(&tlv->nonce);
        !           286:   msg->interval = get_time16(&tlv->interval);
        !           287:   msg->sender = state->saddr;
        !           288: 
        !           289:   if (!msg->interval)
        !           290:     return PARSE_ERROR;
        !           291: 
        !           292:   return PARSE_SUCCESS;
        !           293: }
        !           294: 
        !           295: static uint
        !           296: babel_write_ack(struct babel_tlv *hdr, union babel_msg *m,
        !           297:                 struct babel_write_state *state UNUSED, uint max_len UNUSED)
        !           298: {
        !           299:   struct babel_tlv_ack *tlv = (void *) hdr;
        !           300:   struct babel_msg_ack *msg = &m->ack;
        !           301: 
        !           302:   TLV_HDR0(tlv, BABEL_TLV_ACK);
        !           303:   put_u16(&tlv->nonce, msg->nonce);
        !           304: 
        !           305:   return sizeof(struct babel_tlv_ack);
        !           306: }
        !           307: 
        !           308: static int
        !           309: babel_read_hello(struct babel_tlv *hdr, union babel_msg *m,
        !           310:                  struct babel_parse_state *state)
        !           311: {
        !           312:   struct babel_tlv_hello *tlv = (void *) hdr;
        !           313:   struct babel_msg_hello *msg = &m->hello;
        !           314: 
        !           315:   msg->type = BABEL_TLV_HELLO;
        !           316:   msg->seqno = get_u16(&tlv->seqno);
        !           317:   msg->interval = get_time16(&tlv->interval);
        !           318:   msg->sender = state->saddr;
        !           319: 
        !           320:   return PARSE_SUCCESS;
        !           321: }
        !           322: 
        !           323: static uint
        !           324: babel_write_hello(struct babel_tlv *hdr, union babel_msg *m,
        !           325:                   struct babel_write_state *state UNUSED, uint max_len UNUSED)
        !           326: {
        !           327:   struct babel_tlv_hello *tlv = (void *) hdr;
        !           328:   struct babel_msg_hello *msg = &m->hello;
        !           329: 
        !           330:   TLV_HDR0(tlv, BABEL_TLV_HELLO);
        !           331:   put_u16(&tlv->seqno, msg->seqno);
        !           332:   put_time16(&tlv->interval, msg->interval);
        !           333: 
        !           334:   return sizeof(struct babel_tlv_hello);
        !           335: }
        !           336: 
        !           337: static int
        !           338: babel_read_ihu(struct babel_tlv *hdr, union babel_msg *m,
        !           339:                struct babel_parse_state *state)
        !           340: {
        !           341:   struct babel_tlv_ihu *tlv = (void *) hdr;
        !           342:   struct babel_msg_ihu *msg = &m->ihu;
        !           343: 
        !           344:   msg->type = BABEL_TLV_IHU;
        !           345:   msg->ae = tlv->ae;
        !           346:   msg->rxcost = get_u16(&tlv->rxcost);
        !           347:   msg->interval = get_time16(&tlv->interval);
        !           348:   msg->addr = IPA_NONE;
        !           349:   msg->sender = state->saddr;
        !           350: 
        !           351:   if (msg->ae >= BABEL_AE_MAX)
        !           352:     return PARSE_IGNORE;
        !           353: 
        !           354:   // We handle link-local IPs. In every other case, the addr field will be 0 but
        !           355:   // validation will succeed. The handler takes care of these cases.
        !           356:   if (msg->ae == BABEL_AE_IP6_LL)
        !           357:   {
        !           358:     if (TLV_OPT_LENGTH(tlv) < 8)
        !           359:       return PARSE_ERROR;
        !           360: 
        !           361:     msg->addr = ipa_from_ip6(get_ip6_ll(&tlv->addr));
        !           362:   }
        !           363: 
        !           364:   return PARSE_SUCCESS;
        !           365: }
        !           366: 
        !           367: static uint
        !           368: babel_write_ihu(struct babel_tlv *hdr, union babel_msg *m,
        !           369:                 struct babel_write_state *state UNUSED, uint max_len)
        !           370: {
        !           371:   struct babel_tlv_ihu *tlv = (void *) hdr;
        !           372:   struct babel_msg_ihu *msg = &m->ihu;
        !           373: 
        !           374:   if (ipa_is_link_local(msg->addr) && max_len < sizeof(struct babel_tlv_ihu) + 8)
        !           375:     return 0;
        !           376: 
        !           377:   TLV_HDR0(tlv, BABEL_TLV_IHU);
        !           378:   put_u16(&tlv->rxcost, msg->rxcost);
        !           379:   put_time16(&tlv->interval, msg->interval);
        !           380: 
        !           381:   if (!ipa_is_link_local(msg->addr))
        !           382:   {
        !           383:     tlv->ae = BABEL_AE_WILDCARD;
        !           384:     return sizeof(struct babel_tlv_ihu);
        !           385:   }
        !           386:   put_ip6_ll(&tlv->addr, msg->addr);
        !           387:   tlv->ae = BABEL_AE_IP6_LL;
        !           388:   hdr->length += 8;
        !           389:   return sizeof(struct babel_tlv_ihu) + 8;
        !           390: }
        !           391: 
        !           392: static int
        !           393: babel_read_router_id(struct babel_tlv *hdr, union babel_msg *m UNUSED,
        !           394:                      struct babel_parse_state *state)
        !           395: {
        !           396:   struct babel_tlv_router_id *tlv = (void *) hdr;
        !           397: 
        !           398:   state->router_id = get_u64(&tlv->router_id);
        !           399:   state->router_id_seen = 1;
        !           400: 
        !           401:   return PARSE_IGNORE;
        !           402: }
        !           403: 
        !           404: /* This is called directly from babel_write_update() */
        !           405: static uint
        !           406: babel_write_router_id(struct babel_tlv *hdr, u64 router_id,
        !           407:                      struct babel_write_state *state, uint max_len UNUSED)
        !           408: {
        !           409:   struct babel_tlv_router_id *tlv = (void *) hdr;
        !           410: 
        !           411:   /* We still assume that first min_length bytes are available and zeroed */
        !           412: 
        !           413:   TLV_HDR0(tlv, BABEL_TLV_ROUTER_ID);
        !           414:   put_u64(&tlv->router_id, router_id);
        !           415: 
        !           416:   state->router_id = router_id;
        !           417:   state->router_id_seen = 1;
        !           418: 
        !           419:   return sizeof(struct babel_tlv_router_id);
        !           420: }
        !           421: 
        !           422: static int
        !           423: babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED,
        !           424:                     struct babel_parse_state *state)
        !           425: {
        !           426:   struct babel_tlv_next_hop *tlv = (void *) hdr;
        !           427: 
        !           428:   switch (tlv->ae)
        !           429:   {
        !           430:   case BABEL_AE_WILDCARD:
        !           431:     return PARSE_ERROR;
        !           432: 
        !           433:   case BABEL_AE_IP4:
        !           434:     /* TODO */
        !           435:     return PARSE_IGNORE;
        !           436: 
        !           437:   case BABEL_AE_IP6:
        !           438:     if (TLV_OPT_LENGTH(tlv) < sizeof(ip6_addr))
        !           439:       return PARSE_ERROR;
        !           440: 
        !           441:     state->next_hop = ipa_from_ip6(get_ip6(&tlv->addr));
        !           442:     return PARSE_IGNORE;
        !           443: 
        !           444:   case BABEL_AE_IP6_LL:
        !           445:     if (TLV_OPT_LENGTH(tlv) < 8)
        !           446:       return PARSE_ERROR;
        !           447: 
        !           448:     state->next_hop = ipa_from_ip6(get_ip6_ll(&tlv->addr));
        !           449:     return PARSE_IGNORE;
        !           450: 
        !           451:   default:
        !           452:     return PARSE_IGNORE;
        !           453:   }
        !           454: 
        !           455:   return PARSE_IGNORE;
        !           456: }
        !           457: 
        !           458: static int
        !           459: babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
        !           460:                   struct babel_parse_state *state)
        !           461: {
        !           462:   struct babel_tlv_update *tlv = (void *) hdr;
        !           463:   struct babel_msg_update *msg = &m->update;
        !           464: 
        !           465:   msg->type = BABEL_TLV_UPDATE;
        !           466:   msg->interval = get_time16(&tlv->interval);
        !           467:   msg->seqno = get_u16(&tlv->seqno);
        !           468:   msg->metric = get_u16(&tlv->metric);
        !           469: 
        !           470:   /* Length of received prefix data without omitted part */
        !           471:   int len = BYTES(tlv->plen) - (int) tlv->omitted;
        !           472:   u8 buf[16] = {};
        !           473: 
        !           474:   if ((len < 0) || ((uint) len > TLV_OPT_LENGTH(tlv)))
        !           475:     return PARSE_ERROR;
        !           476: 
        !           477:   switch (tlv->ae)
        !           478:   {
        !           479:   case BABEL_AE_WILDCARD:
        !           480:     if (tlv->plen > 0)
        !           481:       return PARSE_ERROR;
        !           482: 
        !           483:     msg->wildcard = 1;
        !           484:     break;
        !           485: 
        !           486:   case BABEL_AE_IP4:
        !           487:     /* TODO */
        !           488:     return PARSE_IGNORE;
        !           489: 
        !           490:   case BABEL_AE_IP6:
        !           491:     if (tlv->plen > MAX_PREFIX_LENGTH)
        !           492:       return PARSE_ERROR;
        !           493: 
        !           494:     /* Cannot omit data if there is no saved prefix */
        !           495:     if (tlv->omitted && !state->def_ip6_prefix_seen)
        !           496:       return PARSE_ERROR;
        !           497: 
        !           498:     /* Merge saved prefix and received prefix parts */
        !           499:     memcpy(buf, state->def_ip6_prefix, tlv->omitted);
        !           500:     memcpy(buf + tlv->omitted, tlv->addr, len);
        !           501: 
        !           502:     msg->plen = tlv->plen;
        !           503:     msg->prefix = ipa_from_ip6(get_ip6(buf));
        !           504: 
        !           505:     if (tlv->flags & BABEL_FLAG_DEF_PREFIX)
        !           506:     {
        !           507:       put_ip6(state->def_ip6_prefix, msg->prefix);
        !           508:       state->def_ip6_prefix_seen = 1;
        !           509:     }
        !           510: 
        !           511:     if (tlv->flags & BABEL_FLAG_ROUTER_ID)
        !           512:     {
        !           513:       state->router_id = ((u64) _I2(msg->prefix)) << 32 | _I3(msg->prefix);
        !           514:       state->router_id_seen = 1;
        !           515:     }
        !           516:     break;
        !           517: 
        !           518:   case BABEL_AE_IP6_LL:
        !           519:     /* ??? */
        !           520:     return PARSE_IGNORE;
        !           521: 
        !           522:   default:
        !           523:     return PARSE_IGNORE;
        !           524:   }
        !           525: 
        !           526:   /* Update must have Router ID, unless it is retraction */
        !           527:   if (!state->router_id_seen && (msg->metric != BABEL_INFINITY))
        !           528:   {
        !           529:     DBG("Babel: No router ID seen before update\n");
        !           530:     return PARSE_ERROR;
        !           531:   }
        !           532: 
        !           533:   msg->router_id = state->router_id;
        !           534:   msg->next_hop = state->next_hop;
        !           535:   msg->sender = state->saddr;
        !           536: 
        !           537:   return PARSE_SUCCESS;
        !           538: }
        !           539: 
        !           540: static uint
        !           541: babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
        !           542:                    struct babel_write_state *state, uint max_len)
        !           543: {
        !           544:   struct babel_tlv_update *tlv = (void *) hdr;
        !           545:   struct babel_msg_update *msg = &m->update;
        !           546:   uint len0 = 0;
        !           547: 
        !           548:   /*
        !           549:    * When needed, we write Router-ID TLV before Update TLV and return size of
        !           550:    * both of them. There is enough space for the Router-ID TLV, because
        !           551:    * sizeof(struct babel_tlv_router_id) == sizeof(struct babel_tlv_update).
        !           552:    *
        !           553:    * Router ID is not used for retractions, so do not us it in such case.
        !           554:    */
        !           555:   if ((msg->metric < BABEL_INFINITY) &&
        !           556:       (!state->router_id_seen || (msg->router_id != state->router_id)))
        !           557:   {
        !           558:     len0 = babel_write_router_id(hdr, msg->router_id, state, max_len);
        !           559:     tlv = (struct babel_tlv_update *) NEXT_TLV(tlv);
        !           560:   }
        !           561: 
        !           562:   uint len = sizeof(struct babel_tlv_update) + BYTES(msg->plen);
        !           563: 
        !           564:   if (len0 + len > max_len)
        !           565:     return 0;
        !           566: 
        !           567:   memset(tlv, 0, sizeof(struct babel_tlv_update));
        !           568:   TLV_HDR(tlv, BABEL_TLV_UPDATE, len);
        !           569: 
        !           570:   if (msg->wildcard)
        !           571:   {
        !           572:     tlv->ae = BABEL_AE_WILDCARD;
        !           573:     tlv->plen = 0;
        !           574:   }
        !           575:   else
        !           576:   {
        !           577:     tlv->ae = BABEL_AE_IP6;
        !           578:     tlv->plen = msg->plen;
        !           579:     put_ip6_px(tlv->addr, msg->prefix, msg->plen);
        !           580:   }
        !           581: 
        !           582:   put_time16(&tlv->interval, msg->interval);
        !           583:   put_u16(&tlv->seqno, msg->seqno);
        !           584:   put_u16(&tlv->metric, msg->metric);
        !           585: 
        !           586:   return len0 + len;
        !           587: }
        !           588: 
        !           589: static int
        !           590: babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
        !           591:                          struct babel_parse_state *state UNUSED)
        !           592: {
        !           593:   struct babel_tlv_route_request *tlv = (void *) hdr;
        !           594:   struct babel_msg_route_request *msg = &m->route_request;
        !           595: 
        !           596:   msg->type = BABEL_TLV_ROUTE_REQUEST;
        !           597: 
        !           598:   switch (tlv->ae)
        !           599:   {
        !           600:   case BABEL_AE_WILDCARD:
        !           601:     /* Wildcard requests must have plen 0 */
        !           602:     if (tlv->plen > 0)
        !           603:       return PARSE_ERROR;
        !           604: 
        !           605:     msg->full = 1;
        !           606:     return PARSE_SUCCESS;
        !           607: 
        !           608:   case BABEL_AE_IP4:
        !           609:     /* TODO */
        !           610:     return PARSE_IGNORE;
        !           611: 
        !           612:   case BABEL_AE_IP6:
        !           613:     if (tlv->plen > MAX_PREFIX_LENGTH)
        !           614:       return PARSE_ERROR;
        !           615: 
        !           616:     if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen))
        !           617:       return PARSE_ERROR;
        !           618: 
        !           619:     msg->plen = tlv->plen;
        !           620:     msg->prefix = get_ip6_px(tlv->addr, tlv->plen);
        !           621:     return PARSE_SUCCESS;
        !           622: 
        !           623:   case BABEL_AE_IP6_LL:
        !           624:     return PARSE_ERROR;
        !           625: 
        !           626:   default:
        !           627:     return PARSE_IGNORE;
        !           628:   }
        !           629: 
        !           630:   return PARSE_IGNORE;
        !           631: }
        !           632: 
        !           633: static uint
        !           634: babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
        !           635:                          struct babel_write_state *state UNUSED, uint max_len)
        !           636: {
        !           637:   struct babel_tlv_route_request *tlv = (void *) hdr;
        !           638:   struct babel_msg_route_request *msg = &m->route_request;
        !           639: 
        !           640:   uint len = sizeof(struct babel_tlv_route_request) + BYTES(msg->plen);
        !           641: 
        !           642:   if (len > max_len)
        !           643:     return 0;
        !           644: 
        !           645:   TLV_HDR(tlv, BABEL_TLV_ROUTE_REQUEST, len);
        !           646: 
        !           647:   if (msg->full)
        !           648:   {
        !           649:     tlv->ae = BABEL_AE_WILDCARD;
        !           650:     tlv->plen = 0;
        !           651:   }
        !           652:   else
        !           653:   {
        !           654:     tlv->ae = BABEL_AE_IP6;
        !           655:     tlv->plen = msg->plen;
        !           656:     put_ip6_px(tlv->addr, msg->prefix, msg->plen);
        !           657:   }
        !           658: 
        !           659:   return len;
        !           660: }
        !           661: 
        !           662: static int
        !           663: babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
        !           664:                          struct babel_parse_state *state)
        !           665: {
        !           666:   struct babel_tlv_seqno_request *tlv = (void *) hdr;
        !           667:   struct babel_msg_seqno_request *msg = &m->seqno_request;
        !           668: 
        !           669:   msg->type = BABEL_TLV_SEQNO_REQUEST;
        !           670:   msg->seqno = get_u16(&tlv->seqno);
        !           671:   msg->hop_count = tlv->hop_count;
        !           672:   msg->router_id = get_u64(&tlv->router_id);
        !           673:   msg->sender = state->saddr;
        !           674: 
        !           675:   if (tlv->hop_count == 0)
        !           676:     return PARSE_ERROR;
        !           677: 
        !           678:   switch (tlv->ae)
        !           679:   {
        !           680:   case BABEL_AE_WILDCARD:
        !           681:     return PARSE_ERROR;
        !           682: 
        !           683:   case BABEL_AE_IP4:
        !           684:     /* TODO */
        !           685:     return PARSE_IGNORE;
        !           686: 
        !           687:   case BABEL_AE_IP6:
        !           688:     if (tlv->plen > MAX_PREFIX_LENGTH)
        !           689:       return PARSE_ERROR;
        !           690: 
        !           691:     if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen))
        !           692:       return PARSE_ERROR;
        !           693: 
        !           694:     msg->plen = tlv->plen;
        !           695:     msg->prefix = get_ip6_px(tlv->addr, tlv->plen);
        !           696:     return PARSE_SUCCESS;
        !           697: 
        !           698:   case BABEL_AE_IP6_LL:
        !           699:     return PARSE_ERROR;
        !           700: 
        !           701:   default:
        !           702:     return PARSE_IGNORE;
        !           703:   }
        !           704: 
        !           705:   return PARSE_IGNORE;
        !           706: }
        !           707: 
        !           708: static uint
        !           709: babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
        !           710:                          struct babel_write_state *state UNUSED, uint max_len)
        !           711: {
        !           712:   struct babel_tlv_seqno_request *tlv = (void *) hdr;
        !           713:   struct babel_msg_seqno_request *msg = &m->seqno_request;
        !           714: 
        !           715:   uint len = sizeof(struct babel_tlv_seqno_request) + BYTES(msg->plen);
        !           716: 
        !           717:   if (len > max_len)
        !           718:     return 0;
        !           719: 
        !           720:   TLV_HDR(tlv, BABEL_TLV_SEQNO_REQUEST, len);
        !           721:   tlv->ae = BABEL_AE_IP6;
        !           722:   tlv->plen = msg->plen;
        !           723:   put_u16(&tlv->seqno, msg->seqno);
        !           724:   tlv->hop_count = msg->hop_count;
        !           725:   put_u64(&tlv->router_id, msg->router_id);
        !           726:   put_ip6_px(tlv->addr, msg->prefix, msg->plen);
        !           727: 
        !           728:   return len;
        !           729: }
        !           730: 
        !           731: static inline int
        !           732: babel_read_tlv(struct babel_tlv *hdr,
        !           733:                union babel_msg *msg,
        !           734:                struct babel_parse_state *state)
        !           735: {
        !           736:   if ((hdr->type <= BABEL_TLV_PADN) ||
        !           737:       (hdr->type >= BABEL_TLV_MAX) ||
        !           738:       !tlv_data[hdr->type].read_tlv)
        !           739:     return PARSE_IGNORE;
        !           740: 
        !           741:   if (TLV_LENGTH(hdr) < tlv_data[hdr->type].min_length)
        !           742:     return PARSE_ERROR;
        !           743: 
        !           744:   memset(msg, 0, sizeof(*msg));
        !           745:   return tlv_data[hdr->type].read_tlv(hdr, msg, state);
        !           746: }
        !           747: 
        !           748: static uint
        !           749: babel_write_tlv(struct babel_tlv *hdr,
        !           750:                union babel_msg *msg,
        !           751:                struct babel_write_state *state,
        !           752:                uint max_len)
        !           753: {
        !           754:   if ((msg->type <= BABEL_TLV_PADN) ||
        !           755:       (msg->type >= BABEL_TLV_MAX) ||
        !           756:       !tlv_data[msg->type].write_tlv)
        !           757:     return 0;
        !           758: 
        !           759:   if (tlv_data[msg->type].min_length > max_len)
        !           760:     return 0;
        !           761: 
        !           762:   memset(hdr, 0, tlv_data[msg->type].min_length);
        !           763:   return tlv_data[msg->type].write_tlv(hdr, msg, state, max_len);
        !           764: }
        !           765: 
        !           766: 
        !           767: /*
        !           768:  *     Packet RX/TX functions
        !           769:  */
        !           770: 
        !           771: static int
        !           772: babel_send_to(struct babel_iface *ifa, ip_addr dest)
        !           773: {
        !           774:   sock *sk = ifa->sk;
        !           775:   struct babel_pkt_header *hdr = (void *) sk->tbuf;
        !           776:   int len = get_u16(&hdr->length) + sizeof(struct babel_pkt_header);
        !           777: 
        !           778:   DBG("Babel: Sending %d bytes to %I\n", len, dest);
        !           779:   return sk_send_to(sk, len, dest, 0);
        !           780: }
        !           781: 
        !           782: /**
        !           783:  * babel_write_queue - Write a TLV queue to a transmission buffer
        !           784:  * @ifa: Interface holding the transmission buffer
        !           785:  * @queue: TLV queue to write (containing internal-format TLVs)
        !           786:  *
        !           787:  * This function writes a packet to the interface transmission buffer with as
        !           788:  * many TLVs from the &queue as will fit in the buffer. It returns the number of
        !           789:  * bytes written (NOT counting the packet header). The function is called by
        !           790:  * babel_send_queue() and babel_send_unicast() to construct packets for
        !           791:  * transmission, and uses per-TLV helper functions to convert the
        !           792:  * internal-format TLVs to their wire representations.
        !           793:  *
        !           794:  * The TLVs in the queue are freed after they are written to the buffer.
        !           795:  */
        !           796: static uint
        !           797: babel_write_queue(struct babel_iface *ifa, list *queue)
        !           798: {
        !           799:   struct babel_proto *p = ifa->proto;
        !           800:   struct babel_write_state state = {};
        !           801: 
        !           802:   if (EMPTY_LIST(*queue))
        !           803:     return 0;
        !           804: 
        !           805:   byte *pos = ifa->sk->tbuf;
        !           806:   byte *end = pos + ifa->tx_length;
        !           807: 
        !           808:   struct babel_pkt_header *pkt = (void *) pos;
        !           809:   pkt->magic = BABEL_MAGIC;
        !           810:   pkt->version = BABEL_VERSION;
        !           811:   pkt->length = 0;
        !           812:   pos += sizeof(struct babel_pkt_header);
        !           813: 
        !           814:   struct babel_msg_node *msg;
        !           815:   WALK_LIST_FIRST(msg, *queue)
        !           816:   {
        !           817:     if (pos >= end)
        !           818:       break;
        !           819: 
        !           820:     int len = babel_write_tlv((struct babel_tlv *) pos, &msg->msg, &state, end - pos);
        !           821: 
        !           822:     if (!len)
        !           823:       break;
        !           824: 
        !           825:     pos += len;
        !           826:     rem_node(NODE msg);
        !           827:     sl_free(p->msg_slab, msg);
        !           828:   }
        !           829: 
        !           830:   uint plen = pos - (byte *) pkt;
        !           831:   put_u16(&pkt->length, plen - sizeof(struct babel_pkt_header));
        !           832: 
        !           833:   return plen;
        !           834: }
        !           835: 
        !           836: void
        !           837: babel_send_queue(void *arg)
        !           838: {
        !           839:   struct babel_iface *ifa = arg;
        !           840:   while ((babel_write_queue(ifa, &ifa->msg_queue) > 0) &&
        !           841:         (babel_send_to(ifa, IP6_BABEL_ROUTERS) > 0));
        !           842: }
        !           843: 
        !           844: static inline void
        !           845: babel_kick_queue(struct babel_iface *ifa)
        !           846: {
        !           847:   /*
        !           848:    * Only schedule send event if there is not already data in the socket buffer.
        !           849:    * Otherwise we may overwrite the data already in the buffer.
        !           850:    */
        !           851: 
        !           852:   if ((ifa->sk->tpos == ifa->sk->tbuf) && !ev_active(ifa->send_event))
        !           853:     ev_schedule(ifa->send_event);
        !           854: }
        !           855: 
        !           856: /**
        !           857:  * babel_send_unicast - send a single TLV via unicast to a destination
        !           858:  * @msg: TLV to send
        !           859:  * @ifa: Interface to send via
        !           860:  * @dest: Destination of the TLV
        !           861:  *
        !           862:  * This function is used to send a single TLV via unicast to a designated
        !           863:  * receiver. This is used for replying to certain incoming requests, and for
        !           864:  * sending unicast requests to refresh routes before they expire.
        !           865:  */
        !           866: void
        !           867: babel_send_unicast(union babel_msg *msg, struct babel_iface *ifa, ip_addr dest)
        !           868: {
        !           869:   struct babel_proto *p = ifa->proto;
        !           870:   struct babel_msg_node *msgn = sl_alloc(p->msg_slab);
        !           871:   list queue;
        !           872: 
        !           873:   msgn->msg = *msg;
        !           874:   init_list(&queue);
        !           875:   add_tail(&queue, NODE msgn);
        !           876:   babel_write_queue(ifa, &queue);
        !           877:   babel_send_to(ifa, dest);
        !           878: 
        !           879:   /* We could overwrite waiting packet here, we may have to kick TX queue */
        !           880:   if (!EMPTY_LIST(ifa->msg_queue))
        !           881:     babel_kick_queue(ifa);
        !           882: }
        !           883: 
        !           884: /**
        !           885:  * babel_enqueue - enqueue a TLV for transmission on an interface
        !           886:  * @msg: TLV to enqueue (in internal TLV format)
        !           887:  * @ifa: Interface to enqueue to
        !           888:  *
        !           889:  * This function is called to enqueue a TLV for subsequent transmission on an
        !           890:  * interface. The transmission event is triggered whenever a TLV is enqueued;
        !           891:  * this ensures that TLVs will be transmitted in a timely manner, but that TLVs
        !           892:  * which are enqueued in rapid succession can be transmitted together in one
        !           893:  * packet.
        !           894:  */
        !           895: void
        !           896: babel_enqueue(union babel_msg *msg, struct babel_iface *ifa)
        !           897: {
        !           898:   struct babel_proto *p = ifa->proto;
        !           899:   struct babel_msg_node *msgn = sl_alloc(p->msg_slab);
        !           900:   msgn->msg = *msg;
        !           901:   add_tail(&ifa->msg_queue, NODE msgn);
        !           902:   babel_kick_queue(ifa);
        !           903: }
        !           904: 
        !           905: /**
        !           906:  * babel_process_packet - process incoming data packet
        !           907:  * @pkt: Pointer to the packet data
        !           908:  * @len: Length of received packet
        !           909:  * @saddr: Address of packet sender
        !           910:  * @ifa: Interface packet was received on.
        !           911:  *
        !           912:  * This function is the main processing hook of incoming Babel packets. It
        !           913:  * checks that the packet header is well-formed, then processes the TLVs
        !           914:  * contained in the packet. This is done in two passes: First all TLVs are
        !           915:  * parsed into the internal TLV format. If a TLV parser fails, processing of the
        !           916:  * rest of the packet is aborted.
        !           917:  *
        !           918:  * After the parsing step, the TLV handlers are called for each parsed TLV in
        !           919:  * order.
        !           920:  */
        !           921: static void
        !           922: babel_process_packet(struct babel_pkt_header *pkt, int len,
        !           923:                      ip_addr saddr, struct babel_iface *ifa)
        !           924: {
        !           925:   struct babel_proto *p = ifa->proto;
        !           926:   struct babel_tlv *tlv;
        !           927:   struct babel_msg_node *msg;
        !           928:   list msgs;
        !           929:   int res;
        !           930: 
        !           931:   int plen = sizeof(struct babel_pkt_header) + get_u16(&pkt->length);
        !           932:   byte *pos;
        !           933:   byte *end = (byte *)pkt + plen;
        !           934: 
        !           935:   struct babel_parse_state state = {
        !           936:     .proto     = p,
        !           937:     .ifa       = ifa,
        !           938:     .saddr     = saddr,
        !           939:     .next_hop  = saddr,
        !           940:   };
        !           941: 
        !           942:   if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))
        !           943:   {
        !           944:     TRACE(D_PACKETS, "Strange packet from %I via %s - magic %d version %d",
        !           945:          saddr, ifa->iface->name, pkt->magic, pkt->version);
        !           946:     return;
        !           947:   }
        !           948: 
        !           949:   if (plen > len)
        !           950:   {
        !           951:     LOG_PKT("Bad packet from %I via %s - %s (%u)",
        !           952:            saddr, ifa->iface->name, "length mismatch", plen);
        !           953:     return;
        !           954:   }
        !           955: 
        !           956:   TRACE(D_PACKETS, "Packet received from %I via %s",
        !           957:         saddr, ifa->iface->name);
        !           958: 
        !           959:   init_list(&msgs);
        !           960: 
        !           961:   /* First pass through the packet TLV by TLV, parsing each into internal data
        !           962:      structures. */
        !           963:   for (tlv = FIRST_TLV(pkt);
        !           964:        (byte *)tlv < end;
        !           965:        tlv = NEXT_TLV(tlv))
        !           966:   {
        !           967:     /* Ugly special case */
        !           968:     if (tlv->type == BABEL_TLV_PAD1)
        !           969:       continue;
        !           970: 
        !           971:     /* The end of the common TLV header */
        !           972:     pos = (byte *)tlv + sizeof(struct babel_tlv);
        !           973:     if ((pos > end) || (pos + tlv->length > end))
        !           974:     {
        !           975:       LOG_PKT("Bad TLV from %I via %s type %d pos %d - framing error",
        !           976:              saddr, ifa->iface->name, tlv->type, (byte *)tlv - (byte *)pkt);
        !           977:       break;
        !           978:     }
        !           979: 
        !           980:     msg = sl_alloc(p->msg_slab);
        !           981:     res = babel_read_tlv(tlv, &msg->msg, &state);
        !           982:     if (res == PARSE_SUCCESS)
        !           983:     {
        !           984:       add_tail(&msgs, NODE msg);
        !           985:     }
        !           986:     else if (res == PARSE_IGNORE)
        !           987:     {
        !           988:       DBG("Babel: Ignoring TLV of type %d\n", tlv->type);
        !           989:       sl_free(p->msg_slab, msg);
        !           990:     }
        !           991:     else /* PARSE_ERROR */
        !           992:     {
        !           993:       LOG_PKT("Bad TLV from %I via %s type %d pos %d - parse error",
        !           994:              saddr, ifa->iface->name, tlv->type, (byte *)tlv - (byte *)pkt);
        !           995:       sl_free(p->msg_slab, msg);
        !           996:       break;
        !           997:     }
        !           998:   }
        !           999: 
        !          1000:   /* Parsing done, handle all parsed TLVs */
        !          1001:   WALK_LIST_FIRST(msg, msgs)
        !          1002:   {
        !          1003:     if (tlv_data[msg->msg.type].handle_tlv)
        !          1004:       tlv_data[msg->msg.type].handle_tlv(&msg->msg, ifa);
        !          1005:     rem_node(NODE msg);
        !          1006:     sl_free(p->msg_slab, msg);
        !          1007:   }
        !          1008: }
        !          1009: 
        !          1010: static void
        !          1011: babel_err_hook(sock *sk, int err)
        !          1012: {
        !          1013:   struct babel_iface *ifa = sk->data;
        !          1014:   struct babel_proto *p = ifa->proto;
        !          1015: 
        !          1016:   log(L_ERR "%s: Socket error on %s: %M", p->p.name, ifa->iface->name, err);
        !          1017:   /* FIXME: Drop queued TLVs here? */
        !          1018: }
        !          1019: 
        !          1020: 
        !          1021: static void
        !          1022: babel_tx_hook(sock *sk)
        !          1023: {
        !          1024:   struct babel_iface *ifa = sk->data;
        !          1025: 
        !          1026:   DBG("Babel: TX hook called (iface %s, src %I, dst %I)\n",
        !          1027:       sk->iface->name, sk->saddr, sk->daddr);
        !          1028: 
        !          1029:   babel_send_queue(ifa);
        !          1030: }
        !          1031: 
        !          1032: 
        !          1033: static int
        !          1034: babel_rx_hook(sock *sk, uint len)
        !          1035: {
        !          1036:   struct babel_iface *ifa = sk->data;
        !          1037:   struct babel_proto *p = ifa->proto;
        !          1038:   const char *err_dsc = NULL;
        !          1039:   uint err_val = 0;
        !          1040: 
        !          1041:   if (sk->lifindex != ifa->iface->index)
        !          1042:     return 1;
        !          1043: 
        !          1044:   DBG("Babel: RX hook called (iface %s, src %I, dst %I)\n",
        !          1045:       sk->iface->name, sk->faddr, sk->laddr);
        !          1046: 
        !          1047:   /* Silently ignore my own packets */
        !          1048:   if (ipa_equal(ifa->iface->addr->ip, sk->faddr))
        !          1049:     return 1;
        !          1050: 
        !          1051:   if (!ipa_is_link_local(sk->faddr))
        !          1052:     DROP1("wrong src address");
        !          1053: 
        !          1054:   if (sk->fport != ifa->cf->port)
        !          1055:     DROP("wrong src port", sk->fport);
        !          1056: 
        !          1057:   if (len < sizeof(struct babel_pkt_header))
        !          1058:     DROP("too short", len);
        !          1059: 
        !          1060:   if (sk->flags & SKF_TRUNCATED)
        !          1061:     DROP("truncated", len);
        !          1062: 
        !          1063:   babel_process_packet((struct babel_pkt_header *) sk->rbuf, len, sk->faddr, ifa);
        !          1064:   return 1;
        !          1065: 
        !          1066: drop:
        !          1067:   LOG_PKT("Bad packet from %I via %s - %s (%u)",
        !          1068:          sk->faddr, sk->iface->name, err_dsc, err_val);
        !          1069:   return 1;
        !          1070: }
        !          1071: 
        !          1072: int
        !          1073: babel_open_socket(struct babel_iface *ifa)
        !          1074: {
        !          1075:   struct babel_proto *p = ifa->proto;
        !          1076: 
        !          1077:   sock *sk;
        !          1078:   sk = sk_new(ifa->pool);
        !          1079:   sk->type = SK_UDP;
        !          1080:   sk->sport = ifa->cf->port;
        !          1081:   sk->dport = ifa->cf->port;
        !          1082:   sk->iface = ifa->iface;
        !          1083: 
        !          1084:   sk->rx_hook = babel_rx_hook;
        !          1085:   sk->tx_hook = babel_tx_hook;
        !          1086:   sk->err_hook = babel_err_hook;
        !          1087:   sk->data = ifa;
        !          1088: 
        !          1089:   sk->tos = ifa->cf->tx_tos;
        !          1090:   sk->priority = ifa->cf->tx_priority;
        !          1091:   sk->ttl = 1;
        !          1092:   sk->flags = SKF_LADDR_RX;
        !          1093: 
        !          1094:   if (sk_open(sk) < 0)
        !          1095:     goto err;
        !          1096: 
        !          1097:   if (sk_setup_multicast(sk) < 0)
        !          1098:     goto err;
        !          1099: 
        !          1100:   if (sk_join_group(sk, IP6_BABEL_ROUTERS) < 0)
        !          1101:     goto err;
        !          1102: 
        !          1103:   ifa->sk = sk;
        !          1104:   return 1;
        !          1105: 
        !          1106: err:
        !          1107:   sk_log_error(sk, p->p.name);
        !          1108:   rfree(sk);
        !          1109:   return 0;
        !          1110: }

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