icmp and ctlinput working -- missing protocol specific ctlinput's
[unix-history] / usr / src / sys / netinet / udp_usrreq.c
CommitLineData
72e4f44e 1/* udp_usrreq.c 4.27 82/04/24 */
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);
99 if (ui->ui_dst.s_addr != broadcastaddr.s_addr)
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_ctlinput(cmd, arg)
122 int cmd;
123 caddr_t arg;
1bd53abe
BJ
124{
125
ce605ce8 126COUNT(UDP_CTLINPUT);
72e4f44e
SL
127}
128
129udp_abort(inp)
130 struct inpcb *inp;
131{
132 struct socket *so = inp->inp_socket;
133
134 in_pcbdisconnect(inp);
135 soisdisconnected(so);
1bd53abe
BJ
136}
137
4ad99bae 138udp_output(inp, m0)
2b4b57cd 139 struct inpcb *inp;
2b4b57cd 140 struct mbuf *m0;
1bd53abe 141{
2b4b57cd
BJ
142 register struct mbuf *m;
143 register struct udpiphdr *ui;
144 register int len = 0;
145
ce605ce8 146COUNT(UDP_OUTPUT);
2b4b57cd
BJ
147 /*
148 * Calculate data length and get a mbuf
4aed14e3 149 * for UDP and IP headers.
2b4b57cd
BJ
150 */
151 for (m = m0; m; m = m->m_next)
152 len += m->m_len;
ef9b4258 153 m = m_get(M_DONTWAIT);
8a2f82db
SL
154 if (m == 0) {
155 m_freem(m0);
156 return (ENOBUFS);
157 }
2b4b57cd
BJ
158
159 /*
4aed14e3 160 * Fill in mbuf with extended UDP header
2b4b57cd
BJ
161 * and addresses and length put into network format.
162 */
163 m->m_off = MMAXOFF - sizeof (struct udpiphdr);
164 m->m_len = sizeof (struct udpiphdr);
165 m->m_next = m0;
166 ui = mtod(m, struct udpiphdr *);
167 ui->ui_next = ui->ui_prev = 0;
168 ui->ui_x1 = 0;
169 ui->ui_pr = IPPROTO_UDP;
4e60622a
BJ
170 ui->ui_len = sizeof (struct udpiphdr) + len;
171 ui->ui_src = inp->inp_laddr;
172 ui->ui_dst = inp->inp_faddr;
173 ui->ui_sport = inp->inp_lport;
174 ui->ui_dport = inp->inp_fport;
4ad99bae 175 ui->ui_ulen = htons((u_short)len);
2b4b57cd
BJ
176
177 /*
178 * Stuff checksum and output datagram.
179 */
180 ui->ui_sum = 0;
ce605ce8 181 ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
4e60622a
BJ
182 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
183 ((struct ip *)ui)->ip_ttl = MAXTTL;
8a2f82db
SL
184 return (ip_output(m, (struct mbuf *)0, 0,
185 inp->inp_socket->so_state & SS_PRIV));
1bd53abe
BJ
186}
187
53a5409e
BJ
188udp_usrreq(so, req, m, addr)
189 struct socket *so;
1bd53abe
BJ
190 int req;
191 struct mbuf *m;
cdad2eb1 192 caddr_t addr;
1bd53abe 193{
53a5409e 194 struct inpcb *inp = sotoinpcb(so);
8a2f82db 195 int error = 0;
1bd53abe 196
ce605ce8 197COUNT(UDP_USRREQ);
bbb5f5dd 198 if (inp == 0 && req != PRU_ATTACH)
4e60622a 199 return (EINVAL);
1bd53abe
BJ
200 switch (req) {
201
202 case PRU_ATTACH:
53a5409e
BJ
203 if (inp != 0)
204 return (EINVAL);
8a2f82db
SL
205 error = in_pcbattach(so, &udb, 2048, 2048,
206 (struct sockaddr_in *)addr);
53a5409e 207 break;
1bd53abe
BJ
208
209 case PRU_DETACH:
53a5409e
BJ
210 if (inp == 0)
211 return (ENOTCONN);
405c9168 212 in_pcbdetach(inp);
53a5409e 213 break;
1bd53abe
BJ
214
215 case PRU_CONNECT:
4ad99bae 216 if (inp->inp_faddr.s_addr)
53a5409e 217 return (EISCONN);
405c9168 218 error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
8a2f82db
SL
219 if (error == 0)
220 soisconnected(so);
1bd53abe
BJ
221 break;
222
2b4b57cd
BJ
223 case PRU_ACCEPT:
224 return (EOPNOTSUPP);
225
53a5409e 226 case PRU_DISCONNECT:
4ad99bae 227 if (inp->inp_faddr.s_addr == 0)
53a5409e 228 return (ENOTCONN);
405c9168 229 in_pcbdisconnect(inp);
53a5409e 230 soisdisconnected(so);
1bd53abe
BJ
231 break;
232
cdad2eb1
BJ
233 case PRU_SHUTDOWN:
234 socantsendmore(so);
235 break;
236
1aa87517
BJ
237 case PRU_SEND: {
238 struct in_addr laddr;
239
53a5409e 240 if (addr) {
1aa87517 241 laddr = inp->inp_laddr;
02bcdb4e 242 if (inp->inp_faddr.s_addr)
53a5409e 243 return (EISCONN);
405c9168 244 error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
02bcdb4e 245 if (error)
8a2f82db 246 break;
4ad99bae
BJ
247 } else {
248 if (inp->inp_faddr.s_addr == 0)
249 return (ENOTCONN);
250 }
8a2f82db 251 error = udp_output(inp, m);
1aa87517 252 if (addr) {
405c9168 253 in_pcbdisconnect(inp);
1aa87517
BJ
254 inp->inp_laddr = laddr;
255 }
256 }
1bd53abe
BJ
257 break;
258
259 case PRU_ABORT:
405c9168 260 in_pcbdetach(inp);
53a5409e
BJ
261 sofree(so);
262 soisdisconnected(so);
1bd53abe
BJ
263 break;
264
265 case PRU_CONTROL:
53a5409e 266 return (EOPNOTSUPP);
1bd53abe 267
126472ab
SL
268 case PRU_SOCKADDR:
269 in_setsockaddr((struct sockaddr_in *)addr, inp);
270 break;
271
1bd53abe
BJ
272 default:
273 panic("udp_usrreq");
d52566dd 274 }
8a2f82db 275 return (error);
d52566dd 276}