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