m_get(0) -> m_get(M_DONTWAIT)
[unix-history] / usr / src / sys / netinet / udp_usrreq.c
... / ...
CommitLineData
1/* udp_usrreq.c 4.19 82/01/19 */
2
3#include "../h/param.h"
4#include "../h/dir.h"
5#include "../h/user.h"
6#include "../h/mbuf.h"
7#include "../h/protosw.h"
8#include "../h/socket.h"
9#include "../h/socketvar.h"
10#include "../net/in.h"
11#include "../net/in_pcb.h"
12#include "../net/in_systm.h"
13#include "../net/ip.h"
14#include "../net/ip_var.h"
15#include "../net/udp.h"
16#include "../net/udp_var.h"
17
18/*
19 * UDP protocol implementation.
20 * Per RFC 768, August, 1980.
21 */
22udp_init()
23{
24
25COUNT(UDP_INIT);
26 udb.inp_next = udb.inp_prev = &udb;
27}
28
29int udpcksum;
30struct sockaddr_in udp_in = { AF_INET };
31
32udp_input(m0)
33 struct mbuf *m0;
34{
35 register struct udpiphdr *ui;
36 register struct inpcb *inp;
37 register struct mbuf *m;
38 int len, ulen;
39
40COUNT(UDP_INPUT);
41 /*
42 * Get IP and UDP header together in first mbuf.
43 */
44 m = m0;
45 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&
46 (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
47 udpstat.udps_hdrops++;
48 return;
49 }
50 ui = mtod(m, struct udpiphdr *);
51 if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))
52 ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
53
54 /*
55 * Make mbuf data length reflect UDP length.
56 * If not enough data to reflect UDP length, drop.
57 */
58 ulen = ntohs((u_short)ui->ui_ulen);
59 len = sizeof (struct udphdr) + ulen;
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 /*
70 * Checksum extended UDP header and data.
71 */
72 if (udpcksum) {
73 ui->ui_next = ui->ui_prev = 0;
74 ui->ui_x1 = 0;
75 ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen));
76 if (ui->ui_sum = in_cksum(m, len)) {
77 udpstat.udps_badsum++;
78 printf("udp cksum %x\n", ui->ui_sum);
79 m_freem(m);
80 return;
81 }
82 }
83
84 /*
85 * Locate pcb for datagram.
86 */
87 inp = in_pcblookup(&udb,
88 ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport);
89 if (inp == 0)
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;
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)
101 goto bad;
102 sorwakeup(inp->inp_socket);
103 return;
104bad:
105 m_freem(m);
106}
107
108udp_ctlinput(m)
109 struct mbuf *m;
110{
111
112COUNT(UDP_CTLINPUT);
113 m_freem(m);
114}
115
116udp_output(inp, m0)
117 struct inpcb *inp;
118 struct mbuf *m0;
119{
120 register struct mbuf *m;
121 register struct udpiphdr *ui;
122 register int len = 0;
123
124COUNT(UDP_OUTPUT);
125 /*
126 * Calculate data length and get a mbuf
127 * for UDP and IP headers.
128 */
129 for (m = m0; m; m = m->m_next)
130 len += m->m_len;
131 m = m_get(M_DONTWAIT);
132 if (m == 0)
133 goto bad;
134
135 /*
136 * Fill in mbuf with extended UDP header
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;
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;
151 ui->ui_ulen = htons((u_short)len);
152
153 /*
154 * Stuff checksum and output datagram.
155 */
156 ui->ui_sum = 0;
157 ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
158 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
159 ((struct ip *)ui)->ip_ttl = MAXTTL;
160 (void) ip_output(m, (struct mbuf *)0);
161 return;
162bad:
163 m_freem(m);
164}
165
166udp_usrreq(so, req, m, addr)
167 struct socket *so;
168 int req;
169 struct mbuf *m;
170 caddr_t addr;
171{
172 struct inpcb *inp = sotoinpcb(so);
173 int error;
174
175COUNT(UDP_USRREQ);
176 if (inp == 0 && req != PRU_ATTACH)
177 return (EINVAL);
178 switch (req) {
179
180 case PRU_ATTACH:
181 if (inp != 0)
182 return (EINVAL);
183 error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr);
184 if (error)
185 return (error);
186 break;
187
188 case PRU_DETACH:
189 if (inp == 0)
190 return (ENOTCONN);
191 in_pcbdetach(inp);
192 break;
193
194 case PRU_CONNECT:
195 if (inp->inp_faddr.s_addr)
196 return (EISCONN);
197 error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
198 if (error)
199 return (error);
200 soisconnected(so);
201 break;
202
203 case PRU_ACCEPT:
204 return (EOPNOTSUPP);
205
206 case PRU_DISCONNECT:
207 if (inp->inp_faddr.s_addr == 0)
208 return (ENOTCONN);
209 in_pcbdisconnect(inp);
210 soisdisconnected(so);
211 break;
212
213 case PRU_SHUTDOWN:
214 socantsendmore(so);
215 break;
216
217 case PRU_SEND:
218 if (addr) {
219 if (inp->inp_faddr.s_addr)
220 return (EISCONN);
221 error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
222 if (error)
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)
230 in_pcbdisconnect(inp);
231 break;
232
233 case PRU_ABORT:
234 in_pcbdetach(inp);
235 sofree(so);
236 soisdisconnected(so);
237 break;
238
239 case PRU_CONTROL:
240 return (EOPNOTSUPP);
241
242 default:
243 panic("udp_usrreq");
244 }
245 return (0);
246}