Annotation of embedaddon/bird/lib/fletcher16.h, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *     BIRD Library -- Fletcher-16 checksum
                      3:  *
                      4:  *     (c) 2015 Ondrej Zajicek <santiago@crfreenet.org>
                      5:  *     (c) 2015 CZ.NIC z.s.p.o.
                      6:  *
                      7:  *     Can be freely distributed and used under the terms of the GNU GPL.
                      8:  */
                      9: 
                     10: /**
                     11:  * DOC: Fletcher-16 checksum
                     12:  *
                     13:  * Fletcher-16 checksum is a position-dependent checksum algorithm used for
                     14:  * error-detection e.g. in OSPF LSAs.
                     15:  *
                     16:  * To generate Fletcher-16 checksum, zero the checksum field in data, initialize
                     17:  * the context by fletcher16_init(), process the data by fletcher16_update(),
                     18:  * compute the checksum value by fletcher16_final() and store it to the checksum
                     19:  * field in data by put_u16() (or other means involving htons() conversion).
                     20:  *
                     21:  * To verify Fletcher-16 checksum, initialize the context by fletcher16_init(),
                     22:  * process the data by fletcher16_update(), compute a passing checksum by
                     23:  * fletcher16_compute() and check if it is zero.
                     24:  */
                     25: 
                     26: #ifndef _BIRD_FLETCHER16_H_
                     27: #define _BIRD_FLETCHER16_H_
                     28: 
                     29: #include "nest/bird.h"
                     30: 
                     31: 
                     32: struct fletcher16_context
                     33: {
                     34:   int c0, c1;
                     35: };
                     36: 
                     37: 
                     38: /**
                     39:  * fletcher16_init - initialize Fletcher-16 context
                     40:  * @ctx: the context
                     41:  */
                     42: static inline void
                     43: fletcher16_init(struct fletcher16_context *ctx)
                     44: {
                     45:   ctx->c0 = ctx->c1 = 0;
                     46: }
                     47: 
                     48: /**
                     49:  * fletcher16_update - process data to Fletcher-16 context
                     50:  * @ctx: the context
                     51:  * @buf: data buffer
                     52:  * @len: data length
                     53:  *
                     54:  * fletcher16_update() reads data from the buffer @buf and updates passing sums
                     55:  * in the context @ctx. It may be used multiple times for multiple blocks of
                     56:  * checksummed data.
                     57:  */
                     58: static inline void
                     59: fletcher16_update(struct fletcher16_context *ctx, const u8* buf, int len)
                     60: {
                     61:   /*
                     62:    * The Fletcher-16 sum is essentially a sequence of
                     63:    * ctx->c1 += ctx->c0 += *buf++, modulo 255.
                     64:    *
                     65:    * In the inner loop, we eliminate modulo operation and we do some loop
                     66:    * unrolling. MODX is the maximal number of steps that can be done without
                     67:    * modulo before overflow, see RFC 1008 for details. We use a bit smaller
                     68:    * value to cover for initial steps due to loop unrolling.
                     69:    */
                     70: 
                     71: #define MODX 4096
                     72: 
                     73:   int blen, i;
                     74: 
                     75:   blen = len % 4;
                     76:   len -= blen;
                     77: 
                     78:   for (i = 0; i < blen; i++)
                     79:     ctx->c1 += ctx->c0 += *buf++;
                     80: 
                     81:   do {
                     82:     blen = MIN(len, MODX);
                     83:     len -= blen;
                     84: 
                     85:     for (i = 0; i < blen; i += 4)
                     86:     {
                     87:       ctx->c1 += ctx->c0 += *buf++;
                     88:       ctx->c1 += ctx->c0 += *buf++;
                     89:       ctx->c1 += ctx->c0 += *buf++;
                     90:       ctx->c1 += ctx->c0 += *buf++;
                     91:     }
                     92: 
                     93:     ctx->c0 %= 255;
                     94:     ctx->c1 %= 255;
                     95: 
                     96:   } while (len);
                     97: }
                     98: 
                     99: 
                    100: /**
                    101:  * fletcher16_update_n32 - process data to Fletcher-16 context, with endianity adjustment
                    102:  * @ctx: the context
                    103:  * @buf: data buffer
                    104:  * @len: data length
                    105:  *
                    106:  * fletcher16_update_n32() works like fletcher16_update(), except it applies
                    107:  * 32-bit host/network endianity swap to the data before they are processed.
                    108:  * I.e., it assumes that the data is a sequence of u32 that must be converted by
                    109:  * ntohl() or htonl() before processing. The @buf need not to be aligned, but
                    110:  * its length (@len) must be multiple of 4. Note that on big endian systems the
                    111:  * host endianity is the same as the network endianity, therefore there is no
                    112:  * endianity swap.
                    113:  */
                    114: static inline void
                    115: fletcher16_update_n32(struct fletcher16_context *ctx, const u8* buf, int len)
                    116: {
                    117:   /* See fletcher16_update() for details */
                    118: 
                    119:   int blen, i;
                    120: 
                    121:   do {
                    122:     blen = MIN(len, MODX);
                    123:     len -= blen;
                    124: 
                    125:     for (i = 0; i < blen; i += 4)
                    126:     {
                    127: #ifdef CPU_BIG_ENDIAN
                    128:       ctx->c1 += ctx->c0 += *buf++;
                    129:       ctx->c1 += ctx->c0 += *buf++;
                    130:       ctx->c1 += ctx->c0 += *buf++;
                    131:       ctx->c1 += ctx->c0 += *buf++;
                    132: #else
                    133:       ctx->c1 += ctx->c0 += buf[3];
                    134:       ctx->c1 += ctx->c0 += buf[2];
                    135:       ctx->c1 += ctx->c0 += buf[1];
                    136:       ctx->c1 += ctx->c0 += buf[0];
                    137:       buf += 4;
                    138: #endif
                    139:     }
                    140: 
                    141:     ctx->c0 %= 255;
                    142:     ctx->c1 %= 255;
                    143: 
                    144:   } while (len);
                    145: }
                    146: 
                    147: /**
                    148:  * fletcher16_final - compute final Fletcher-16 checksum value
                    149:  * @ctx: the context
                    150:  * @len: total data length
                    151:  * @pos: offset in data where the checksum will be stored
                    152:  *
                    153:  * fletcher16_final() computes the final checksum value and returns it.
                    154:  * The caller is responsible for storing it in the appropriate position.
                    155:  * The checksum value depends on @len and @pos, but only their difference
                    156:  * (i.e. the offset from the end) is significant.
                    157:  *
                    158:  * The checksum value is represented as u16, although it is defined as two
                    159:  * consecutive bytes. We treat them as one u16 in big endian / network order.
                    160:  * I.e., the returned value is in the form that would be returned by get_u16()
                    161:  * from the checksum field in the data buffer, therefore the caller should use
                    162:  * put_u16() or an explicit host-to-network conversion when storing it to the
                    163:  * checksum field in the data buffer.
                    164:  *
                    165:  * Note that the returned checksum value is always nonzero.
                    166:  */
                    167: static inline u16
                    168: fletcher16_final(struct fletcher16_context *ctx, int len, int pos)
                    169: {
                    170:   int x = ((len - pos - 1) * ctx->c0 - ctx->c1) % 255;
                    171:   if (x <= 0)
                    172:     x += 255;
                    173: 
                    174:   int y = 510 - ctx->c0 - x;
                    175:   if (y > 255)
                    176:     y -= 255;
                    177: 
                    178:   return (x << 8) | y;
                    179: }
                    180: 
                    181: 
                    182: /**
                    183:  * fletcher16_compute - compute Fletcher-16 sum for verification
                    184:  * @ctx: the context
                    185:  *
                    186:  * fletcher16_compute() returns a passing Fletcher-16 sum for processed data.
                    187:  * If the data contains the proper Fletcher-16 checksum value, the returned
                    188:  * value is zero.
                    189:  */
                    190: static inline u16
                    191: fletcher16_compute(struct fletcher16_context *ctx)
                    192: {
                    193:   return (ctx->c0 << 8) | ctx->c1;
                    194: }
                    195: 
                    196: #endif

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