#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/kdebug.h>
#define DBG_FNC_IN_CKSUM NETDBG_CODE(DBG_NETIP, (3 << 8))
union s_util {
char c[2];
u_short s;
};
union l_util {
u_int16_t s[2];
u_int32_t l;
};
union q_util {
u_int16_t s[4];
u_int32_t l[2];
u_int64_t q;
};
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
#define REDUCE32 \
{ \
q_util.q = sum; \
sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
}
#define REDUCE16 \
{ \
q_util.q = sum; \
l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
sum = l_util.s[0] + l_util.s[1]; \
ADDCARRY(sum); \
}
#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
#if defined(ppc)
__inline unsigned short
in_addword(u_short a, u_short b)
{
union l_util l_util;
u_int32_t sum = a + b;
REDUCE;
return (sum);
}
__inline unsigned short
in_pseudo(u_int a, u_int b, u_int c)
{
u_int64_t sum;
union q_util q_util;
union l_util l_util;
sum = (u_int64_t) a + b + c;
REDUCE16;
return (sum);
}
int
in_cksum(m, len)
register struct mbuf *m;
register int len;
{
register u_short *w;
register int sum = 0;
register int mlen = 0;
int starting_on_odd = 0;
KERNEL_DEBUG(DBG_FNC_IN_CKSUM | DBG_FUNC_START, len,0,0,0,0);
for (;m && len; m = m->m_next) {
if (m->m_len == 0)
continue;
mlen = m->m_len;
w = mtod(m, u_short *);
if (len < mlen)
mlen = len;
sum = xsum_assym(w, mlen, sum, starting_on_odd);
len -= mlen;
if (mlen & 0x1)
{
if (starting_on_odd)
starting_on_odd = 0;
else
starting_on_odd = 1;
}
}
KERNEL_DEBUG(DBG_FNC_IN_CKSUM | DBG_FUNC_END, 0,0,0,0,0);
return (~sum & 0xffff);
}
u_short
in_cksum_skip(m, len, skip)
register struct mbuf *m;
register int len;
register int skip;
{
register u_short *w;
register int sum = 0;
register int mlen = 0;
int starting_on_odd = 0;
len -= skip;
for (; skip && m; m = m->m_next) {
if (m->m_len > skip) {
mlen = m->m_len - skip;
w = (u_short *)(m->m_data+skip);
goto skip_start;
} else {
skip -= m->m_len;
}
}
for (;m && len; m = m->m_next) {
if (m->m_len == 0)
continue;
mlen = m->m_len;
w = mtod(m, u_short *);
skip_start:
if (len < mlen)
mlen = len;
sum = xsum_assym(w, mlen, sum, starting_on_odd);
len -= mlen;
if (mlen & 0x1)
{
if (starting_on_odd)
starting_on_odd = 0;
else
starting_on_odd = 1;
}
}
return (~sum & 0xffff);
}
#else
u_short
in_addword(u_short a, u_short b)
{
union l_util l_util;
u_int32_t sum = a + b;
REDUCE(sum);
return (sum);
}
u_short
in_pseudo(u_int a, u_int b, u_int c)
{
u_int64_t sum;
union q_util q_util;
union l_util l_util;
sum = (u_int64_t) a + b + c;
REDUCE16;
return (sum);
}
int
in_cksum(m, len)
register struct mbuf *m;
register int len;
{
register u_short *w;
register int sum = 0;
register int mlen = 0;
int byte_swapped = 0;
union s_util s_util;
union l_util l_util;
KERNEL_DEBUG(DBG_FNC_IN_CKSUM | DBG_FUNC_START, len,0,0,0,0);
for (;m && len; m = m->m_next) {
if (m->m_len == 0)
continue;
w = mtod(m, u_short *);
if (mlen == -1) {
s_util.c[1] = *(char *)w;
sum += s_util.s;
w = (u_short *)((char *)w + 1);
mlen = m->m_len - 1;
len--;
} else
mlen = m->m_len;
if (len < mlen)
mlen = len;
len -= mlen;
if ((1 & (int) w) && (mlen > 0)) {
REDUCE;
sum <<= 8;
s_util.c[0] = *(u_char *)w;
w = (u_short *)((char *)w + 1);
mlen--;
byte_swapped = 1;
}
while ((mlen -= 32) >= 0) {
sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
w += 16;
}
mlen += 32;
while ((mlen -= 8) >= 0) {
sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
w += 4;
}
mlen += 8;
if (mlen == 0 && byte_swapped == 0)
continue;
REDUCE;
while ((mlen -= 2) >= 0) {
sum += *w++;
}
if (byte_swapped) {
REDUCE;
sum <<= 8;
byte_swapped = 0;
if (mlen == -1) {
s_util.c[1] = *(char *)w;
sum += s_util.s;
mlen = 0;
} else
mlen = -1;
} else if (mlen == -1)
s_util.c[0] = *(char *)w;
}
if (len)
printf("cksum: out of data\n");
if (mlen == -1) {
s_util.c[1] = 0;
sum += s_util.s;
}
REDUCE;
KERNEL_DEBUG(DBG_FNC_IN_CKSUM | DBG_FUNC_END, 0,0,0,0,0);
return (~sum & 0xffff);
}
int
in_cksum_skip(m, len, skip)
register struct mbuf *m;
register u_short len;
register u_short skip;
{
register u_short *w;
register int sum = 0;
register int mlen = 0;
int byte_swapped = 0;
union s_util s_util;
union l_util l_util;
KERNEL_DEBUG(DBG_FNC_IN_CKSUM | DBG_FUNC_START, len,0,0,0,0);
len -= skip;
for (; skip && m; m = m->m_next) {
if (m->m_len > skip) {
mlen = m->m_len - skip;
w = (u_short *)(m->m_data+skip);
goto skip_start;
} else {
skip -= m->m_len;
}
}
for (;m && len; m = m->m_next) {
if (m->m_len == 0)
continue;
w = mtod(m, u_short *);
if (mlen == -1) {
s_util.c[1] = *(char *)w;
sum += s_util.s;
w = (u_short *)((char *)w + 1);
mlen = m->m_len - 1;
len--;
} else {
mlen = m->m_len;
}
skip_start:
if (len < mlen)
mlen = len;
len -= mlen;
if ((1 & (int) w) && (mlen > 0)) {
REDUCE;
sum <<= 8;
s_util.c[0] = *(u_char *)w;
w = (u_short *)((char *)w + 1);
mlen--;
byte_swapped = 1;
}
while ((mlen -= 32) >= 0) {
sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
w += 16;
}
mlen += 32;
while ((mlen -= 8) >= 0) {
sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
w += 4;
}
mlen += 8;
if (mlen == 0 && byte_swapped == 0)
continue;
REDUCE;
while ((mlen -= 2) >= 0) {
sum += *w++;
}
if (byte_swapped) {
REDUCE;
sum <<= 8;
byte_swapped = 0;
if (mlen == -1) {
s_util.c[1] = *(char *)w;
sum += s_util.s;
mlen = 0;
} else
mlen = -1;
} else if (mlen == -1)
s_util.c[0] = *(char *)w;
}
if (len)
printf("cksum: out of data\n");
if (mlen == -1) {
s_util.c[1] = 0;
sum += s_util.s;
}
REDUCE;
KERNEL_DEBUG(DBG_FNC_IN_CKSUM | DBG_FUNC_END, 0,0,0,0,0);
return (~sum & 0xffff);
}
#endif