Commit | Line | Data |
---|---|---|
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 |
22 | udp_init() |
23 | { | |
24 | ||
ce605ce8 | 25 | COUNT(UDP_INIT); |
eb44bfb2 | 26 | udb.inp_next = udb.inp_prev = &udb; |
d52566dd | 27 | } |
1bd53abe | 28 | |
eb44bfb2 | 29 | int udpcksum; |
2b4b57cd | 30 | struct sockaddr_in udp_in = { AF_INET }; |
eb44bfb2 | 31 | |
2b4b57cd BJ |
32 | udp_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 | 40 | COUNT(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 | 106 | bad: |
53a5409e | 107 | m_freem(m); |
1bd53abe BJ |
108 | } |
109 | ||
cdad2eb1 | 110 | udp_ctlinput(m) |
1bd53abe BJ |
111 | struct mbuf *m; |
112 | { | |
113 | ||
ce605ce8 | 114 | COUNT(UDP_CTLINPUT); |
1bd53abe BJ |
115 | m_freem(m); |
116 | } | |
117 | ||
4ad99bae | 118 | udp_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 | 126 | COUNT(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; |
165 | bad: | |
166 | m_freem(m); | |
1bd53abe BJ |
167 | } |
168 | ||
53a5409e BJ |
169 | udp_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 | 178 | COUNT(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 | } |