1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright (c) 1996-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/types.h>
30#include <strings.h>
31#include <netinet/in.h>
32#include "v4_sum_impl.h"
33
34/*
35 * RFC 768 pseudo header. Used in calculating UDP checksums.
36 */
37struct pseudo_udp {
38	struct in_addr	src;
39	struct in_addr	dst;
40	uint8_t		notused;	/* always zero */
41	uint8_t		proto;		/* protocol used */
42	uint16_t	len;		/* UDP len */
43};
44
45/*
46 * One's complement checksum of pseudo header, udp header, and data.
47 * Must be MT SAFE.
48 */
49uint16_t
50udp_chksum(struct udphdr *udph, const struct in_addr *src,
51    const struct in_addr *dst, uint8_t proto)
52{
53	struct pseudo_udp	ck;
54	uint16_t		*end_pseudo_hdr = (uint16_t *)(&ck + 1);
55	uint16_t		*sp = (uint16_t *)&ck;
56	uint_t			sum = 0;
57	uint16_t		cnt;
58
59	/*
60	 * Start on the pseudo header. Note that pseudo_udp already takes
61	 * acount for the udphdr...
62	 */
63
64	bzero(&ck, sizeof (ck));
65
66	/* struct copies */
67	ck.src	 = *src;
68	ck.dst	 = *dst;
69	ck.len	 = udph->uh_ulen;
70	ck.proto = proto;
71
72	/*
73	 * If the packet is an odd length, zero the pad byte for checksum
74	 * purposes [doesn't hurt data]
75	 */
76
77	cnt = ntohs(ck.len) + sizeof (ck);
78	if (cnt & 1) {
79		((caddr_t)udph)[ntohs(udph->uh_ulen)] = '\0';
80		cnt++;	/* make even */
81	}
82
83	for (cnt >>= 1; cnt != 0; cnt--) {
84
85		sum += *sp++;
86		if (sum >= BIT_WRAP) {
87			/* Wrap carries into low bit */
88			sum -= BIT_WRAP;
89			sum++;
90		}
91
92		/*
93		 * If we've finished checking the pseudo-header, move
94		 * onto the udp header and data.
95		 */
96
97		if (sp == end_pseudo_hdr)
98			sp = (uint16_t *)udph;
99	}
100
101	return (~sum == 0 ? ~0 : ~sum);
102}
103