|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that the above copyright notice and this paragraph are
7: * duplicated in all such forms and that any documentation,
8: * advertising materials, and other materials related to such
9: * distribution and use acknowledge that the software was developed
10: * by the University of California, Berkeley. The name of the
11: * University may not be used to endorse or promote products derived
12: * from this software without specific prior written permission.
13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16: *
17: * @(#)udp_usrreq.c 7.7 (Berkeley) 6/29/88
18: */
19:
20: #include "param.h"
21: #include "dir.h"
22: #include "user.h"
23: #include "mbuf.h"
24: #include "protosw.h"
25: #include "socket.h"
26: #include "socketvar.h"
27: #include "errno.h"
28: #include "stat.h"
29:
30: #include "../net/if.h"
31: #include "../net/route.h"
32:
33: #include "in.h"
34: #include "in_pcb.h"
35: #include "in_systm.h"
36: #include "ip.h"
37: #include "ip_var.h"
38: #include "ip_icmp.h"
39: #include "udp.h"
40: #include "udp_var.h"
41:
42: /*
43: * UDP protocol implementation.
44: * Per RFC 768, August, 1980.
45: */
46: udp_init()
47: {
48:
49: udb.inp_next = udb.inp_prev = &udb;
50: }
51:
52: #ifndef COMPAT_42
53: int udpcksum = 1;
54: #else
55: int udpcksum = 0; /* XXX */
56: #endif
57: int udp_ttl = UDP_TTL;
58:
59: struct sockaddr_in udp_in = { AF_INET };
60:
61: udp_input(m0, ifp)
62: struct mbuf *m0;
63: struct ifnet *ifp;
64: {
65: register struct udpiphdr *ui;
66: register struct inpcb *inp;
67: register struct mbuf *m;
68: int len;
69: struct ip ip;
70:
71: /*
72: * Get IP and UDP header together in first mbuf.
73: */
74: m = m0;
75: if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&
76: (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
77: udpstat.udps_hdrops++;
78: return;
79: }
80: ui = mtod(m, struct udpiphdr *);
81: if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))
82: ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
83:
84: /*
85: * Make mbuf data length reflect UDP length.
86: * If not enough data to reflect UDP length, drop.
87: */
88: len = ntohs((u_short)ui->ui_ulen);
89: if (((struct ip *)ui)->ip_len != len) {
90: if (len > ((struct ip *)ui)->ip_len) {
91: udpstat.udps_badlen++;
92: goto bad;
93: }
94: m_adj(m, len - ((struct ip *)ui)->ip_len);
95: /* ((struct ip *)ui)->ip_len = len; */
96: }
97: /*
98: * Save a copy of the IP header in case we want restore it for ICMP.
99: */
100: ip = *(struct ip*)ui;
101:
102: /*
103: * Checksum extended UDP header and data.
104: */
105: if (udpcksum && ui->ui_sum) {
106: ui->ui_next = ui->ui_prev = 0;
107: ui->ui_x1 = 0;
108: ui->ui_len = ui->ui_ulen;
109: if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) {
110: udpstat.udps_badsum++;
111: m_freem(m);
112: return;
113: }
114: }
115:
116: /*
117: * Locate pcb for datagram.
118: */
119: inp = in_pcblookup(&udb,
120: ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport,
121: INPLOOKUP_WILDCARD);
122: if (inp == 0) {
123: /* don't send ICMP response for broadcast packet */
124: if (in_broadcast(ui->ui_dst))
125: goto bad;
126: *(struct ip *)ui = ip;
127: icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT,
128: ifp);
129: return;
130: }
131:
132: /*
133: * Construct sockaddr format source address.
134: * Stuff source address and datagram in user buffer.
135: */
136: udp_in.sin_port = ui->ui_sport;
137: udp_in.sin_addr = ui->ui_src;
138: m->m_len -= sizeof (struct udpiphdr);
139: m->m_off += sizeof (struct udpiphdr);
140: if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
141: m, (struct mbuf *)0) == 0)
142: goto bad;
143: sorwakeup(inp->inp_socket);
144: return;
145: bad:
146: m_freem(m);
147: }
148:
149: /*
150: * Notify a udp user of an asynchronous error;
151: * just wake up so that he can collect error status.
152: */
153: udp_notify(inp)
154: register struct inpcb *inp;
155: {
156:
157: sorwakeup(inp->inp_socket);
158: sowwakeup(inp->inp_socket);
159: }
160:
161: udp_ctlinput(cmd, sa)
162: int cmd;
163: struct sockaddr *sa;
164: {
165: extern u_char inetctlerrmap[];
166: struct sockaddr_in *sin;
167: int in_rtchange();
168:
169: if ((unsigned)cmd > PRC_NCMDS)
170: return;
171: if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
172: return;
173: sin = (struct sockaddr_in *)sa;
174: if (sin->sin_addr.s_addr == INADDR_ANY)
175: return;
176:
177: switch (cmd) {
178:
179: case PRC_QUENCH:
180: break;
181:
182: case PRC_ROUTEDEAD:
183: case PRC_REDIRECT_NET:
184: case PRC_REDIRECT_HOST:
185: case PRC_REDIRECT_TOSNET:
186: case PRC_REDIRECT_TOSHOST:
187: in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange);
188: break;
189:
190: default:
191: if (inetctlerrmap[cmd] == 0)
192: return; /* XXX */
193: in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd],
194: udp_notify);
195: }
196: }
197:
198: udp_output(inp, m0)
199: register struct inpcb *inp;
200: struct mbuf *m0;
201: {
202: register struct mbuf *m;
203: register struct udpiphdr *ui;
204: register int len = 0;
205:
206: /*
207: * Calculate data length and get a mbuf
208: * for UDP and IP headers.
209: */
210: for (m = m0; m; m = m->m_next)
211: len += m->m_len;
212: MGET(m, M_DONTWAIT, MT_HEADER);
213: if (m == 0) {
214: m_freem(m0);
215: return (ENOBUFS);
216: }
217:
218: /*
219: * Fill in mbuf with extended UDP header
220: * and addresses and length put into network format.
221: */
222: m->m_off = MMAXOFF - sizeof (struct udpiphdr);
223: m->m_len = sizeof (struct udpiphdr);
224: m->m_next = m0;
225: ui = mtod(m, struct udpiphdr *);
226: ui->ui_next = ui->ui_prev = 0;
227: ui->ui_x1 = 0;
228: ui->ui_pr = IPPROTO_UDP;
229: ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
230: ui->ui_src = inp->inp_laddr;
231: ui->ui_dst = inp->inp_faddr;
232: ui->ui_sport = inp->inp_lport;
233: ui->ui_dport = inp->inp_fport;
234: ui->ui_ulen = ui->ui_len;
235:
236: /*
237: * Stuff checksum and output datagram.
238: */
239: ui->ui_sum = 0;
240: if (udpcksum) {
241: if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
242: ui->ui_sum = 0xffff;
243: }
244: ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
245: ((struct ip *)ui)->ip_ttl = udp_ttl;
246: return (ip_output(m, inp->inp_options, &inp->inp_route,
247: inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)));
248: }
249:
250: u_long udp_sendspace = 2048; /* really max datagram size */
251: u_long udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */
252:
253: /*ARGSUSED*/
254: udp_usrreq(so, req, m, nam, rights)
255: struct socket *so;
256: int req;
257: struct mbuf *m, *nam, *rights;
258: {
259: struct inpcb *inp = sotoinpcb(so);
260: int error = 0;
261:
262: if (req == PRU_CONTROL)
263: return (in_control(so, (int)m, (caddr_t)nam,
264: (struct ifnet *)rights));
265: if (rights && rights->m_len) {
266: error = EINVAL;
267: goto release;
268: }
269: if (inp == NULL && req != PRU_ATTACH) {
270: error = EINVAL;
271: goto release;
272: }
273: switch (req) {
274:
275: case PRU_ATTACH:
276: if (inp != NULL) {
277: error = EINVAL;
278: break;
279: }
280: error = in_pcballoc(so, &udb);
281: if (error)
282: break;
283: error = soreserve(so, udp_sendspace, udp_recvspace);
284: if (error)
285: break;
286: break;
287:
288: case PRU_DETACH:
289: in_pcbdetach(inp);
290: break;
291:
292: case PRU_BIND:
293: error = in_pcbbind(inp, nam);
294: break;
295:
296: case PRU_LISTEN:
297: error = EOPNOTSUPP;
298: break;
299:
300: case PRU_CONNECT:
301: if (inp->inp_faddr.s_addr != INADDR_ANY) {
302: error = EISCONN;
303: break;
304: }
305: error = in_pcbconnect(inp, nam);
306: if (error == 0)
307: soisconnected(so);
308: break;
309:
310: case PRU_CONNECT2:
311: error = EOPNOTSUPP;
312: break;
313:
314: case PRU_ACCEPT:
315: error = EOPNOTSUPP;
316: break;
317:
318: case PRU_DISCONNECT:
319: if (inp->inp_faddr.s_addr == INADDR_ANY) {
320: error = ENOTCONN;
321: break;
322: }
323: in_pcbdisconnect(inp);
324: so->so_state &= ~SS_ISCONNECTED; /* XXX */
325: break;
326:
327: case PRU_SHUTDOWN:
328: socantsendmore(so);
329: break;
330:
331: case PRU_SEND: {
332: struct in_addr laddr;
333: int s;
334:
335: if (nam) {
336: laddr = inp->inp_laddr;
337: if (inp->inp_faddr.s_addr != INADDR_ANY) {
338: error = EISCONN;
339: break;
340: }
341: /*
342: * Must block input while temporarily connected.
343: */
344: s = splnet();
345: error = in_pcbconnect(inp, nam);
346: if (error) {
347: splx(s);
348: break;
349: }
350: } else {
351: if (inp->inp_faddr.s_addr == INADDR_ANY) {
352: error = ENOTCONN;
353: break;
354: }
355: }
356: error = udp_output(inp, m);
357: m = NULL;
358: if (nam) {
359: in_pcbdisconnect(inp);
360: inp->inp_laddr = laddr;
361: splx(s);
362: }
363: }
364: break;
365:
366: case PRU_ABORT:
367: soisdisconnected(so);
368: in_pcbdetach(inp);
369: break;
370:
371: case PRU_SOCKADDR:
372: in_setsockaddr(inp, nam);
373: break;
374:
375: case PRU_PEERADDR:
376: in_setpeeraddr(inp, nam);
377: break;
378:
379: case PRU_SENSE:
380: /*
381: * stat: don't bother with a blocksize.
382: */
383: return (0);
384:
385: case PRU_SENDOOB:
386: case PRU_FASTTIMO:
387: case PRU_SLOWTIMO:
388: case PRU_PROTORCV:
389: case PRU_PROTOSEND:
390: error = EOPNOTSUPP;
391: break;
392:
393: case PRU_RCVD:
394: case PRU_RCVOOB:
395: return (EOPNOTSUPP); /* do not free mbuf's */
396:
397: default:
398: panic("udp_usrreq");
399: }
400: release:
401: if (m != NULL)
402: m_freem(m);
403: return (error);
404: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.