|
|
1.1 cgd 1: /*
2: * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
1.2 ! cgd 33: * from: @(#)udp_usrreq.c 7.20 (Berkeley) 4/20/91
! 34: * $Id$
1.1 cgd 35: */
36:
37: #include "param.h"
38: #include "malloc.h"
1.2 ! cgd 39: #include "select.h"
1.1 cgd 40: #include "mbuf.h"
41: #include "protosw.h"
42: #include "socket.h"
43: #include "socketvar.h"
44: #include "stat.h"
45:
46: #include "../net/if.h"
47: #include "../net/route.h"
48:
49: #include "in.h"
50: #include "in_systm.h"
51: #include "ip.h"
52: #include "in_pcb.h"
53: #include "ip_var.h"
54: #include "ip_icmp.h"
55: #include "udp.h"
56: #include "udp_var.h"
57:
58: struct inpcb *udp_last_inpcb = &udb;
59:
60: /*
61: * UDP protocol implementation.
62: * Per RFC 768, August, 1980.
63: */
64: udp_init()
65: {
66:
67: udb.inp_next = udb.inp_prev = &udb;
68: }
69:
70: #ifndef COMPAT_42
71: int udpcksum = 1;
72: #else
73: int udpcksum = 0; /* XXX */
74: #endif
75: int udp_ttl = UDP_TTL;
76:
77: struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
78:
79: udp_input(m, iphlen)
80: register struct mbuf *m;
81: int iphlen;
82: {
83: register struct ip *ip;
84: register struct udphdr *uh;
85: register struct inpcb *inp;
86: struct mbuf *opts = 0;
87: int len;
88: struct ip save_ip;
89:
90: udpstat.udps_ipackets++;
91:
92: /*
93: * Strip IP options, if any; should skip this,
94: * make available to user, and use on returned packets,
95: * but we don't yet have a way to check the checksum
96: * with options still present.
97: */
98: if (iphlen > sizeof (struct ip)) {
99: ip_stripoptions(m, (struct mbuf *)0);
100: iphlen = sizeof(struct ip);
101: }
102:
103: /*
104: * Get IP and UDP header together in first mbuf.
105: */
106: ip = mtod(m, struct ip *);
107: if (m->m_len < iphlen + sizeof(struct udphdr)) {
108: if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
109: udpstat.udps_hdrops++;
110: return;
111: }
112: ip = mtod(m, struct ip *);
113: }
114: uh = (struct udphdr *)((caddr_t)ip + iphlen);
115:
116: /*
117: * Make mbuf data length reflect UDP length.
118: * If not enough data to reflect UDP length, drop.
119: */
120: len = ntohs((u_short)uh->uh_ulen);
121: if (ip->ip_len != len) {
122: if (len > ip->ip_len) {
123: udpstat.udps_badlen++;
124: goto bad;
125: }
126: m_adj(m, len - ip->ip_len);
127: /* ip->ip_len = len; */
128: }
129: /*
130: * Save a copy of the IP header in case we want restore it
131: * for sending an ICMP error message in response.
132: */
133: save_ip = *ip;
134:
135: /*
136: * Checksum extended UDP header and data.
137: */
138: if (udpcksum && uh->uh_sum) {
139: ((struct ipovly *)ip)->ih_next = 0;
140: ((struct ipovly *)ip)->ih_prev = 0;
141: ((struct ipovly *)ip)->ih_x1 = 0;
142: ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
143: if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) {
144: udpstat.udps_badsum++;
145: m_freem(m);
146: return;
147: }
148: }
149:
150: /*
151: * Locate pcb for datagram.
152: */
153: inp = udp_last_inpcb;
154: if (inp->inp_lport != uh->uh_dport ||
155: inp->inp_fport != uh->uh_sport ||
156: inp->inp_faddr.s_addr != ip->ip_src.s_addr ||
157: inp->inp_laddr.s_addr != ip->ip_dst.s_addr) {
158: inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport,
159: ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
160: if (inp)
161: udp_last_inpcb = inp;
162: udpstat.udpps_pcbcachemiss++;
163: }
164: if (inp == 0) {
165: /* don't send ICMP response for broadcast packet */
166: udpstat.udps_noport++;
167: if (m->m_flags & M_BCAST) {
168: udpstat.udps_noportbcast++;
169: goto bad;
170: }
171: *ip = save_ip;
172: ip->ip_len += iphlen;
173: icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT);
174: return;
175: }
176:
177: /*
178: * Construct sockaddr format source address.
179: * Stuff source address and datagram in user buffer.
180: */
181: udp_in.sin_port = uh->uh_sport;
182: udp_in.sin_addr = ip->ip_src;
183: if (inp->inp_flags & INP_CONTROLOPTS) {
184: struct mbuf **mp = &opts;
185: struct mbuf *udp_saveopt();
186:
187: if (inp->inp_flags & INP_RECVDSTADDR) {
188: *mp = udp_saveopt((caddr_t) &ip->ip_dst,
189: sizeof(struct in_addr), IP_RECVDSTADDR);
190: if (*mp)
191: mp = &(*mp)->m_next;
192: }
193: #ifdef notyet
194: /* options were tossed above */
195: if (inp->inp_flags & INP_RECVOPTS) {
196: *mp = udp_saveopt((caddr_t) opts_deleted_above,
197: sizeof(struct in_addr), IP_RECVOPTS);
198: if (*mp)
199: mp = &(*mp)->m_next;
200: }
201: /* ip_srcroute doesn't do what we want here, need to fix */
202: if (inp->inp_flags & INP_RECVRETOPTS) {
203: *mp = udp_saveopt((caddr_t) ip_srcroute(),
204: sizeof(struct in_addr), IP_RECVRETOPTS);
205: if (*mp)
206: mp = &(*mp)->m_next;
207: }
208: #endif
209: }
210: iphlen += sizeof(struct udphdr);
211: m->m_len -= iphlen;
212: m->m_pkthdr.len -= iphlen;
213: m->m_data += iphlen;
214: if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
215: m, opts) == 0) {
216: udpstat.udps_fullsock++;
217: goto bad;
218: }
219: sorwakeup(inp->inp_socket);
220: return;
221: bad:
222: m_freem(m);
223: if (opts)
224: m_freem(opts);
225: }
226:
227: /*
228: * Create a "control" mbuf containing the specified data
229: * with the specified type for presentation with a datagram.
230: */
231: struct mbuf *
232: udp_saveopt(p, size, type)
233: caddr_t p;
234: register int size;
235: int type;
236: {
237: register struct cmsghdr *cp;
238: struct mbuf *m;
239:
240: if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
241: return ((struct mbuf *) NULL);
242: cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
243: bcopy(p, (caddr_t)(cp + 1), size);
244: size += sizeof(*cp);
245: m->m_len = size;
246: cp->cmsg_len = size;
247: cp->cmsg_level = IPPROTO_IP;
248: cp->cmsg_type = type;
249: return (m);
250: }
251:
252: /*
253: * Notify a udp user of an asynchronous error;
254: * just wake up so that he can collect error status.
255: */
256: udp_notify(inp, errno)
257: register struct inpcb *inp;
258: {
259:
260: inp->inp_socket->so_error = errno;
261: sorwakeup(inp->inp_socket);
262: sowwakeup(inp->inp_socket);
263: }
264:
265: udp_ctlinput(cmd, sa, ip)
266: int cmd;
267: struct sockaddr *sa;
268: register struct ip *ip;
269: {
270: register struct udphdr *uh;
271: extern struct in_addr zeroin_addr;
272: extern u_char inetctlerrmap[];
273:
274: if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
275: return;
276: if (ip) {
277: uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
278: in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
279: cmd, udp_notify);
280: } else
281: in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
282: }
283:
284: udp_output(inp, m, addr, control)
285: register struct inpcb *inp;
286: register struct mbuf *m;
287: struct mbuf *addr, *control;
288: {
289: register struct udpiphdr *ui;
290: register int len = m->m_pkthdr.len;
291: struct in_addr laddr;
292: int s, error = 0;
293:
294: if (control)
295: m_freem(control); /* XXX */
296:
297: if (addr) {
298: laddr = inp->inp_laddr;
299: if (inp->inp_faddr.s_addr != INADDR_ANY) {
300: error = EISCONN;
301: goto release;
302: }
303: /*
304: * Must block input while temporarily connected.
305: */
306: s = splnet();
307: error = in_pcbconnect(inp, addr);
308: if (error) {
309: splx(s);
310: goto release;
311: }
312: } else {
313: if (inp->inp_faddr.s_addr == INADDR_ANY) {
314: error = ENOTCONN;
315: goto release;
316: }
317: }
318: /*
319: * Calculate data length and get a mbuf
320: * for UDP and IP headers.
321: */
322: M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT);
323:
324: /*
325: * Fill in mbuf with extended UDP header
326: * and addresses and length put into network format.
327: */
328: ui = mtod(m, struct udpiphdr *);
329: ui->ui_next = ui->ui_prev = 0;
330: ui->ui_x1 = 0;
331: ui->ui_pr = IPPROTO_UDP;
332: ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
333: ui->ui_src = inp->inp_laddr;
334: ui->ui_dst = inp->inp_faddr;
335: ui->ui_sport = inp->inp_lport;
336: ui->ui_dport = inp->inp_fport;
337: ui->ui_ulen = ui->ui_len;
338:
339: /*
340: * Stuff checksum and output datagram.
341: */
342: ui->ui_sum = 0;
343: if (udpcksum) {
344: if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
345: ui->ui_sum = 0xffff;
346: }
347: ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
348: ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
349: ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
350: udpstat.udps_opackets++;
351: error = ip_output(m, inp->inp_options, &inp->inp_route,
352: inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST));
353:
354: if (addr) {
355: in_pcbdisconnect(inp);
356: inp->inp_laddr = laddr;
357: splx(s);
358: }
359: return (error);
360:
361: release:
362: m_freem(m);
363: return (error);
364: }
365:
366: u_long udp_sendspace = 9216; /* really max datagram size */
367: u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
368: /* 40 1K datagrams */
369:
370: /*ARGSUSED*/
371: udp_usrreq(so, req, m, addr, control)
372: struct socket *so;
373: int req;
374: struct mbuf *m, *addr, *control;
375: {
376: struct inpcb *inp = sotoinpcb(so);
377: int error = 0;
378: int s;
379:
380: if (req == PRU_CONTROL)
381: return (in_control(so, (int)m, (caddr_t)addr,
382: (struct ifnet *)control));
383: if (inp == NULL && req != PRU_ATTACH) {
384: error = EINVAL;
385: goto release;
386: }
387: /*
388: * Note: need to block udp_input while changing
389: * the udp pcb queue and/or pcb addresses.
390: */
391: switch (req) {
392:
393: case PRU_ATTACH:
394: if (inp != NULL) {
395: error = EINVAL;
396: break;
397: }
398: s = splnet();
399: error = in_pcballoc(so, &udb);
400: splx(s);
401: if (error)
402: break;
403: error = soreserve(so, udp_sendspace, udp_recvspace);
404: if (error)
405: break;
406: ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = udp_ttl;
407: break;
408:
409: case PRU_DETACH:
410: udp_detach(inp);
411: break;
412:
413: case PRU_BIND:
414: s = splnet();
415: error = in_pcbbind(inp, addr);
416: splx(s);
417: break;
418:
419: case PRU_LISTEN:
420: error = EOPNOTSUPP;
421: break;
422:
423: case PRU_CONNECT:
424: if (inp->inp_faddr.s_addr != INADDR_ANY) {
425: error = EISCONN;
426: break;
427: }
428: s = splnet();
429: error = in_pcbconnect(inp, addr);
430: splx(s);
431: if (error == 0)
432: soisconnected(so);
433: break;
434:
435: case PRU_CONNECT2:
436: error = EOPNOTSUPP;
437: break;
438:
439: case PRU_ACCEPT:
440: error = EOPNOTSUPP;
441: break;
442:
443: case PRU_DISCONNECT:
444: if (inp->inp_faddr.s_addr == INADDR_ANY) {
445: error = ENOTCONN;
446: break;
447: }
448: s = splnet();
449: in_pcbdisconnect(inp);
450: inp->inp_laddr.s_addr = INADDR_ANY;
451: splx(s);
452: so->so_state &= ~SS_ISCONNECTED; /* XXX */
453: break;
454:
455: case PRU_SHUTDOWN:
456: socantsendmore(so);
457: break;
458:
459: case PRU_SEND:
460: return (udp_output(inp, m, addr, control));
461:
462: case PRU_ABORT:
463: soisdisconnected(so);
464: udp_detach(inp);
465: break;
466:
467: case PRU_SOCKADDR:
468: in_setsockaddr(inp, addr);
469: break;
470:
471: case PRU_PEERADDR:
472: in_setpeeraddr(inp, addr);
473: break;
474:
475: case PRU_SENSE:
476: /*
477: * stat: don't bother with a blocksize.
478: */
479: return (0);
480:
481: case PRU_SENDOOB:
482: case PRU_FASTTIMO:
483: case PRU_SLOWTIMO:
484: case PRU_PROTORCV:
485: case PRU_PROTOSEND:
486: error = EOPNOTSUPP;
487: break;
488:
489: case PRU_RCVD:
490: case PRU_RCVOOB:
491: return (EOPNOTSUPP); /* do not free mbuf's */
492:
493: default:
494: panic("udp_usrreq");
495: }
496:
497: release:
498: if (control) {
499: printf("udp control data unexpectedly retained\n");
500: m_freem(control);
501: }
502: if (m)
503: m_freem(m);
504: return (error);
505: }
506:
507: udp_detach(inp)
508: struct inpcb *inp;
509: {
510: int s = splnet();
511:
512: if (inp == udp_last_inpcb)
513: udp_last_inpcb = &udb;
514: in_pcbdetach(inp);
515: splx(s);
516: }