bug fix, 4.3BSD/usr.bin/41
[unix-history] / usr / src / sys / netinet / udp_usrreq.c
CommitLineData
8ae0e4b4 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
8ae0e4b4
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
0880b18e 6 * @(#)udp_usrreq.c 7.1 (Berkeley) %G%
8ae0e4b4 7 */
20666ad3
JB
8
9#include "param.h"
10#include "dir.h"
11#include "user.h"
12#include "mbuf.h"
13#include "protosw.h"
14#include "socket.h"
15#include "socketvar.h"
16#include "errno.h"
17#include "stat.h"
f4d55810 18
72e4f44e 19#include "../net/if.h"
c124e997 20#include "../net/route.h"
f4d55810 21
20666ad3
JB
22#include "in.h"
23#include "in_pcb.h"
24#include "in_systm.h"
25#include "ip.h"
26#include "ip_var.h"
27#include "ip_icmp.h"
28#include "udp.h"
29#include "udp_var.h"
d52566dd 30
2b4b57cd
BJ
31/*
32 * UDP protocol implementation.
33 * Per RFC 768, August, 1980.
34 */
d52566dd
BJ
35udp_init()
36{
37
eb44bfb2 38 udb.inp_next = udb.inp_prev = &udb;
d52566dd 39}
1bd53abe 40
c50542f3 41#ifndef COMPAT_42
dd8707ae 42int udpcksum = 1;
c50542f3
MK
43#else
44int udpcksum = 0; /* XXX */
45#endif
46
2b4b57cd 47struct sockaddr_in udp_in = { AF_INET };
eb44bfb2 48
c45e83d2 49udp_input(m0, ifp)
2b4b57cd 50 struct mbuf *m0;
c45e83d2 51 struct ifnet *ifp;
1bd53abe 52{
eb44bfb2 53 register struct udpiphdr *ui;
53a5409e 54 register struct inpcb *inp;
2b4b57cd 55 register struct mbuf *m;
e199a8a5 56 int len;
dcea2497 57 struct ip ip;
eb44bfb2 58
2b4b57cd 59 /*
4aed14e3 60 * Get IP and UDP header together in first mbuf.
2b4b57cd
BJ
61 */
62 m = m0;
89925e89
BJ
63 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&
64 (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
2b4b57cd 65 udpstat.udps_hdrops++;
89925e89 66 return;
2b4b57cd 67 }
4e60622a 68 ui = mtod(m, struct udpiphdr *);
4aed14e3 69 if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))
cca1853f 70 ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
2b4b57cd
BJ
71
72 /*
4aed14e3
BJ
73 * Make mbuf data length reflect UDP length.
74 * If not enough data to reflect UDP length, drop.
2b4b57cd 75 */
e199a8a5 76 len = ntohs((u_short)ui->ui_ulen);
2b4b57cd
BJ
77 if (((struct ip *)ui)->ip_len != len) {
78 if (len > ((struct ip *)ui)->ip_len) {
79 udpstat.udps_badlen++;
80 goto bad;
81 }
4828da7c 82 m_adj(m, len - ((struct ip *)ui)->ip_len);
dcea2497 83 /* ((struct ip *)ui)->ip_len = len; */
2b4b57cd 84 }
dcea2497
MK
85 /*
86 * Save a copy of the IP header in case we want restore it for ICMP.
87 */
88 ip = *(struct ip*)ui;
2b4b57cd
BJ
89
90 /*
4aed14e3 91 * Checksum extended UDP header and data.
2b4b57cd 92 */
4828da7c 93 if (udpcksum && ui->ui_sum) {
2b4b57cd
BJ
94 ui->ui_next = ui->ui_prev = 0;
95 ui->ui_x1 = 0;
ee09448f 96 ui->ui_len = ui->ui_ulen;
e199a8a5 97 if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) {
2b4b57cd 98 udpstat.udps_badsum++;
eb44bfb2
BJ
99 m_freem(m);
100 return;
101 }
102 }
2b4b57cd
BJ
103
104 /*
e199a8a5 105 * Locate pcb for datagram.
2b4b57cd 106 */
2b4b57cd 107 inp = in_pcblookup(&udb,
ebcadd38
BJ
108 ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport,
109 INPLOOKUP_WILDCARD);
72e4f44e 110 if (inp == 0) {
5cdc4d65 111 /* don't send ICMP response for broadcast packet */
ee09448f 112 if (in_broadcast(ui->ui_dst))
72e4f44e 113 goto bad;
dcea2497 114 *(struct ip *)ui = ip;
c45e83d2
MK
115 icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT,
116 ifp);
72e4f44e
SL
117 return;
118 }
2b4b57cd
BJ
119
120 /*
121 * Construct sockaddr format source address.
122 * Stuff source address and datagram in user buffer.
123 */
124 udp_in.sin_port = ui->ui_sport;
125 udp_in.sin_addr = ui->ui_src;
4e60622a
BJ
126 m->m_len -= sizeof (struct udpiphdr);
127 m->m_off += sizeof (struct udpiphdr);
ab85b059
SL
128 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
129 m, (struct mbuf *)0) == 0)
2b4b57cd 130 goto bad;
4e60622a 131 sorwakeup(inp->inp_socket);
53a5409e 132 return;
2b4b57cd 133bad:
53a5409e 134 m_freem(m);
1bd53abe
BJ
135}
136
41715710
MK
137/*
138 * Notify a udp user of an asynchronous error;
139 * just wake up so that he can collect error status.
140 */
141udp_notify(inp)
142 register struct inpcb *inp;
143{
144
145 sorwakeup(inp->inp_socket);
146 sowwakeup(inp->inp_socket);
147}
148
dcea2497 149udp_ctlinput(cmd, sa)
39674d5f 150 int cmd;
dcea2497 151 struct sockaddr *sa;
39674d5f 152{
39674d5f 153 extern u_char inetctlerrmap[];
dcea2497 154 struct sockaddr_in *sin;
336240bf 155 int in_rtchange();
39674d5f 156
dcea2497 157 if ((unsigned)cmd > PRC_NCMDS)
39674d5f 158 return;
dcea2497
MK
159 if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
160 return;
161 sin = (struct sockaddr_in *)sa;
162 if (sin->sin_addr.s_addr == INADDR_ANY)
163 return;
164
39674d5f
SL
165 switch (cmd) {
166
dcea2497 167 case PRC_QUENCH:
39674d5f
SL
168 break;
169
dcea2497 170 case PRC_ROUTEDEAD:
336240bf
MK
171 case PRC_REDIRECT_NET:
172 case PRC_REDIRECT_HOST:
dcea2497
MK
173 case PRC_REDIRECT_TOSNET:
174 case PRC_REDIRECT_TOSHOST:
175 in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange);
39674d5f
SL
176 break;
177
39674d5f 178 default:
336240bf
MK
179 if (inetctlerrmap[cmd] == 0)
180 return; /* XXX */
dcea2497 181 in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd],
41715710 182 udp_notify);
39674d5f
SL
183 }
184}
185
4ad99bae 186udp_output(inp, m0)
d55475b1 187 register struct inpcb *inp;
2b4b57cd 188 struct mbuf *m0;
1bd53abe 189{
2b4b57cd
BJ
190 register struct mbuf *m;
191 register struct udpiphdr *ui;
f553b1f7 192 register int len = 0;
2b4b57cd
BJ
193
194 /*
195 * Calculate data length and get a mbuf
4aed14e3 196 * for UDP and IP headers.
2b4b57cd
BJ
197 */
198 for (m = m0; m; m = m->m_next)
199 len += m->m_len;
ee09448f 200 MGET(m, M_DONTWAIT, MT_HEADER);
8a2f82db
SL
201 if (m == 0) {
202 m_freem(m0);
203 return (ENOBUFS);
204 }
2b4b57cd
BJ
205
206 /*
4aed14e3 207 * Fill in mbuf with extended UDP header
2b4b57cd
BJ
208 * and addresses and length put into network format.
209 */
210 m->m_off = MMAXOFF - sizeof (struct udpiphdr);
211 m->m_len = sizeof (struct udpiphdr);
212 m->m_next = m0;
213 ui = mtod(m, struct udpiphdr *);
214 ui->ui_next = ui->ui_prev = 0;
215 ui->ui_x1 = 0;
216 ui->ui_pr = IPPROTO_UDP;
ee847abd 217 ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
4e60622a
BJ
218 ui->ui_src = inp->inp_laddr;
219 ui->ui_dst = inp->inp_faddr;
220 ui->ui_sport = inp->inp_lport;
221 ui->ui_dport = inp->inp_fport;
ee847abd 222 ui->ui_ulen = ui->ui_len;
2b4b57cd
BJ
223
224 /*
225 * Stuff checksum and output datagram.
226 */
227 ui->ui_sum = 0;
dd8707ae
MK
228 if (udpcksum) {
229 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
4828da7c 230 ui->ui_sum = -1;
ee09448f 231 }
4e60622a 232 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
1820d4e3 233 ((struct ip *)ui)->ip_ttl = UDP_TTL;
d55475b1
MK
234 return (ip_output(m, inp->inp_options, &inp->inp_route,
235 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)));
1bd53abe
BJ
236}
237
1d14d351
MK
238int udp_sendspace = 2048; /* really max datagram size */
239int udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */
240
a8d3bf7f 241/*ARGSUSED*/
ab85b059 242udp_usrreq(so, req, m, nam, rights)
53a5409e 243 struct socket *so;
1bd53abe 244 int req;
ab85b059 245 struct mbuf *m, *nam, *rights;
1bd53abe 246{
53a5409e 247 struct inpcb *inp = sotoinpcb(so);
8a2f82db 248 int error = 0;
1bd53abe 249
1d14d351
MK
250 if (req == PRU_CONTROL)
251 return (in_control(so, (int)m, (caddr_t)nam,
252 (struct ifnet *)rights));
ab85b059
SL
253 if (rights && rights->m_len) {
254 error = EINVAL;
255 goto release;
256 }
a3fa431a
SL
257 if (inp == NULL && req != PRU_ATTACH) {
258 error = EINVAL;
259 goto release;
260 }
1bd53abe
BJ
261 switch (req) {
262
263 case PRU_ATTACH:
a3fa431a
SL
264 if (inp != NULL) {
265 error = EINVAL;
266 break;
267 }
8075bb0e
BJ
268 error = in_pcballoc(so, &udb);
269 if (error)
270 break;
1d14d351 271 error = soreserve(so, udp_sendspace, udp_recvspace);
8075bb0e
BJ
272 if (error)
273 break;
53a5409e 274 break;
1bd53abe
BJ
275
276 case PRU_DETACH:
405c9168 277 in_pcbdetach(inp);
53a5409e 278 break;
1bd53abe 279
8075bb0e
BJ
280 case PRU_BIND:
281 error = in_pcbbind(inp, nam);
282 break;
283
284 case PRU_LISTEN:
285 error = EOPNOTSUPP;
286 break;
287
1bd53abe 288 case PRU_CONNECT:
a3fa431a
SL
289 if (inp->inp_faddr.s_addr != INADDR_ANY) {
290 error = EISCONN;
291 break;
292 }
8075bb0e 293 error = in_pcbconnect(inp, nam);
8a2f82db
SL
294 if (error == 0)
295 soisconnected(so);
1bd53abe
BJ
296 break;
297
4945768c
SL
298 case PRU_CONNECT2:
299 error = EOPNOTSUPP;
300 break;
301
2b4b57cd 302 case PRU_ACCEPT:
a3fa431a
SL
303 error = EOPNOTSUPP;
304 break;
2b4b57cd 305
53a5409e 306 case PRU_DISCONNECT:
a3fa431a
SL
307 if (inp->inp_faddr.s_addr == INADDR_ANY) {
308 error = ENOTCONN;
309 break;
310 }
405c9168 311 in_pcbdisconnect(inp);
f96a0781 312 so->so_state &= ~SS_ISCONNECTED; /* XXX */
1bd53abe
BJ
313 break;
314
cdad2eb1
BJ
315 case PRU_SHUTDOWN:
316 socantsendmore(so);
317 break;
318
1aa87517
BJ
319 case PRU_SEND: {
320 struct in_addr laddr;
5f55b8b5 321 int s;
1aa87517 322
8075bb0e 323 if (nam) {
1aa87517 324 laddr = inp->inp_laddr;
a3fa431a
SL
325 if (inp->inp_faddr.s_addr != INADDR_ANY) {
326 error = EISCONN;
327 break;
328 }
5f55b8b5
MK
329 /*
330 * Must block input while temporarily connected.
331 */
332 s = splnet();
8075bb0e 333 error = in_pcbconnect(inp, nam);
5f55b8b5
MK
334 if (error) {
335 splx(s);
8a2f82db 336 break;
5f55b8b5 337 }
4ad99bae 338 } else {
a3fa431a
SL
339 if (inp->inp_faddr.s_addr == INADDR_ANY) {
340 error = ENOTCONN;
341 break;
342 }
4ad99bae 343 }
8a2f82db 344 error = udp_output(inp, m);
a3fa431a 345 m = NULL;
8075bb0e 346 if (nam) {
405c9168 347 in_pcbdisconnect(inp);
1aa87517 348 inp->inp_laddr = laddr;
1d14d351 349 splx(s);
1aa87517
BJ
350 }
351 }
1bd53abe
BJ
352 break;
353
354 case PRU_ABORT:
405c9168 355 in_pcbdetach(inp);
53a5409e
BJ
356 sofree(so);
357 soisdisconnected(so);
1bd53abe
BJ
358 break;
359
126472ab 360 case PRU_SOCKADDR:
8075bb0e 361 in_setsockaddr(inp, nam);
126472ab
SL
362 break;
363
a7343092
SL
364 case PRU_PEERADDR:
365 in_setpeeraddr(inp, nam);
366 break;
367
74040e68
MK
368 case PRU_SENSE:
369 /*
370 * stat: don't bother with a blocksize.
371 */
372 return (0);
373
11d2a668
SL
374 case PRU_SENDOOB:
375 case PRU_FASTTIMO:
376 case PRU_SLOWTIMO:
377 case PRU_PROTORCV:
378 case PRU_PROTOSEND:
379 error = EOPNOTSUPP;
380 break;
4945768c 381
5f55b8b5
MK
382 case PRU_RCVD:
383 case PRU_RCVOOB:
384 return (EOPNOTSUPP); /* do not free mbuf's */
385
4945768c
SL
386 default:
387 panic("udp_usrreq");
d52566dd 388 }
a3fa431a
SL
389release:
390 if (m != NULL)
391 m_freem(m);
8a2f82db 392 return (error);
d52566dd 393}