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