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