m_get(0) -> m_get(M_DONTWAIT)
[unix-history] / usr / src / sys / netinet / udp_usrreq.c
CommitLineData
ef9b4258 1/* udp_usrreq.c 4.19 82/01/19 */
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 /*
2b4b57cd
BJ
85 * Locate pcb for datagram.
86 */
2b4b57cd
BJ
87 inp = in_pcblookup(&udb,
88 ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport);
bbb5f5dd 89 if (inp == 0)
2b4b57cd
BJ
90 goto bad;
91
92 /*
93 * Construct sockaddr format source address.
94 * Stuff source address and datagram in user buffer.
95 */
96 udp_in.sin_port = ui->ui_sport;
97 udp_in.sin_addr = ui->ui_src;
4e60622a
BJ
98 m->m_len -= sizeof (struct udpiphdr);
99 m->m_off += sizeof (struct udpiphdr);
100 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0)
2b4b57cd 101 goto bad;
4e60622a 102 sorwakeup(inp->inp_socket);
53a5409e 103 return;
2b4b57cd 104bad:
53a5409e 105 m_freem(m);
1bd53abe
BJ
106}
107
cdad2eb1 108udp_ctlinput(m)
1bd53abe
BJ
109 struct mbuf *m;
110{
111
ce605ce8 112COUNT(UDP_CTLINPUT);
1bd53abe
BJ
113 m_freem(m);
114}
115
4ad99bae 116udp_output(inp, m0)
2b4b57cd 117 struct inpcb *inp;
2b4b57cd 118 struct mbuf *m0;
1bd53abe 119{
2b4b57cd
BJ
120 register struct mbuf *m;
121 register struct udpiphdr *ui;
122 register int len = 0;
123
ce605ce8 124COUNT(UDP_OUTPUT);
2b4b57cd
BJ
125 /*
126 * Calculate data length and get a mbuf
4aed14e3 127 * for UDP and IP headers.
2b4b57cd
BJ
128 */
129 for (m = m0; m; m = m->m_next)
130 len += m->m_len;
ef9b4258 131 m = m_get(M_DONTWAIT);
bbb5f5dd 132 if (m == 0)
2b4b57cd
BJ
133 goto bad;
134
135 /*
4aed14e3 136 * Fill in mbuf with extended UDP header
2b4b57cd
BJ
137 * and addresses and length put into network format.
138 */
139 m->m_off = MMAXOFF - sizeof (struct udpiphdr);
140 m->m_len = sizeof (struct udpiphdr);
141 m->m_next = m0;
142 ui = mtod(m, struct udpiphdr *);
143 ui->ui_next = ui->ui_prev = 0;
144 ui->ui_x1 = 0;
145 ui->ui_pr = IPPROTO_UDP;
4e60622a
BJ
146 ui->ui_len = sizeof (struct udpiphdr) + len;
147 ui->ui_src = inp->inp_laddr;
148 ui->ui_dst = inp->inp_faddr;
149 ui->ui_sport = inp->inp_lport;
150 ui->ui_dport = inp->inp_fport;
4ad99bae 151 ui->ui_ulen = htons((u_short)len);
2b4b57cd
BJ
152
153 /*
154 * Stuff checksum and output datagram.
155 */
156 ui->ui_sum = 0;
ce605ce8 157 ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
4e60622a
BJ
158 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
159 ((struct ip *)ui)->ip_ttl = MAXTTL;
f1b2fa5b 160 (void) ip_output(m, (struct mbuf *)0);
2b4b57cd
BJ
161 return;
162bad:
163 m_freem(m);
1bd53abe
BJ
164}
165
53a5409e
BJ
166udp_usrreq(so, req, m, addr)
167 struct socket *so;
1bd53abe
BJ
168 int req;
169 struct mbuf *m;
cdad2eb1 170 caddr_t addr;
1bd53abe 171{
53a5409e
BJ
172 struct inpcb *inp = sotoinpcb(so);
173 int error;
1bd53abe 174
ce605ce8 175COUNT(UDP_USRREQ);
bbb5f5dd 176 if (inp == 0 && req != PRU_ATTACH)
4e60622a 177 return (EINVAL);
1bd53abe
BJ
178 switch (req) {
179
180 case PRU_ATTACH:
53a5409e
BJ
181 if (inp != 0)
182 return (EINVAL);
405c9168 183 error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr);
bbb5f5dd 184 if (error)
4ad99bae 185 return (error);
53a5409e 186 break;
1bd53abe
BJ
187
188 case PRU_DETACH:
53a5409e
BJ
189 if (inp == 0)
190 return (ENOTCONN);
405c9168 191 in_pcbdetach(inp);
53a5409e 192 break;
1bd53abe
BJ
193
194 case PRU_CONNECT:
4ad99bae 195 if (inp->inp_faddr.s_addr)
53a5409e 196 return (EISCONN);
405c9168 197 error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
bbb5f5dd 198 if (error)
53a5409e
BJ
199 return (error);
200 soisconnected(so);
1bd53abe
BJ
201 break;
202
2b4b57cd
BJ
203 case PRU_ACCEPT:
204 return (EOPNOTSUPP);
205
53a5409e 206 case PRU_DISCONNECT:
4ad99bae 207 if (inp->inp_faddr.s_addr == 0)
53a5409e 208 return (ENOTCONN);
405c9168 209 in_pcbdisconnect(inp);
53a5409e 210 soisdisconnected(so);
1bd53abe
BJ
211 break;
212
cdad2eb1
BJ
213 case PRU_SHUTDOWN:
214 socantsendmore(so);
215 break;
216
1bd53abe 217 case PRU_SEND:
53a5409e 218 if (addr) {
02bcdb4e 219 if (inp->inp_faddr.s_addr)
53a5409e 220 return (EISCONN);
405c9168 221 error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
02bcdb4e 222 if (error)
4ad99bae
BJ
223 return (error);
224 } else {
225 if (inp->inp_faddr.s_addr == 0)
226 return (ENOTCONN);
227 }
228 udp_output(inp, m);
229 if (addr)
405c9168 230 in_pcbdisconnect(inp);
1bd53abe
BJ
231 break;
232
233 case PRU_ABORT:
405c9168 234 in_pcbdetach(inp);
53a5409e
BJ
235 sofree(so);
236 soisdisconnected(so);
1bd53abe
BJ
237 break;
238
239 case PRU_CONTROL:
53a5409e 240 return (EOPNOTSUPP);
1bd53abe
BJ
241
242 default:
243 panic("udp_usrreq");
d52566dd 244 }
53a5409e 245 return (0);
d52566dd 246}