xref: /openbsd/sys/lib/libsa/netudp.c (revision 09467b48)
1 /*	$OpenBSD: netudp.c,v 1.4 2018/03/31 17:09:56 patrick Exp $	*/
2 /*	$NetBSD: net.c,v 1.14 1996/10/13 02:29:02 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1992 Regents of the University of California.
6  * All rights reserved.
7  *
8  * This software was developed by the Computer Systems Engineering group
9  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10  * contributed to Berkeley.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *	This product includes software developed by the University of
23  *	California, Lawrence Berkeley Laboratory and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp  (LBL)
41  */
42 
43 #include <sys/param.h>
44 #include <sys/socket.h>
45 
46 #include <net/if.h>
47 #include <netinet/in.h>
48 
49 #include <netinet/if_ether.h>
50 #include <netinet/ip.h>
51 #include <netinet/ip_var.h>
52 #include <netinet/udp.h>
53 #include <netinet/udp_var.h>
54 
55 #include "stand.h"
56 #include "net.h"
57 
58 /* Caller must leave room for ethernet, ip and udp headers in front!! */
59 ssize_t
60 sendudp(struct iodesc *d, void *pkt, size_t len)
61 {
62 	ssize_t cc;
63 	struct ip *ip;
64 	struct udpiphdr *ui;
65 	struct udphdr *uh;
66 	u_char *ea;
67 	struct ip tip;
68 
69 #ifdef NET_DEBUG
70 	if (debug) {
71 		printf("sendudp: d=%x called.\n", (u_int)d);
72 		if (d) {
73 			printf("saddr: %s:%d",
74 			    inet_ntoa(d->myip), ntohs(d->myport));
75 			printf(" daddr: %s:%d\n",
76 			    inet_ntoa(d->destip), ntohs(d->destport));
77 		}
78 	}
79 #endif
80 
81 	uh = (struct udphdr *)pkt - 1;
82 	ip = (struct ip *)uh - 1;
83 	len += sizeof(*ip) + sizeof(*uh);
84 
85 	bzero(ip, sizeof(*ip) + sizeof(*uh));
86 
87 	ip->ip_v = IPVERSION;			/* half-char */
88 	ip->ip_hl = sizeof(*ip) >> 2;		/* half-char */
89 	ip->ip_len = htons(len);
90 	ip->ip_p = IPPROTO_UDP;			/* char */
91 	ip->ip_ttl = IP_TTL;			/* char */
92 	ip->ip_src = d->myip;
93 	ip->ip_dst = d->destip;
94 	ip->ip_sum = in_cksum(ip, sizeof(*ip));	 /* short, but special */
95 
96 	uh->uh_sport = d->myport;
97 	uh->uh_dport = d->destport;
98 	uh->uh_ulen = htons(len - sizeof(*ip));
99 
100 	/* Calculate checksum (must save and restore ip header) */
101 	tip = *ip;
102 	ui = (struct udpiphdr *)ip;
103 	bzero(ui->ui_x1, sizeof(ui->ui_x1));
104 	ui->ui_len = uh->uh_ulen;
105 	uh->uh_sum = in_cksum(ui, len);
106 	*ip = tip;
107 
108 	if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 ||
109 	    netmask == 0 || SAMENET(ip->ip_src, ip->ip_dst, netmask))
110 		ea = arpwhohas(d, ip->ip_dst);
111 	else
112 		ea = arpwhohas(d, gateip);
113 
114 	cc = sendether(d, ip, len, ea, ETHERTYPE_IP);
115 	if (cc < 0)
116 		return (-1);
117 	if ((size_t)cc != len)
118 		panic("sendudp: bad write (%d != %d)", cc, len);
119 	return (cc - (sizeof(*ip) + sizeof(*uh)));
120 }
121 
122 /*
123  * Receive a UDP packet and validate it is for us.
124  * Caller leaves room for the headers (Ether, IP, UDP)
125  */
126 ssize_t
127 readudp(struct iodesc *d, void *pkt, size_t len, time_t tleft)
128 {
129 	ssize_t n;
130 	size_t hlen;
131 	struct ip *ip;
132 	struct udphdr *uh;
133 	struct udpiphdr *ui;
134 	struct ip tip;
135 	u_int16_t etype;	/* host order */
136 
137 #ifdef NET_DEBUG
138 	if (debug)
139 		printf("readudp: called\n");
140 #endif
141 
142 	uh = (struct udphdr *)pkt - 1;
143 	ip = (struct ip *)uh - 1;
144 
145 	n = readether(d, ip, len + sizeof(*ip) + sizeof(*uh), tleft, &etype);
146 	if (n < 0 || (size_t)n < sizeof(*ip) + sizeof(*uh))
147 		return -1;
148 
149 	/* Ethernet address checks now in readether() */
150 
151 	/* Need to respond to ARP requests. */
152 	if (etype == ETHERTYPE_ARP) {
153 		struct arphdr *ah = (void *)ip;
154 		if (ah->ar_op == htons(ARPOP_REQUEST)) {
155 			/* Send ARP reply */
156 			arp_reply(d, ah);
157 		}
158 		return -1;
159 	}
160 
161 	if (etype != ETHERTYPE_IP) {
162 #ifdef NET_DEBUG
163 		if (debug)
164 			printf("readudp: not IP. ether_type=%x\n", etype);
165 #endif
166 		return -1;
167 	}
168 
169 	/* Check ip header */
170 	if (ip->ip_v != IPVERSION || ip->ip_p != IPPROTO_UDP) {	/* half char */
171 #ifdef NET_DEBUG
172 		if (debug)
173 			printf("readudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p);
174 #endif
175 		return -1;
176 	}
177 
178 	hlen = ip->ip_hl << 2;
179 	if (hlen < sizeof(*ip) || in_cksum(ip, hlen) != 0) {
180 #ifdef NET_DEBUG
181 		if (debug)
182 			printf("readudp: short hdr or bad cksum.\n");
183 #endif
184 		return -1;
185 	}
186 	if (n < ntohs(ip->ip_len)) {
187 #ifdef NET_DEBUG
188 		if (debug)
189 			printf("readudp: bad length %d < %d.\n",
190 			    n, ntohs(ip->ip_len));
191 #endif
192 		return -1;
193 	}
194 	if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) {
195 #ifdef NET_DEBUG
196 		if (debug) {
197 			printf("readudp: bad saddr %s != ", inet_ntoa(d->myip));
198 			printf("%s\n", inet_ntoa(ip->ip_dst));
199 		}
200 #endif
201 		return -1;
202 	}
203 
204 	/* If there were ip options, make them go away */
205 	if (hlen != sizeof(*ip)) {
206 		bcopy(((u_char *)ip) + hlen, uh, len - hlen);
207 		ip->ip_len = htons(sizeof(*ip));
208 		n -= hlen - sizeof(*ip);
209 	}
210 	if (uh->uh_dport != d->myport) {
211 #ifdef NET_DEBUG
212 		if (debug)
213 			printf("readudp: bad dport %d != %d\n",
214 				d->myport, ntohs(uh->uh_dport));
215 #endif
216 		return -1;
217 	}
218 
219 	if (uh->uh_sum) {
220 		n = ntohs(uh->uh_ulen) + sizeof(*ip);
221 		if (n > RECV_SIZE - ETHER_SIZE) {
222 			printf("readudp: huge packet, udp len %ld\n", (long)n);
223 			return -1;
224 		}
225 
226 		/* Check checksum (must save and restore ip header) */
227 		tip = *ip;
228 		ui = (struct udpiphdr *)ip;
229 		bzero(ui->ui_x1, sizeof(ui->ui_x1));
230 		ui->ui_len = uh->uh_ulen;
231 		if (in_cksum(ui, n) != 0) {
232 #ifdef NET_DEBUG
233 			if (debug)
234 				printf("readudp: bad cksum\n");
235 #endif
236 			*ip = tip;
237 			return -1;
238 		}
239 		*ip = tip;
240 	}
241 	if (ntohs(uh->uh_ulen) < sizeof(*uh)) {
242 #ifdef NET_DEBUG
243 		if (debug)
244 			printf("readudp: bad udp len %d < %d\n",
245 			    ntohs(uh->uh_ulen), sizeof(*uh));
246 #endif
247 		return -1;
248 	}
249 
250 	n -= sizeof(*ip) + sizeof(*uh);
251 	return (n);
252 }
253