1 /* udp_usrreq.c 4.45 83/02/16 */
2 /*
3 * UDP protocol implementation.
4 * Per RFC 768, August, 1980.
5 */
6
7 #include "../h/param.h"
8 #include "../h/dir.h"
9 #include "../h/user.h"
10 #include "../h/mbuf.h"
11 #include "../h/protosw.h"
12 #include "../h/socket.h"
13 #include "../h/socketvar.h"
14 #include "../h/errno.h"
15
16 #include "../net/if.h"
17 #include "../net/route.h"
18
19 #include "../bbnnet/in.h"
20 #include "../bbnnet/in_var.h"
21 #include "../bbnnet/net.h"
22 #include "../bbnnet/in_pcb.h"
23 #include "../bbnnet/ip.h"
24 #include "../bbnnet/udp.h"
25 #include "../bbnnet/fsm.h"
26 #include "../bbnnet/tcp.h"
27 #include "../bbnnet/icmp.h"
28
29 extern udp_binding_used();
30 extern struct inpcb udp;
31
32 struct pr_advice udp_advice =
33 {
34 UDP_RESERVED, /* all basically the same as TCP */
35 UDP_USERRESERVED,
36 UDP_MAXPORT,
37 UDP_USERRESERVED+1,
38 sizeof(u_short),
39 udp_binding_used
40 } ;
41
udp_init()42 udp_init()
43 {
44 udp.inp_next = udp.inp_prev = &udp;
45 ipsw[IPPROTO_UDP].ipsw_hlen = sizeof(struct udp);
46 }
47
48 udp_abort(inp)
49 struct inpcb *inp;
50 {
51 struct socket *so = inp->inp_socket;
52
53 in_pcbdisconnect(inp, (int(*)())0);
54 soisdisconnected(so);
55 }
56
57 /*
58 * Is a udp port/address pair already in use?
59 */
udp_binding_used(inp,lport,lsaddr,reuselocal)60 int udp_binding_used(inp, lport, lsaddr, reuselocal)
61 struct inpcb *inp;
62 u_short lport;
63 u_long lsaddr;
64 {
65 register struct inpcb *i;
66
67 if (reuselocal)
68 /*
69 * But since UDP, unlike TCP, is not connection oriented,
70 * this allows for liars to exist.
71 */
72 return (0);
73
74 for (i = udp.inp_next; i != &udp; i = i->inp_next)
75 {
76 if (i != inp)
77 if (i->inp_lport == lport)
78 if ((i->inp_laddr.s_addr == lsaddr) ||
79 (i->inp_laddr.s_addr == INADDR_ANY) ||
80 (lsaddr == INADDR_ANY))
81 break;
82 }
83 return (i != &udp);
84 }
85
udp_conn_used(inp,lport,lsaddr,fport,fsaddr)86 char *udp_conn_used(inp, lport, lsaddr, fport, fsaddr)
87 struct inpcb *inp;
88 u_short lport;
89 u_long lsaddr;
90 u_short fport;
91 u_long fsaddr;
92 {
93 register struct inpcb *i;
94
95 for (i = udp.inp_next; i != &udp; i = i->inp_next)
96 {
97 /*
98 * Since our inpcb is in this linked list, don't want to know
99 * if we, ourselves, are already using this connetion.
100 */
101 if (i != inp)
102 if ((i->inp_lport == lport) && (i->inp_fport == fport) &&
103 (i->inp_laddr.s_addr == lsaddr) &&
104 (i->inp_faddr.s_addr == fsaddr))
105 return((char *) i);
106 }
107
108 return ((char *) NULL);
109 }
110
111
112 /*ARGSUSED*/
113 udp_usrreq(so, req, m, nam, rights)
114 struct socket *so;
115 register int req;
116 struct mbuf *m, *nam, *rights;
117 {
118 register int s;
119 struct inpcb *inp;
120 int error = 0;
121
122 s = splnet();
123 inp = sotoinpcb(so);
124
125 if (rights && req != PRU_CONTROL)
126 {
127 if (rights->m_len)
128 {
129 error = EINVAL;
130 goto release;
131 }
132 }
133
134 if (inp == NULL && req != PRU_ATTACH)
135 {
136 error = EINVAL;
137 goto release;
138 }
139
140 switch (req)
141 {
142
143 case PRU_ATTACH:
144 if (inp != NULL)
145 {
146 error = EINVAL;
147 break;
148 }
149 error = soreserve(so, 2048, 2048);
150 if (error)
151 break;
152 error = in_pcballoc(so, &udp);
153 if (error)
154 break;
155 break;
156
157 case PRU_DETACH:
158 if (inp == NULL)
159 {
160 error = ENOTCONN;
161 break;
162 }
163 in_pcbdetach(inp, (int (*)())0);
164 break;
165
166 case PRU_BIND:
167 error = in_pcbbind(inp, nam, &udp_advice);
168 break;
169
170 case PRU_LISTEN:
171 error = EOPNOTSUPP;
172 break;
173
174 case PRU_CONNECT:
175 if (inp->inp_faddr.s_addr != INADDR_ANY)
176 {
177 error = EISCONN;
178 break;
179 }
180 if (inp->inp_lport == 0)
181 {
182 error = in_pcbbind(inp, (struct mbuf *)0, &udp_advice);
183 if (error)
184 break;
185 }
186 error = in_pcbconnect(inp, nam, udp_conn_used);
187 if (error == 0)
188 soisconnected(so);
189 break;
190
191 case PRU_ACCEPT:
192 error = EOPNOTSUPP;
193 break;
194
195 case PRU_DISCONNECT:
196 if (inp->inp_faddr.s_addr == INADDR_ANY)
197 {
198 error = ENOTCONN;
199 break;
200 }
201 in_pcbdisconnect(inp, (int(*)())0);
202 soisdisconnected(so);
203 break;
204
205 case PRU_SHUTDOWN:
206 socantsendmore(so);
207 break;
208
209 case PRU_SEND:
210 {
211 struct in_addr laddr;
212
213 if (nam)
214 {
215 laddr = inp->inp_laddr;
216 if (inp->inp_faddr.s_addr != INADDR_ANY)
217 {
218 error = EISCONN;
219 break;
220 }
221 if (inp->inp_lport == 0)
222 {
223 if (error = in_pcbbind(inp, (struct mbuf *)0, &udp_advice))
224 break;
225 }
226 error = in_pcbconnect(inp, nam, udp_conn_used);
227 if (error)
228 break;
229 }
230 else
231 {
232 if (inp->inp_faddr.s_addr == INADDR_ANY)
233 {
234 error = ENOTCONN;
235 break;
236 }
237 }
238 error = udp_output(inp, m);
239 m = NULL;
240 if (nam)
241 {
242 in_pcbdisconnect(inp, (int(*))0);
243 inp->inp_laddr = laddr;
244 }
245 }
246 break;
247
248 case PRU_ABORT:
249 in_pcbdetach(inp, (int (*)())0);
250 break;
251
252 case PRU_CONTROL:
253 /* not our ioctl, let lower level try ioctl */
254 error = ip_ioctl (inp, (int) m, (caddr_t) nam);
255 goto dontfree;
256
257 case PRU_SOCKADDR:
258 in_setsockaddr(inp, nam);
259 break;
260
261 default:
262 panic("udp_usrreq");
263 }
264
265 release :
266 if (m != NULL)
267 m_freem(m);
268 dontfree:
269 splx(s);
270 return (error);
271 }
272
udp_ctlinput(prc_code,arg)273 udp_ctlinput (prc_code, arg)
274 caddr_t arg;
275 {
276 int error;
277
278 error = inetctlerrmap[prc_code];
279
280 switch (prc_code)
281 {
282 case PRC_UNREACH_PROTOCOL: /* icmp message */
283 case PRC_UNREACH_PORT:
284 case PRC_MSGSIZE:
285 {
286 register struct udp *up;
287 struct inpcb *inp;
288
289 up = (struct udp *) (&((struct icmp *) arg)->ic_iphdr);
290 inp = (struct inpcb *)udp_conn_used ((struct inpcb *) 0,
291 up->u_src, up->u_s.s_addr,
292 up->u_dst, up->u_d.s_addr);
293
294 if (inp)
295 {
296 inp->inp_socket->so_error = error;
297 udp_abort(inp);
298 }
299 }
300 break;
301
302 case PRC_UNREACH_NET:
303 case PRC_UNREACH_HOST:
304 {
305 register struct udp *up;
306 struct inpcb *inp;
307
308 up = (struct udp *) (&((struct icmp *) arg)->ic_iphdr);
309 inp = (struct inpcb *)udp_conn_used ((struct inpcb *) 0,
310 up->u_src, up->u_s.s_addr,
311 up->u_dst, up->u_d.s_addr);
312
313 if (inp)
314 {
315 struct socket *so;
316
317 so = inp->inp_socket;
318 if ((so->so_state & SS_NOFDREF) == 0)
319 advise_user(so, error);
320 else
321 {
322 so->so_error = error;
323 udp_abort(inp);
324 }
325 }
326 }
327 break;
328
329 case PRC_GWDOWN:
330 in_gdown (&udp, (u_long) arg);
331 break;
332
333 case PRC_REDIRECT_NET: /* icmp message */
334 case PRC_REDIRECT_HOST:
335 {
336 register struct udp *up;
337 struct inpcb *inp;
338
339 up = (struct udp *) (&((struct icmp *) arg)->ic_iphdr);
340 inp = (struct inpcb *)udp_conn_used ((struct inpcb *) 0,
341 up->u_src, up->u_s.s_addr,
342 up->u_dst, up->u_d.s_addr);
343
344 if (inp)
345 icmp_redirect_inp(inp, (struct icmp *) arg,
346 prc_code == PRC_REDIRECT_NET ? rtnet : rthost);
347 }
348 break;
349
350 case PRC_TIMXCEED_INTRANS: /* icmp message */
351 case PRC_TIMXCEED_REASS:
352 case PRC_PARAMPROB:
353 case PRC_QUENCH:
354 break;
355
356 case PRC_IFDOWN:
357 {
358 u_long addr;
359
360 addr = ((struct sockaddr_in *)(arg))->sin_addr.s_addr;
361 inpcb_notify(&udp, addr, (u_long) 0, error);
362 inpcb_notify(&udp, (u_long) 0, addr, error);
363 }
364 break;
365
366 case PRC_HOSTDEAD: /* from imp interface */
367 case PRC_HOSTUNREACH:
368 /*
369 * get same message for destination hosts and gateways.
370 */
371 {
372 u_long addr;
373
374 addr = ((struct sockaddr_in *)arg)->sin_addr.s_addr;
375 in_gdown (&udp, addr);
376 inpcb_notify(&udp, (u_long) 0, addr, error);
377 }
378 break;
379
380 default:
381 panic("udp_ctlinput");
382 }
383 }
384