interfac queueing, restrictions on packets, tcp keep alives done
[unix-history] / usr / src / sys / netinet / udp_usrreq.c
CommitLineData
1e977657 1/* udp_usrreq.c 4.22 82/03/15 */
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
BJ
10#include "../net/in.h"
11#include "../net/in_pcb.h"
12#include "../net/in_systm.h"
eb44bfb2
BJ
13#include "../net/ip.h"
14#include "../net/ip_var.h"
53a5409e
BJ
15#include "../net/udp.h"
16#include "../net/udp_var.h"
d52566dd 17
2b4b57cd
BJ
18/*
19 * UDP protocol implementation.
20 * Per RFC 768, August, 1980.
21 */
d52566dd
BJ
22udp_init()
23{
24
ce605ce8 25COUNT(UDP_INIT);
eb44bfb2 26 udb.inp_next = udb.inp_prev = &udb;
d52566dd 27}
1bd53abe 28
eb44bfb2 29int udpcksum;
2b4b57cd 30struct sockaddr_in udp_in = { AF_INET };
eb44bfb2 31
2b4b57cd
BJ
32udp_input(m0)
33 struct mbuf *m0;
1bd53abe 34{
eb44bfb2 35 register struct udpiphdr *ui;
53a5409e 36 register struct inpcb *inp;
2b4b57cd
BJ
37 register struct mbuf *m;
38 int len, ulen;
eb44bfb2 39
ce605ce8 40COUNT(UDP_INPUT);
2b4b57cd 41 /*
4aed14e3 42 * Get IP and UDP header together in first mbuf.
2b4b57cd
BJ
43 */
44 m = m0;
89925e89
BJ
45 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&
46 (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
2b4b57cd 47 udpstat.udps_hdrops++;
89925e89 48 return;
2b4b57cd 49 }
4e60622a 50 ui = mtod(m, struct udpiphdr *);
4aed14e3 51 if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))
cca1853f 52 ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
2b4b57cd
BJ
53
54 /*
4aed14e3
BJ
55 * Make mbuf data length reflect UDP length.
56 * If not enough data to reflect UDP length, drop.
2b4b57cd 57 */
4ad99bae 58 ulen = ntohs((u_short)ui->ui_ulen);
cca1853f 59 len = sizeof (struct udphdr) + ulen;
2b4b57cd
BJ
60 if (((struct ip *)ui)->ip_len != len) {
61 if (len > ((struct ip *)ui)->ip_len) {
62 udpstat.udps_badlen++;
63 goto bad;
64 }
65 m_adj(m, ((struct ip *)ui)->ip_len - len);
66 /* (struct ip *)ui->ip_len = len; */
67 }
68
69 /*
4aed14e3 70 * Checksum extended UDP header and data.
2b4b57cd 71 */
eb44bfb2 72 if (udpcksum) {
2b4b57cd
BJ
73 ui->ui_next = ui->ui_prev = 0;
74 ui->ui_x1 = 0;
cca1853f
BJ
75 ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen));
76 if (ui->ui_sum = in_cksum(m, len)) {
2b4b57cd 77 udpstat.udps_badsum++;
eb44bfb2
BJ
78 printf("udp cksum %x\n", ui->ui_sum);
79 m_freem(m);
80 return;
81 }
82 }
2b4b57cd
BJ
83
84 /*
1aa87517
BJ
85 * Locate pcb for datagram. On wildcard match, update
86 * control block to anchor network and host address.
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);
bbb5f5dd 91 if (inp == 0)
2b4b57cd
BJ
92 goto bad;
93
94 /*
95 * Construct sockaddr format source address.
96 * Stuff source address and datagram in user buffer.
97 */
98 udp_in.sin_port = ui->ui_sport;
99 udp_in.sin_addr = ui->ui_src;
4e60622a
BJ
100 m->m_len -= sizeof (struct udpiphdr);
101 m->m_off += sizeof (struct udpiphdr);
102 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0)
2b4b57cd 103 goto bad;
4e60622a 104 sorwakeup(inp->inp_socket);
53a5409e 105 return;
2b4b57cd 106bad:
53a5409e 107 m_freem(m);
1bd53abe
BJ
108}
109
cdad2eb1 110udp_ctlinput(m)
1bd53abe
BJ
111 struct mbuf *m;
112{
113
ce605ce8 114COUNT(UDP_CTLINPUT);
1bd53abe
BJ
115 m_freem(m);
116}
117
4ad99bae 118udp_output(inp, m0)
2b4b57cd 119 struct inpcb *inp;
2b4b57cd 120 struct mbuf *m0;
1bd53abe 121{
2b4b57cd
BJ
122 register struct mbuf *m;
123 register struct udpiphdr *ui;
124 register int len = 0;
125
ce605ce8 126COUNT(UDP_OUTPUT);
2b4b57cd
BJ
127 /*
128 * Calculate data length and get a mbuf
4aed14e3 129 * for UDP and IP headers.
2b4b57cd
BJ
130 */
131 for (m = m0; m; m = m->m_next)
132 len += m->m_len;
ef9b4258 133 m = m_get(M_DONTWAIT);
bbb5f5dd 134 if (m == 0)
2b4b57cd
BJ
135 goto bad;
136
137 /*
4aed14e3 138 * Fill in mbuf with extended UDP header
2b4b57cd
BJ
139 * and addresses and length put into network format.
140 */
141 m->m_off = MMAXOFF - sizeof (struct udpiphdr);
142 m->m_len = sizeof (struct udpiphdr);
143 m->m_next = m0;
144 ui = mtod(m, struct udpiphdr *);
145 ui->ui_next = ui->ui_prev = 0;
146 ui->ui_x1 = 0;
147 ui->ui_pr = IPPROTO_UDP;
4e60622a
BJ
148 ui->ui_len = sizeof (struct udpiphdr) + len;
149 ui->ui_src = inp->inp_laddr;
150 ui->ui_dst = inp->inp_faddr;
151 ui->ui_sport = inp->inp_lport;
152 ui->ui_dport = inp->inp_fport;
4ad99bae 153 ui->ui_ulen = htons((u_short)len);
2b4b57cd
BJ
154
155 /*
156 * Stuff checksum and output datagram.
157 */
158 ui->ui_sum = 0;
ce605ce8 159 ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
4e60622a
BJ
160 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
161 ((struct ip *)ui)->ip_ttl = MAXTTL;
1e977657
BJ
162 (void) ip_output(m, (struct mbuf *)0,
163 inp->inp_socket->so_state & SS_PRIV);
2b4b57cd
BJ
164 return;
165bad:
166 m_freem(m);
1bd53abe
BJ
167}
168
53a5409e
BJ
169udp_usrreq(so, req, m, addr)
170 struct socket *so;
1bd53abe
BJ
171 int req;
172 struct mbuf *m;
cdad2eb1 173 caddr_t addr;
1bd53abe 174{
53a5409e
BJ
175 struct inpcb *inp = sotoinpcb(so);
176 int error;
1bd53abe 177
ce605ce8 178COUNT(UDP_USRREQ);
bbb5f5dd 179 if (inp == 0 && req != PRU_ATTACH)
4e60622a 180 return (EINVAL);
1bd53abe
BJ
181 switch (req) {
182
183 case PRU_ATTACH:
53a5409e
BJ
184 if (inp != 0)
185 return (EINVAL);
405c9168 186 error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr);
bbb5f5dd 187 if (error)
4ad99bae 188 return (error);
53a5409e 189 break;
1bd53abe
BJ
190
191 case PRU_DETACH:
53a5409e
BJ
192 if (inp == 0)
193 return (ENOTCONN);
405c9168 194 in_pcbdetach(inp);
53a5409e 195 break;
1bd53abe
BJ
196
197 case PRU_CONNECT:
4ad99bae 198 if (inp->inp_faddr.s_addr)
53a5409e 199 return (EISCONN);
405c9168 200 error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
bbb5f5dd 201 if (error)
53a5409e
BJ
202 return (error);
203 soisconnected(so);
1bd53abe
BJ
204 break;
205
2b4b57cd
BJ
206 case PRU_ACCEPT:
207 return (EOPNOTSUPP);
208
53a5409e 209 case PRU_DISCONNECT:
4ad99bae 210 if (inp->inp_faddr.s_addr == 0)
53a5409e 211 return (ENOTCONN);
405c9168 212 in_pcbdisconnect(inp);
53a5409e 213 soisdisconnected(so);
1bd53abe
BJ
214 break;
215
cdad2eb1
BJ
216 case PRU_SHUTDOWN:
217 socantsendmore(so);
218 break;
219
1aa87517
BJ
220 case PRU_SEND: {
221 struct in_addr laddr;
222
53a5409e 223 if (addr) {
1aa87517 224 laddr = inp->inp_laddr;
02bcdb4e 225 if (inp->inp_faddr.s_addr)
53a5409e 226 return (EISCONN);
405c9168 227 error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
02bcdb4e 228 if (error)
4ad99bae
BJ
229 return (error);
230 } else {
231 if (inp->inp_faddr.s_addr == 0)
232 return (ENOTCONN);
233 }
234 udp_output(inp, m);
1aa87517 235 if (addr) {
405c9168 236 in_pcbdisconnect(inp);
1aa87517 237 inp->inp_laddr = laddr;
ebcadd38 238 in_setsockaddr(inp);
1aa87517
BJ
239 }
240 }
1bd53abe
BJ
241 break;
242
243 case PRU_ABORT:
405c9168 244 in_pcbdetach(inp);
53a5409e
BJ
245 sofree(so);
246 soisdisconnected(so);
1bd53abe
BJ
247 break;
248
249 case PRU_CONTROL:
53a5409e 250 return (EOPNOTSUPP);
1bd53abe
BJ
251
252 default:
253 panic("udp_usrreq");
d52566dd 254 }
53a5409e 255 return (0);
d52566dd 256}