Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 1998-2004  Hannes Gredler <hannes (at) tcpdump.org>
      3  *      The TCPDUMP project
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that: (1) source code
      7  * distributions retain the above copyright notice and this paragraph
      8  * in its entirety, and (2) distributions including binary code include
      9  * the above copyright notice and this paragraph in its entirety in
     10  * the documentation or other materials provided with the distribution.
     11  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
     12  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
     13  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     14  * FOR A PARTICULAR PURPOSE.
     15  */
     16 
     17 #ifndef lint
     18 static const char rcsid[] _U_ =
     19     "@(#) $Header: /tcpdump/master/tcpdump/print-eigrp.c,v 1.5.2.2 2005/05/06 02:53:41 guy Exp $";
     20 #endif
     21 
     22 #ifdef HAVE_CONFIG_H
     23 #include "config.h"
     24 #endif
     25 
     26 #include <tcpdump-stdinc.h>
     27 
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <string.h>
     31 
     32 #include "interface.h"
     33 #include "extract.h"
     34 #include "addrtoname.h"
     35 
     36 /*
     37  * packet format documented at
     38  * http://www.rhyshaden.com/eigrp.htm
     39  */
     40 
     41 struct eigrp_common_header {
     42     u_int8_t version;
     43     u_int8_t opcode;
     44     u_int8_t checksum[2];
     45     u_int8_t flags[4];
     46     u_int8_t seq[4];
     47     u_int8_t ack[4];
     48     u_int8_t asn[4];
     49 };
     50 
     51 #define	EIGRP_VERSION                        2
     52 
     53 #define	EIGRP_OPCODE_UPDATE                  1
     54 #define	EIGRP_OPCODE_QUERY                   3
     55 #define	EIGRP_OPCODE_REPLY                   4
     56 #define	EIGRP_OPCODE_HELLO                   5
     57 #define	EIGRP_OPCODE_IPXSAP                  6
     58 #define	EIGRP_OPCODE_PROBE                   7
     59 
     60 static const struct tok eigrp_opcode_values[] = {
     61     { EIGRP_OPCODE_UPDATE, "Update" },
     62     { EIGRP_OPCODE_QUERY, "Query" },
     63     { EIGRP_OPCODE_REPLY, "Reply" },
     64     { EIGRP_OPCODE_HELLO, "Hello" },
     65     { EIGRP_OPCODE_IPXSAP, "IPX SAP" },
     66     { EIGRP_OPCODE_PROBE, "Probe" },
     67     { 0, NULL}
     68 };
     69 
     70 static const struct tok eigrp_common_header_flag_values[] = {
     71     { 0x01, "Init" },
     72     { 0x02, "Conditionally Received" },
     73     { 0, NULL}
     74 };
     75 
     76 struct eigrp_tlv_header {
     77     u_int8_t type[2];
     78     u_int8_t length[2];
     79 };
     80 
     81 #define EIGRP_TLV_GENERAL_PARM   0x0001
     82 #define EIGRP_TLV_AUTH           0x0002
     83 #define EIGRP_TLV_SEQ            0x0003
     84 #define EIGRP_TLV_SW_VERSION     0x0004
     85 #define EIGRP_TLV_MCAST_SEQ      0x0005
     86 #define EIGRP_TLV_IP_INT         0x0102
     87 #define EIGRP_TLV_IP_EXT         0x0103
     88 #define EIGRP_TLV_AT_INT         0x0202
     89 #define EIGRP_TLV_AT_EXT         0x0203
     90 #define EIGRP_TLV_AT_CABLE_SETUP 0x0204
     91 #define EIGRP_TLV_IPX_INT        0x0302
     92 #define EIGRP_TLV_IPX_EXT        0x0303
     93 
     94 static const struct tok eigrp_tlv_values[] = {
     95     { EIGRP_TLV_GENERAL_PARM, "General Parameters"},
     96     { EIGRP_TLV_AUTH, "Authentication"},
     97     { EIGRP_TLV_SEQ, "Sequence"},
     98     { EIGRP_TLV_SW_VERSION, "Software Version"},
     99     { EIGRP_TLV_MCAST_SEQ, "Next Multicast Sequence"},
    100     { EIGRP_TLV_IP_INT, "IP Internal routes"},
    101     { EIGRP_TLV_IP_EXT, "IP External routes"},
    102     { EIGRP_TLV_AT_INT, "AppleTalk Internal routes"},
    103     { EIGRP_TLV_AT_EXT, "AppleTalk External routes"},
    104     { EIGRP_TLV_AT_CABLE_SETUP, "AppleTalk Cable setup"},
    105     { EIGRP_TLV_IPX_INT, "IPX Internal routes"},
    106     { EIGRP_TLV_IPX_EXT, "IPX External routes"},
    107     { 0, NULL}
    108 };
    109 
    110 struct eigrp_tlv_general_parm_t {
    111     u_int8_t k1;
    112     u_int8_t k2;
    113     u_int8_t k3;
    114     u_int8_t k4;
    115     u_int8_t k5;
    116     u_int8_t res;
    117     u_int8_t holdtime[2];
    118 };
    119 
    120 struct eigrp_tlv_sw_version_t {
    121     u_int8_t ios_major;
    122     u_int8_t ios_minor;
    123     u_int8_t eigrp_major;
    124     u_int8_t eigrp_minor;
    125 };
    126 
    127 struct eigrp_tlv_ip_int_t {
    128     u_int8_t nexthop[4];
    129     u_int8_t delay[4];
    130     u_int8_t bandwidth[4];
    131     u_int8_t mtu[3];
    132     u_int8_t hopcount;
    133     u_int8_t reliability;
    134     u_int8_t load;
    135     u_int8_t reserved[2];
    136     u_int8_t plen;
    137     u_int8_t destination; /* variable length [1-4] bytes encoding */
    138 };
    139 
    140 struct eigrp_tlv_ip_ext_t {
    141     u_int8_t nexthop[4];
    142     u_int8_t origin_router[4];
    143     u_int8_t origin_as[4];
    144     u_int8_t tag[4];
    145     u_int8_t metric[4];
    146     u_int8_t reserved[2];
    147     u_int8_t proto_id;
    148     u_int8_t flags;
    149     u_int8_t delay[4];
    150     u_int8_t bandwidth[4];
    151     u_int8_t mtu[3];
    152     u_int8_t hopcount;
    153     u_int8_t reliability;
    154     u_int8_t load;
    155     u_int8_t reserved2[2];
    156     u_int8_t plen;
    157     u_int8_t destination; /* variable length [1-4] bytes encoding */
    158 };
    159 
    160 struct eigrp_tlv_at_cable_setup_t {
    161     u_int8_t cable_start[2];
    162     u_int8_t cable_end[2];
    163     u_int8_t router_id[4];
    164 };
    165 
    166 struct eigrp_tlv_at_int_t {
    167     u_int8_t nexthop[4];
    168     u_int8_t delay[4];
    169     u_int8_t bandwidth[4];
    170     u_int8_t mtu[3];
    171     u_int8_t hopcount;
    172     u_int8_t reliability;
    173     u_int8_t load;
    174     u_int8_t reserved[2];
    175     u_int8_t cable_start[2];
    176     u_int8_t cable_end[2];
    177 };
    178 
    179 struct eigrp_tlv_at_ext_t {
    180     u_int8_t nexthop[4];
    181     u_int8_t origin_router[4];
    182     u_int8_t origin_as[4];
    183     u_int8_t tag[4];
    184     u_int8_t proto_id;
    185     u_int8_t flags;
    186     u_int8_t metric[2];
    187     u_int8_t delay[4];
    188     u_int8_t bandwidth[4];
    189     u_int8_t mtu[3];
    190     u_int8_t hopcount;
    191     u_int8_t reliability;
    192     u_int8_t load;
    193     u_int8_t reserved2[2];
    194     u_int8_t cable_start[2];
    195     u_int8_t cable_end[2];
    196 };
    197 
    198 static const struct tok eigrp_ext_proto_id_values[] = {
    199     { 0x01, "IGRP" },
    200     { 0x02, "EIGRP" },
    201     { 0x03, "Static" },
    202     { 0x04, "RIP" },
    203     { 0x05, "Hello" },
    204     { 0x06, "OSPF" },
    205     { 0x07, "IS-IS" },
    206     { 0x08, "EGP" },
    207     { 0x09, "BGP" },
    208     { 0x0a, "IDRP" },
    209     { 0x0b, "Connected" },
    210     { 0, NULL}
    211 };
    212 
    213 void
    214 eigrp_print(register const u_char *pptr, register u_int len) {
    215 
    216     const struct eigrp_common_header *eigrp_com_header;
    217     const struct eigrp_tlv_header *eigrp_tlv_header;
    218     const u_char *tptr,*tlv_tptr;
    219     u_int tlen,eigrp_tlv_len,eigrp_tlv_type,tlv_tlen, byte_length, bit_length;
    220     u_int8_t prefix[4];
    221 
    222     union {
    223         const struct eigrp_tlv_general_parm_t *eigrp_tlv_general_parm;
    224         const struct eigrp_tlv_sw_version_t *eigrp_tlv_sw_version;
    225         const struct eigrp_tlv_ip_int_t *eigrp_tlv_ip_int;
    226         const struct eigrp_tlv_ip_ext_t *eigrp_tlv_ip_ext;
    227         const struct eigrp_tlv_at_cable_setup_t *eigrp_tlv_at_cable_setup;
    228         const struct eigrp_tlv_at_int_t *eigrp_tlv_at_int;
    229         const struct eigrp_tlv_at_ext_t *eigrp_tlv_at_ext;
    230     } tlv_ptr;
    231 
    232     tptr=pptr;
    233     eigrp_com_header = (const struct eigrp_common_header *)pptr;
    234     TCHECK(*eigrp_com_header);
    235 
    236     /*
    237      * Sanity checking of the header.
    238      */
    239     if (eigrp_com_header->version != EIGRP_VERSION) {
    240 	printf("EIGRP version %u packet not supported",eigrp_com_header->version);
    241 	return;
    242     }
    243 
    244     /* in non-verbose mode just lets print the basic Message Type*/
    245     if (vflag < 1) {
    246         printf("EIGRP %s, length: %u",
    247                tok2str(eigrp_opcode_values, "unknown (%u)",eigrp_com_header->opcode),
    248                len);
    249         return;
    250     }
    251 
    252     /* ok they seem to want to know everything - lets fully decode it */
    253 
    254     tlen=len-sizeof(struct eigrp_common_header);
    255 
    256     /* FIXME print other header info */
    257     printf("\n\tEIGRP v%u, opcode: %s (%u), chksum: 0x%04x, Flags: [%s]\n\tseq: 0x%08x, ack: 0x%08x, AS: %u, length: %u",
    258            eigrp_com_header->version,
    259            tok2str(eigrp_opcode_values, "unknown, type: %u",eigrp_com_header->opcode),
    260            eigrp_com_header->opcode,
    261            EXTRACT_16BITS(&eigrp_com_header->checksum),
    262            tok2str(eigrp_common_header_flag_values,
    263                    "none",
    264                    EXTRACT_32BITS(&eigrp_com_header->flags)),
    265            EXTRACT_32BITS(&eigrp_com_header->seq),
    266            EXTRACT_32BITS(&eigrp_com_header->ack),
    267            EXTRACT_32BITS(&eigrp_com_header->asn),
    268            tlen);
    269 
    270     tptr+=sizeof(const struct eigrp_common_header);
    271 
    272     while(tlen>0) {
    273         /* did we capture enough for fully decoding the object header ? */
    274         TCHECK2(*tptr, sizeof(struct eigrp_tlv_header));
    275 
    276         eigrp_tlv_header = (const struct eigrp_tlv_header *)tptr;
    277         eigrp_tlv_len=EXTRACT_16BITS(&eigrp_tlv_header->length);
    278         eigrp_tlv_type=EXTRACT_16BITS(&eigrp_tlv_header->type);
    279 
    280 
    281         if (eigrp_tlv_len < sizeof(struct eigrp_tlv_header) ||
    282             eigrp_tlv_len > tlen) {
    283             print_unknown_data(tptr+sizeof(sizeof(struct eigrp_tlv_header)),"\n\t    ",tlen);
    284             return;
    285         }
    286 
    287         printf("\n\t  %s TLV (0x%04x), length: %u",
    288                tok2str(eigrp_tlv_values,
    289                        "Unknown",
    290                        eigrp_tlv_type),
    291                eigrp_tlv_type,
    292                eigrp_tlv_len);
    293 
    294         tlv_tptr=tptr+sizeof(struct eigrp_tlv_header);
    295         tlv_tlen=eigrp_tlv_len-sizeof(struct eigrp_tlv_header);
    296 
    297         /* did we capture enough for fully decoding the object ? */
    298         TCHECK2(*tptr, eigrp_tlv_len);
    299 
    300         switch(eigrp_tlv_type) {
    301 
    302         case EIGRP_TLV_GENERAL_PARM:
    303             tlv_ptr.eigrp_tlv_general_parm = (const struct eigrp_tlv_general_parm_t *)tlv_tptr;
    304 
    305             printf("\n\t    holdtime: %us, k1 %u, k2 %u, k3 %u, k4 %u, k5 %u",
    306                    EXTRACT_16BITS(tlv_ptr.eigrp_tlv_general_parm->holdtime),
    307                    tlv_ptr.eigrp_tlv_general_parm->k1,
    308                    tlv_ptr.eigrp_tlv_general_parm->k2,
    309                    tlv_ptr.eigrp_tlv_general_parm->k3,
    310                    tlv_ptr.eigrp_tlv_general_parm->k4,
    311                    tlv_ptr.eigrp_tlv_general_parm->k5);
    312             break;
    313 
    314         case EIGRP_TLV_SW_VERSION:
    315             tlv_ptr.eigrp_tlv_sw_version = (const struct eigrp_tlv_sw_version_t *)tlv_tptr;
    316 
    317             printf("\n\t    IOS version: %u.%u, EIGRP version %u.%u",
    318                    tlv_ptr.eigrp_tlv_sw_version->ios_major,
    319                    tlv_ptr.eigrp_tlv_sw_version->ios_minor,
    320                    tlv_ptr.eigrp_tlv_sw_version->eigrp_major,
    321                    tlv_ptr.eigrp_tlv_sw_version->eigrp_minor);
    322             break;
    323 
    324         case EIGRP_TLV_IP_INT:
    325             tlv_ptr.eigrp_tlv_ip_int = (const struct eigrp_tlv_ip_int_t *)tlv_tptr;
    326 
    327             bit_length = tlv_ptr.eigrp_tlv_ip_int->plen;
    328             if (bit_length > 32) {
    329                 printf("\n\t    illegal prefix length %u",bit_length);
    330                 break;
    331             }
    332             byte_length = (bit_length + 7) / 8; /* variable length encoding */
    333             memset(prefix, 0, 4);
    334             memcpy(prefix,&tlv_ptr.eigrp_tlv_ip_int->destination,byte_length);
    335 
    336             printf("\n\t    IPv4 prefix: %15s/%u, nexthop: ",
    337                    ipaddr_string(prefix),
    338                    bit_length);
    339             if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_int->nexthop) == 0)
    340                 printf("self");
    341             else
    342                 printf("%s",ipaddr_string(&tlv_ptr.eigrp_tlv_ip_int->nexthop));
    343 
    344             printf("\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
    345                    (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_int->delay)/100),
    346                    EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_int->bandwidth),
    347                    EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_ip_int->mtu),
    348                    tlv_ptr.eigrp_tlv_ip_int->hopcount,
    349                    tlv_ptr.eigrp_tlv_ip_int->reliability,
    350                    tlv_ptr.eigrp_tlv_ip_int->load);
    351             break;
    352 
    353         case EIGRP_TLV_IP_EXT:
    354             tlv_ptr.eigrp_tlv_ip_ext = (const struct eigrp_tlv_ip_ext_t *)tlv_tptr;
    355 
    356             bit_length = tlv_ptr.eigrp_tlv_ip_ext->plen;
    357             if (bit_length > 32) {
    358                 printf("\n\t    illegal prefix length %u",bit_length);
    359                 break;
    360             }
    361             byte_length = (bit_length + 7) / 8; /* variable length encoding */
    362             memset(prefix, 0, 4);
    363             memcpy(prefix,&tlv_ptr.eigrp_tlv_ip_ext->destination,byte_length);
    364 
    365             printf("\n\t    IPv4 prefix: %15s/%u, nexthop: ",
    366                    ipaddr_string(prefix),
    367                    bit_length);
    368             if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_ext->nexthop) == 0)
    369                 printf("self");
    370             else
    371                 printf("%s",ipaddr_string(&tlv_ptr.eigrp_tlv_ip_ext->nexthop));
    372 
    373             printf("\n\t      origin-router %s, origin-as %u, origin-proto %s, flags [0x%02x], tag 0x%08x, metric %u",
    374                    ipaddr_string(tlv_ptr.eigrp_tlv_ip_ext->origin_router),
    375                    EXTRACT_32BITS(tlv_ptr.eigrp_tlv_ip_ext->origin_as),
    376                    tok2str(eigrp_ext_proto_id_values,"unknown",tlv_ptr.eigrp_tlv_ip_ext->proto_id),
    377                    tlv_ptr.eigrp_tlv_ip_ext->flags,
    378                    EXTRACT_32BITS(tlv_ptr.eigrp_tlv_ip_ext->tag),
    379                    EXTRACT_32BITS(tlv_ptr.eigrp_tlv_ip_ext->metric));
    380 
    381             printf("\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
    382                    (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_ext->delay)/100),
    383                    EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_ext->bandwidth),
    384                    EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_ip_ext->mtu),
    385                    tlv_ptr.eigrp_tlv_ip_ext->hopcount,
    386                    tlv_ptr.eigrp_tlv_ip_ext->reliability,
    387                    tlv_ptr.eigrp_tlv_ip_ext->load);
    388             break;
    389 
    390         case EIGRP_TLV_AT_CABLE_SETUP:
    391             tlv_ptr.eigrp_tlv_at_cable_setup = (const struct eigrp_tlv_at_cable_setup_t *)tlv_tptr;
    392 
    393             printf("\n\t    Cable-range: %u-%u, Router-ID %u",
    394                    EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_cable_setup->cable_start),
    395                    EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_cable_setup->cable_end),
    396                    EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_cable_setup->router_id));
    397             break;
    398 
    399         case EIGRP_TLV_AT_INT:
    400             tlv_ptr.eigrp_tlv_at_int = (const struct eigrp_tlv_at_int_t *)tlv_tptr;
    401 
    402             printf("\n\t     Cable-Range: %u-%u, nexthop: ",
    403                    EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->cable_start),
    404                    EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->cable_end));
    405 
    406             if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_int->nexthop) == 0)
    407                 printf("self");
    408             else
    409                 printf("%u.%u",
    410                        EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->nexthop),
    411                        EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->nexthop[2]));
    412 
    413             printf("\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
    414                    (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_int->delay)/100),
    415                    EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_int->bandwidth),
    416                    EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_at_int->mtu),
    417                    tlv_ptr.eigrp_tlv_at_int->hopcount,
    418                    tlv_ptr.eigrp_tlv_at_int->reliability,
    419                    tlv_ptr.eigrp_tlv_at_int->load);
    420             break;
    421 
    422         case EIGRP_TLV_AT_EXT:
    423             tlv_ptr.eigrp_tlv_at_ext = (const struct eigrp_tlv_at_ext_t *)tlv_tptr;
    424 
    425             printf("\n\t     Cable-Range: %u-%u, nexthop: ",
    426                    EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->cable_start),
    427                    EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->cable_end));
    428 
    429             if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_ext->nexthop) == 0)
    430                 printf("self");
    431             else
    432                 printf("%u.%u",
    433                        EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->nexthop),
    434                        EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->nexthop[2]));
    435 
    436             printf("\n\t      origin-router %u, origin-as %u, origin-proto %s, flags [0x%02x], tag 0x%08x, metric %u",
    437                    EXTRACT_32BITS(tlv_ptr.eigrp_tlv_at_ext->origin_router),
    438                    EXTRACT_32BITS(tlv_ptr.eigrp_tlv_at_ext->origin_as),
    439                    tok2str(eigrp_ext_proto_id_values,"unknown",tlv_ptr.eigrp_tlv_at_ext->proto_id),
    440                    tlv_ptr.eigrp_tlv_at_ext->flags,
    441                    EXTRACT_32BITS(tlv_ptr.eigrp_tlv_at_ext->tag),
    442                    EXTRACT_16BITS(tlv_ptr.eigrp_tlv_at_ext->metric));
    443 
    444             printf("\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
    445                    (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_ext->delay)/100),
    446                    EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_ext->bandwidth),
    447                    EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_at_ext->mtu),
    448                    tlv_ptr.eigrp_tlv_at_ext->hopcount,
    449                    tlv_ptr.eigrp_tlv_at_ext->reliability,
    450                    tlv_ptr.eigrp_tlv_at_ext->load);
    451             break;
    452 
    453             /*
    454              * FIXME those are the defined TLVs that lack a decoder
    455              * you are welcome to contribute code ;-)
    456              */
    457 
    458         case EIGRP_TLV_AUTH:
    459         case EIGRP_TLV_SEQ:
    460         case EIGRP_TLV_MCAST_SEQ:
    461         case EIGRP_TLV_IPX_INT:
    462         case EIGRP_TLV_IPX_EXT:
    463 
    464         default:
    465             if (vflag <= 1)
    466                 print_unknown_data(tlv_tptr,"\n\t    ",tlv_tlen);
    467             break;
    468         }
    469         /* do we want to see an additionally hexdump ? */
    470         if (vflag > 1)
    471             print_unknown_data(tptr+sizeof(sizeof(struct eigrp_tlv_header)),"\n\t    ",
    472                                eigrp_tlv_len-sizeof(struct eigrp_tlv_header));
    473 
    474         tptr+=eigrp_tlv_len;
    475         tlen-=eigrp_tlv_len;
    476     }
    477     return;
    478 trunc:
    479     printf("\n\t\t packet exceeded snapshot");
    480 }
    481