clean up some stuff; map Internet broadcast address to
[unix-history] / usr / src / sys / netinet / udp_usrreq.c
CommitLineData
5cdc4d65 1/* udp_usrreq.c 4.42 83/01/04 */
1bd53abe
BJ
2
3#include "../h/param.h"
53a5409e
BJ
4#include "../h/dir.h"
5#include "../h/user.h"
1bd53abe 6#include "../h/mbuf.h"
d52566dd 7#include "../h/protosw.h"
53a5409e
BJ
8#include "../h/socket.h"
9#include "../h/socketvar.h"
bf6ab6ff 10#include "../netinet/in.h"
72e4f44e 11#include "../net/if.h"
c124e997 12#include "../net/route.h"
bf6ab6ff
BJ
13#include "../netinet/in_pcb.h"
14#include "../netinet/in_systm.h"
15#include "../netinet/ip.h"
16#include "../netinet/ip_var.h"
17#include "../netinet/ip_icmp.h"
18#include "../netinet/udp.h"
19#include "../netinet/udp_var.h"
8a2f82db 20#include <errno.h>
d52566dd 21
2b4b57cd
BJ
22/*
23 * UDP protocol implementation.
24 * Per RFC 768, August, 1980.
25 */
d52566dd
BJ
26udp_init()
27{
28
eb44bfb2 29 udb.inp_next = udb.inp_prev = &udb;
d52566dd 30}
1bd53abe 31
eb44bfb2 32int udpcksum;
2b4b57cd 33struct sockaddr_in udp_in = { AF_INET };
eb44bfb2 34
2b4b57cd
BJ
35udp_input(m0)
36 struct mbuf *m0;
1bd53abe 37{
eb44bfb2 38 register struct udpiphdr *ui;
53a5409e 39 register struct inpcb *inp;
2b4b57cd 40 register struct mbuf *m;
e199a8a5 41 int len;
eb44bfb2 42
2b4b57cd 43 /*
4aed14e3 44 * Get IP and UDP header together in first mbuf.
2b4b57cd
BJ
45 */
46 m = m0;
89925e89
BJ
47 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&
48 (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
2b4b57cd 49 udpstat.udps_hdrops++;
89925e89 50 return;
2b4b57cd 51 }
4e60622a 52 ui = mtod(m, struct udpiphdr *);
4aed14e3 53 if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))
cca1853f 54 ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
2b4b57cd
BJ
55
56 /*
4aed14e3
BJ
57 * Make mbuf data length reflect UDP length.
58 * If not enough data to reflect UDP length, drop.
2b4b57cd 59 */
e199a8a5 60 len = ntohs((u_short)ui->ui_ulen);
2b4b57cd
BJ
61 if (((struct ip *)ui)->ip_len != len) {
62 if (len > ((struct ip *)ui)->ip_len) {
63 udpstat.udps_badlen++;
64 goto bad;
65 }
66 m_adj(m, ((struct ip *)ui)->ip_len - len);
67 /* (struct ip *)ui->ip_len = len; */
68 }
69
70 /*
4aed14e3 71 * Checksum extended UDP header and data.
2b4b57cd 72 */
eb44bfb2 73 if (udpcksum) {
2b4b57cd
BJ
74 ui->ui_next = ui->ui_prev = 0;
75 ui->ui_x1 = 0;
e199a8a5
BJ
76 ui->ui_len = htons((u_short)len);
77 if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) {
2b4b57cd 78 udpstat.udps_badsum++;
eb44bfb2
BJ
79 printf("udp cksum %x\n", ui->ui_sum);
80 m_freem(m);
81 return;
82 }
83 }
2b4b57cd
BJ
84
85 /*
e199a8a5 86 * Locate pcb for datagram.
2b4b57cd 87 */
2b4b57cd 88 inp = in_pcblookup(&udb,
ebcadd38
BJ
89 ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport,
90 INPLOOKUP_WILDCARD);
72e4f44e 91 if (inp == 0) {
5cdc4d65
SL
92 /* don't send ICMP response for broadcast packet */
93 if (in_lnaof(ui->ui_dst) == INADDR_ANY)
72e4f44e
SL
94 goto bad;
95 icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT);
96 return;
97 }
2b4b57cd
BJ
98
99 /*
100 * Construct sockaddr format source address.
101 * Stuff source address and datagram in user buffer.
102 */
103 udp_in.sin_port = ui->ui_sport;
104 udp_in.sin_addr = ui->ui_src;
4e60622a
BJ
105 m->m_len -= sizeof (struct udpiphdr);
106 m->m_off += sizeof (struct udpiphdr);
107 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0)
2b4b57cd 108 goto bad;
4e60622a 109 sorwakeup(inp->inp_socket);
53a5409e 110 return;
2b4b57cd 111bad:
53a5409e 112 m_freem(m);
1bd53abe
BJ
113}
114
72e4f44e
SL
115udp_abort(inp)
116 struct inpcb *inp;
117{
118 struct socket *so = inp->inp_socket;
119
120 in_pcbdisconnect(inp);
121 soisdisconnected(so);
1bd53abe
BJ
122}
123
39674d5f
SL
124udp_ctlinput(cmd, arg)
125 int cmd;
126 caddr_t arg;
127{
128 struct in_addr *sin;
129 extern u_char inetctlerrmap[];
39674d5f
SL
130
131 if (cmd < 0 || cmd > PRC_NCMDS)
132 return;
133 switch (cmd) {
134
135 case PRC_ROUTEDEAD:
136 break;
137
138 case PRC_QUENCH:
139 break;
140
141 /* these are handled by ip */
142 case PRC_IFDOWN:
143 case PRC_HOSTDEAD:
144 case PRC_HOSTUNREACH:
145 break;
146
147 default:
148 sin = &((struct icmp *)arg)->icmp_ip.ip_dst;
a1edc12b 149 in_pcbnotify(&udb, sin, (int)inetctlerrmap[cmd], udp_abort);
39674d5f
SL
150 }
151}
152
4ad99bae 153udp_output(inp, m0)
2b4b57cd 154 struct inpcb *inp;
2b4b57cd 155 struct mbuf *m0;
1bd53abe 156{
2b4b57cd
BJ
157 register struct mbuf *m;
158 register struct udpiphdr *ui;
a13c006d 159 register struct socket *so;
2b4b57cd
BJ
160 register int len = 0;
161
162 /*
163 * Calculate data length and get a mbuf
4aed14e3 164 * for UDP and IP headers.
2b4b57cd
BJ
165 */
166 for (m = m0; m; m = m->m_next)
167 len += m->m_len;
cce93e4b 168 m = m_get(M_DONTWAIT, MT_HEADER);
8a2f82db
SL
169 if (m == 0) {
170 m_freem(m0);
171 return (ENOBUFS);
172 }
2b4b57cd
BJ
173
174 /*
4aed14e3 175 * Fill in mbuf with extended UDP header
2b4b57cd
BJ
176 * and addresses and length put into network format.
177 */
178 m->m_off = MMAXOFF - sizeof (struct udpiphdr);
179 m->m_len = sizeof (struct udpiphdr);
180 m->m_next = m0;
181 ui = mtod(m, struct udpiphdr *);
182 ui->ui_next = ui->ui_prev = 0;
183 ui->ui_x1 = 0;
184 ui->ui_pr = IPPROTO_UDP;
e199a8a5 185 ui->ui_len = len + sizeof (struct udphdr);
4e60622a
BJ
186 ui->ui_src = inp->inp_laddr;
187 ui->ui_dst = inp->inp_faddr;
188 ui->ui_sport = inp->inp_lport;
189 ui->ui_dport = inp->inp_fport;
e199a8a5 190 ui->ui_ulen = htons((u_short)ui->ui_len);
2b4b57cd
BJ
191
192 /*
193 * Stuff checksum and output datagram.
194 */
195 ui->ui_sum = 0;
ce605ce8 196 ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
4e60622a
BJ
197 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
198 ((struct ip *)ui)->ip_ttl = MAXTTL;
a13c006d
BJ
199 so = inp->inp_socket;
200 return (ip_output(m, (struct mbuf *)0,
201 (so->so_options & SO_DONTROUTE) ? &routetoif : (struct route *)0,
202 so->so_state & SS_PRIV));
1bd53abe
BJ
203}
204
a8d3bf7f 205/*ARGSUSED*/
8075bb0e 206udp_usrreq(so, req, m, nam, opt)
53a5409e 207 struct socket *so;
1bd53abe 208 int req;
8075bb0e
BJ
209 struct mbuf *m, *nam;
210 struct socketopt *opt;
1bd53abe 211{
53a5409e 212 struct inpcb *inp = sotoinpcb(so);
8a2f82db 213 int error = 0;
1bd53abe 214
bbb5f5dd 215 if (inp == 0 && req != PRU_ATTACH)
4e60622a 216 return (EINVAL);
1bd53abe
BJ
217 switch (req) {
218
219 case PRU_ATTACH:
53a5409e
BJ
220 if (inp != 0)
221 return (EINVAL);
8075bb0e
BJ
222 error = in_pcballoc(so, &udb);
223 if (error)
224 break;
59965020 225 error = soreserve(so, 2048, 2048);
8075bb0e
BJ
226 if (error)
227 break;
53a5409e 228 break;
1bd53abe
BJ
229
230 case PRU_DETACH:
53a5409e
BJ
231 if (inp == 0)
232 return (ENOTCONN);
405c9168 233 in_pcbdetach(inp);
53a5409e 234 break;
1bd53abe 235
8075bb0e
BJ
236 case PRU_BIND:
237 error = in_pcbbind(inp, nam);
238 break;
239
240 case PRU_LISTEN:
241 error = EOPNOTSUPP;
242 break;
243
1bd53abe 244 case PRU_CONNECT:
5cdc4d65 245 if (inp->inp_faddr.s_addr != INADDR_ANY)
53a5409e 246 return (EISCONN);
8075bb0e 247 error = in_pcbconnect(inp, nam);
8a2f82db
SL
248 if (error == 0)
249 soisconnected(so);
1bd53abe
BJ
250 break;
251
2b4b57cd
BJ
252 case PRU_ACCEPT:
253 return (EOPNOTSUPP);
254
53a5409e 255 case PRU_DISCONNECT:
5cdc4d65 256 if (inp->inp_faddr.s_addr == INADDR_ANY)
53a5409e 257 return (ENOTCONN);
405c9168 258 in_pcbdisconnect(inp);
53a5409e 259 soisdisconnected(so);
1bd53abe
BJ
260 break;
261
cdad2eb1
BJ
262 case PRU_SHUTDOWN:
263 socantsendmore(so);
264 break;
265
1aa87517
BJ
266 case PRU_SEND: {
267 struct in_addr laddr;
268
8075bb0e 269 if (nam) {
1aa87517 270 laddr = inp->inp_laddr;
5cdc4d65 271 if (inp->inp_faddr.s_addr != INADDR_ANY)
53a5409e 272 return (EISCONN);
8075bb0e 273 error = in_pcbconnect(inp, nam);
02bcdb4e 274 if (error)
8a2f82db 275 break;
4ad99bae 276 } else {
5cdc4d65 277 if (inp->inp_faddr.s_addr == INADDR_ANY)
4ad99bae
BJ
278 return (ENOTCONN);
279 }
8a2f82db 280 error = udp_output(inp, m);
8075bb0e 281 if (nam) {
405c9168 282 in_pcbdisconnect(inp);
1aa87517
BJ
283 inp->inp_laddr = laddr;
284 }
285 }
1bd53abe
BJ
286 break;
287
288 case PRU_ABORT:
405c9168 289 in_pcbdetach(inp);
53a5409e
BJ
290 sofree(so);
291 soisdisconnected(so);
1bd53abe
BJ
292 break;
293
294 case PRU_CONTROL:
53a5409e 295 return (EOPNOTSUPP);
1bd53abe 296
126472ab 297 case PRU_SOCKADDR:
8075bb0e 298 in_setsockaddr(inp, nam);
126472ab
SL
299 break;
300
1bd53abe
BJ
301 default:
302 panic("udp_usrreq");
d52566dd 303 }
8a2f82db 304 return (error);
d52566dd 305}