typo
[unix-history] / usr / src / sys / netinet / udp_usrreq.c
CommitLineData
599c842e 1/* udp_usrreq.c 4.34 82/10/16 */
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
SL
91 if (inp == 0) {
92 struct in_addr broadcastaddr;
93
94 broadcastaddr = if_makeaddr(ui->ui_dst.s_net, INADDR_ANY);
39674d5f 95 if (ui->ui_dst.s_addr == broadcastaddr.s_addr)
72e4f44e
SL
96 goto bad;
97 icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT);
98 return;
99 }
2b4b57cd
BJ
100
101 /*
102 * Construct sockaddr format source address.
103 * Stuff source address and datagram in user buffer.
104 */
105 udp_in.sin_port = ui->ui_sport;
106 udp_in.sin_addr = ui->ui_src;
4e60622a
BJ
107 m->m_len -= sizeof (struct udpiphdr);
108 m->m_off += sizeof (struct udpiphdr);
599c842e 109SBCHECK(&inp->inp_socket->so_rcv, "udpinput before");
4e60622a 110 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0)
2b4b57cd 111 goto bad;
599c842e 112SBCHECK(&inp->inp_socket->so_rcv, "udpinput after");
4e60622a 113 sorwakeup(inp->inp_socket);
53a5409e 114 return;
2b4b57cd 115bad:
53a5409e 116 m_freem(m);
1bd53abe
BJ
117}
118
72e4f44e
SL
119udp_abort(inp)
120 struct inpcb *inp;
121{
122 struct socket *so = inp->inp_socket;
123
124 in_pcbdisconnect(inp);
125 soisdisconnected(so);
1bd53abe
BJ
126}
127
39674d5f
SL
128udp_ctlinput(cmd, arg)
129 int cmd;
130 caddr_t arg;
131{
132 struct in_addr *sin;
133 extern u_char inetctlerrmap[];
39674d5f
SL
134
135 if (cmd < 0 || cmd > PRC_NCMDS)
136 return;
137 switch (cmd) {
138
139 case PRC_ROUTEDEAD:
140 break;
141
142 case PRC_QUENCH:
143 break;
144
145 /* these are handled by ip */
146 case PRC_IFDOWN:
147 case PRC_HOSTDEAD:
148 case PRC_HOSTUNREACH:
149 break;
150
151 default:
152 sin = &((struct icmp *)arg)->icmp_ip.ip_dst;
153 in_pcbnotify(&udb, sin, inetctlerrmap[cmd], udp_abort);
154 }
155}
156
4ad99bae 157udp_output(inp, m0)
2b4b57cd 158 struct inpcb *inp;
2b4b57cd 159 struct mbuf *m0;
1bd53abe 160{
2b4b57cd
BJ
161 register struct mbuf *m;
162 register struct udpiphdr *ui;
a13c006d 163 register struct socket *so;
2b4b57cd
BJ
164 register int len = 0;
165
166 /*
167 * Calculate data length and get a mbuf
4aed14e3 168 * for UDP and IP headers.
2b4b57cd
BJ
169 */
170 for (m = m0; m; m = m->m_next)
171 len += m->m_len;
ef9b4258 172 m = m_get(M_DONTWAIT);
8a2f82db
SL
173 if (m == 0) {
174 m_freem(m0);
175 return (ENOBUFS);
176 }
2b4b57cd
BJ
177
178 /*
4aed14e3 179 * Fill in mbuf with extended UDP header
2b4b57cd
BJ
180 * and addresses and length put into network format.
181 */
182 m->m_off = MMAXOFF - sizeof (struct udpiphdr);
183 m->m_len = sizeof (struct udpiphdr);
184 m->m_next = m0;
185 ui = mtod(m, struct udpiphdr *);
186 ui->ui_next = ui->ui_prev = 0;
187 ui->ui_x1 = 0;
188 ui->ui_pr = IPPROTO_UDP;
e199a8a5 189 ui->ui_len = len + sizeof (struct udphdr);
4e60622a
BJ
190 ui->ui_src = inp->inp_laddr;
191 ui->ui_dst = inp->inp_faddr;
192 ui->ui_sport = inp->inp_lport;
193 ui->ui_dport = inp->inp_fport;
e199a8a5 194 ui->ui_ulen = htons((u_short)ui->ui_len);
2b4b57cd
BJ
195
196 /*
197 * Stuff checksum and output datagram.
198 */
199 ui->ui_sum = 0;
ce605ce8 200 ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
4e60622a
BJ
201 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
202 ((struct ip *)ui)->ip_ttl = MAXTTL;
a13c006d
BJ
203 so = inp->inp_socket;
204 return (ip_output(m, (struct mbuf *)0,
205 (so->so_options & SO_DONTROUTE) ? &routetoif : (struct route *)0,
206 so->so_state & SS_PRIV));
1bd53abe
BJ
207}
208
8075bb0e 209udp_usrreq(so, req, m, nam, opt)
53a5409e 210 struct socket *so;
1bd53abe 211 int req;
8075bb0e
BJ
212 struct mbuf *m, *nam;
213 struct socketopt *opt;
1bd53abe 214{
53a5409e 215 struct inpcb *inp = sotoinpcb(so);
8a2f82db 216 int error = 0;
1bd53abe 217
bbb5f5dd 218 if (inp == 0 && req != PRU_ATTACH)
4e60622a 219 return (EINVAL);
1bd53abe
BJ
220 switch (req) {
221
222 case PRU_ATTACH:
53a5409e
BJ
223 if (inp != 0)
224 return (EINVAL);
8075bb0e
BJ
225 error = in_pcballoc(so, &udb);
226 if (error)
227 break;
228 error = in_pcbreserve(so, 2048, 2048);
229 if (error)
230 break;
53a5409e 231 break;
1bd53abe
BJ
232
233 case PRU_DETACH:
53a5409e
BJ
234 if (inp == 0)
235 return (ENOTCONN);
405c9168 236 in_pcbdetach(inp);
53a5409e 237 break;
1bd53abe 238
8075bb0e
BJ
239 case PRU_BIND:
240 error = in_pcbbind(inp, nam);
241 break;
242
243 case PRU_LISTEN:
244 error = EOPNOTSUPP;
245 break;
246
1bd53abe 247 case PRU_CONNECT:
4ad99bae 248 if (inp->inp_faddr.s_addr)
53a5409e 249 return (EISCONN);
8075bb0e 250 error = in_pcbconnect(inp, nam);
8a2f82db
SL
251 if (error == 0)
252 soisconnected(so);
1bd53abe
BJ
253 break;
254
2b4b57cd
BJ
255 case PRU_ACCEPT:
256 return (EOPNOTSUPP);
257
53a5409e 258 case PRU_DISCONNECT:
4ad99bae 259 if (inp->inp_faddr.s_addr == 0)
53a5409e 260 return (ENOTCONN);
405c9168 261 in_pcbdisconnect(inp);
53a5409e 262 soisdisconnected(so);
1bd53abe
BJ
263 break;
264
cdad2eb1
BJ
265 case PRU_SHUTDOWN:
266 socantsendmore(so);
267 break;
268
1aa87517
BJ
269 case PRU_SEND: {
270 struct in_addr laddr;
271
8075bb0e 272 if (nam) {
1aa87517 273 laddr = inp->inp_laddr;
02bcdb4e 274 if (inp->inp_faddr.s_addr)
53a5409e 275 return (EISCONN);
8075bb0e 276 error = in_pcbconnect(inp, nam);
02bcdb4e 277 if (error)
8a2f82db 278 break;
4ad99bae
BJ
279 } else {
280 if (inp->inp_faddr.s_addr == 0)
281 return (ENOTCONN);
282 }
8a2f82db 283 error = udp_output(inp, m);
8075bb0e 284 if (nam) {
405c9168 285 in_pcbdisconnect(inp);
1aa87517
BJ
286 inp->inp_laddr = laddr;
287 }
288 }
1bd53abe
BJ
289 break;
290
291 case PRU_ABORT:
405c9168 292 in_pcbdetach(inp);
53a5409e
BJ
293 sofree(so);
294 soisdisconnected(so);
1bd53abe
BJ
295 break;
296
297 case PRU_CONTROL:
53a5409e 298 return (EOPNOTSUPP);
1bd53abe 299
126472ab 300 case PRU_SOCKADDR:
8075bb0e 301 in_setsockaddr(inp, nam);
126472ab
SL
302 break;
303
1bd53abe
BJ
304 default:
305 panic("udp_usrreq");
d52566dd 306 }
8a2f82db 307 return (error);
d52566dd 308}