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