17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bdstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bdstevel@tonic-gate * with the License.
87c478bdstevel@tonic-gate *
97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bdstevel@tonic-gate * See the License for the specific language governing permissions
127c478bdstevel@tonic-gate * and limitations under the License.
137c478bdstevel@tonic-gate *
147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bdstevel@tonic-gate *
207c478bdstevel@tonic-gate * CDDL HEADER END
217c478bdstevel@tonic-gate */
227c478bdstevel@tonic-gate/*
237c478bdstevel@tonic-gate * Copyright (c) 1996-2001 by Sun Microsystems, Inc.
247c478bdstevel@tonic-gate * All rights reserved.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bdstevel@tonic-gate
297c478bdstevel@tonic-gate#include <sys/types.h>
307c478bdstevel@tonic-gate#include <strings.h>
317c478bdstevel@tonic-gate#include <netinet/in.h>
327c478bdstevel@tonic-gate#include "v4_sum_impl.h"
337c478bdstevel@tonic-gate
347c478bdstevel@tonic-gate/*
357c478bdstevel@tonic-gate * RFC 768 pseudo header. Used in calculating UDP checksums.
367c478bdstevel@tonic-gate */
377c478bdstevel@tonic-gatestruct pseudo_udp {
387c478bdstevel@tonic-gate	struct in_addr	src;
397c478bdstevel@tonic-gate	struct in_addr	dst;
407c478bdstevel@tonic-gate	uint8_t		notused;	/* always zero */
417c478bdstevel@tonic-gate	uint8_t		proto;		/* protocol used */
427c478bdstevel@tonic-gate	uint16_t	len;		/* UDP len */
437c478bdstevel@tonic-gate};
447c478bdstevel@tonic-gate
457c478bdstevel@tonic-gate/*
467c478bdstevel@tonic-gate * One's complement checksum of pseudo header, udp header, and data.
477c478bdstevel@tonic-gate * Must be MT SAFE.
487c478bdstevel@tonic-gate */
497c478bdstevel@tonic-gateuint16_t
507c478bdstevel@tonic-gateudp_chksum(struct udphdr *udph, const struct in_addr *src,
517c478bdstevel@tonic-gate    const struct in_addr *dst, uint8_t proto)
527c478bdstevel@tonic-gate{
537c478bdstevel@tonic-gate	struct pseudo_udp	ck;
547c478bdstevel@tonic-gate	uint16_t		*end_pseudo_hdr = (uint16_t *)(&ck + 1);
557c478bdstevel@tonic-gate	uint16_t		*sp = (uint16_t *)&ck;
567c478bdstevel@tonic-gate	uint_t			sum = 0;
577c478bdstevel@tonic-gate	uint16_t		cnt;
587c478bdstevel@tonic-gate
597c478bdstevel@tonic-gate	/*
607c478bdstevel@tonic-gate	 * Start on the pseudo header. Note that pseudo_udp already takes
617c478bdstevel@tonic-gate	 * acount for the udphdr...
627c478bdstevel@tonic-gate	 */
637c478bdstevel@tonic-gate
647c478bdstevel@tonic-gate	bzero(&ck, sizeof (ck));
657c478bdstevel@tonic-gate
667c478bdstevel@tonic-gate	/* struct copies */
677c478bdstevel@tonic-gate	ck.src	 = *src;
687c478bdstevel@tonic-gate	ck.dst	 = *dst;
697c478bdstevel@tonic-gate	ck.len	 = udph->uh_ulen;
707c478bdstevel@tonic-gate	ck.proto = proto;
717c478bdstevel@tonic-gate
727c478bdstevel@tonic-gate	/*
737c478bdstevel@tonic-gate	 * If the packet is an odd length, zero the pad byte for checksum
747c478bdstevel@tonic-gate	 * purposes [doesn't hurt data]
757c478bdstevel@tonic-gate	 */
767c478bdstevel@tonic-gate
777c478bdstevel@tonic-gate	cnt = ntohs(ck.len) + sizeof (ck);
787c478bdstevel@tonic-gate	if (cnt & 1) {
797c478bdstevel@tonic-gate		((caddr_t)udph)[ntohs(udph->uh_ulen)] = '\0';
807c478bdstevel@tonic-gate		cnt++;	/* make even */
817c478bdstevel@tonic-gate	}
827c478bdstevel@tonic-gate
837c478bdstevel@tonic-gate	for (cnt >>= 1; cnt != 0; cnt--) {
847c478bdstevel@tonic-gate
857c478bdstevel@tonic-gate		sum += *sp++;
867c478bdstevel@tonic-gate		if (sum >= BIT_WRAP) {
877c478bdstevel@tonic-gate			/* Wrap carries into low bit */
887c478bdstevel@tonic-gate			sum -= BIT_WRAP;
897c478bdstevel@tonic-gate			sum++;
907c478bdstevel@tonic-gate		}
917c478bdstevel@tonic-gate
927c478bdstevel@tonic-gate		/*
937c478bdstevel@tonic-gate		 * If we've finished checking the pseudo-header, move
947c478bdstevel@tonic-gate		 * onto the udp header and data.
957c478bdstevel@tonic-gate		 */
967c478bdstevel@tonic-gate
977c478bdstevel@tonic-gate		if (sp == end_pseudo_hdr)
987c478bdstevel@tonic-gate			sp = (uint16_t *)udph;
997c478bdstevel@tonic-gate	}
1007c478bdstevel@tonic-gate
1017c478bdstevel@tonic-gate	return (~sum == 0 ? ~0 : ~sum);
1027c478bdstevel@tonic-gate}
103