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