xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 5220)
1 /*	udp_usrreq.c	4.15	81/12/09	*/
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  */
22 udp_init()
23 {
24 
25 COUNT(UDP_INIT);
26 	udb.inp_next = udb.inp_prev = &udb;
27 }
28 
29 int	udpcksum;
30 struct	sockaddr_in udp_in = { AF_INET };
31 
32 udp_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 
40 COUNT(UDP_INPUT);
41 	/*
42 	 * Get ip and udp header together in first mbuf.
43 	 */
44 	m = m0;
45 	if (m->m_len < sizeof (struct udpiphdr) &&
46 	    m_pullup(m, sizeof (struct udpiphdr)) == 0) {
47 		udpstat.udps_hdrops++;
48 		goto bad;
49 	}
50 	ui = mtod(m, struct udpiphdr *);
51 	if (ui->ui_len > sizeof (struct ip))
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 printf("len %d, ulen %d, ((struct ip *)ui)->ip_len %d\n",
61     len, ulen, ((struct ip *)ui)->ip_len);
62 	if (((struct ip *)ui)->ip_len != len) {
63 		if (len > ((struct ip *)ui)->ip_len) {
64 			udpstat.udps_badlen++;
65 			goto bad;
66 		}
67 		m_adj(m, ((struct ip *)ui)->ip_len - len);
68 		/* (struct ip *)ui->ip_len = len; */
69 	}
70 
71 	/*
72 	 * Checksum extended udp header and data.
73 	 */
74 	if (udpcksum) {
75 		ui->ui_next = ui->ui_prev = 0;
76 		ui->ui_x1 = 0;
77 		ui->ui_len = htons((u_short)(sizeof (struct udphdr) + ulen));
78 		if (ui->ui_sum = in_cksum(m, len)) {
79 			udpstat.udps_badsum++;
80 			printf("udp cksum %x\n", ui->ui_sum);
81 			m_freem(m);
82 			return;
83 		}
84 	}
85 
86 	/*
87 	 * Locate pcb for datagram.
88 	 */
89 	inp = in_pcblookup(&udb,
90 	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport);
91 	if (inp == 0)
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;
100 	m->m_len -= sizeof (struct udpiphdr);
101 	m->m_off += sizeof (struct udpiphdr);
102 printf("sbappendaddr called with m %x m->m_len %d m->m_off %d\n",
103 m, m->m_len, m->m_off);
104 printf("*mtod(m, char *) %x\n", *mtod(m, char *));
105 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0)
106 		goto bad;
107 	sorwakeup(inp->inp_socket);
108 	return;
109 bad:
110 	m_freem(m);
111 }
112 
113 udp_ctlinput(m)
114 	struct mbuf *m;
115 {
116 
117 COUNT(UDP_CTLINPUT);
118 	printf("udp_ctlinput\n");
119 	m_freem(m);
120 }
121 
122 /*ARGSUSED*/
123 udp_output(inp, m0)
124 	struct inpcb *inp;
125 	struct mbuf *m0;
126 {
127 	register struct mbuf *m;
128 	register struct udpiphdr *ui;
129 	register int len = 0;
130 
131 COUNT(UDP_OUTPUT);
132 	/*
133 	 * Calculate data length and get a mbuf
134 	 * for udp and ip headers.
135 	 */
136 	for (m = m0; m; m = m->m_next)
137 		len += m->m_len;
138 	m = m_get(0);
139 	if (m == 0)
140 		goto bad;
141 
142 	/*
143 	 * Fill in mbuf with extended udp header
144 	 * and addresses and length put into network format.
145 	 */
146 	m->m_off = MMAXOFF - sizeof (struct udpiphdr);
147 	m->m_len = sizeof (struct udpiphdr);
148 	m->m_next = m0;
149 	ui = mtod(m, struct udpiphdr *);
150 	ui->ui_next = ui->ui_prev = 0;
151 	ui->ui_x1 = 0;
152 	ui->ui_pr = IPPROTO_UDP;
153 	ui->ui_len = sizeof (struct udpiphdr) + len;
154 	ui->ui_src = inp->inp_laddr;
155 	ui->ui_dst = inp->inp_faddr;
156 	ui->ui_sport = inp->inp_lport;
157 	ui->ui_dport = inp->inp_fport;
158 	ui->ui_ulen = htons((u_short)len);
159 
160 	/*
161 	 * Stuff checksum and output datagram.
162 	 */
163 	ui->ui_sum = 0;
164 	ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len);
165 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
166 	((struct ip *)ui)->ip_ttl = MAXTTL;
167 	(void) ip_output(m, (struct mbuf *)0);
168 	return;
169 bad:
170 	m_freem(m);
171 }
172 
173 /*ARGSUSED*/
174 udp_usrreq(so, req, m, addr)
175 	struct socket *so;
176 	int req;
177 	struct mbuf *m;
178 	caddr_t addr;
179 {
180 	struct inpcb *inp = sotoinpcb(so);
181 	int error;
182 
183 COUNT(UDP_USRREQ);
184 	if (inp == 0 && req != PRU_ATTACH)
185 		return (EINVAL);
186 printf("udp_usrreq %d\n", req);
187 	switch (req) {
188 
189 	case PRU_ATTACH:
190 		if (inp != 0)
191 			return (EINVAL);
192 		error = in_pcbattach(so, &udb, 2048, 2048, (struct sockaddr_in *)addr);
193 		if (error)
194 			return (error);
195 		break;
196 
197 	case PRU_DETACH:
198 		if (inp == 0)
199 			return (ENOTCONN);
200 		in_pcbdetach(inp);
201 		break;
202 
203 	case PRU_CONNECT:
204 		if (inp->inp_faddr.s_addr)
205 			return (EISCONN);
206 		error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
207 		if (error)
208 			return (error);
209 		soisconnected(so);
210 		break;
211 
212 	case PRU_ACCEPT:
213 		return (EOPNOTSUPP);
214 
215 	case PRU_DISCONNECT:
216 		if (inp->inp_faddr.s_addr == 0)
217 			return (ENOTCONN);
218 		in_pcbdisconnect(inp);
219 		soisdisconnected(so);
220 		break;
221 
222 	case PRU_SHUTDOWN:
223 		socantsendmore(so);
224 		break;
225 
226 	case PRU_SEND:
227 		if (addr) {
228 			if (inp->inp_faddr.s_addr) {
229 				printf("EISCONN\n");
230 				return (EISCONN);
231 			}
232 			error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
233 			if (error) {
234 				printf("pcbconnect error %d\n", error);
235 				return (error);
236 			}
237 		} else {
238 			if (inp->inp_faddr.s_addr == 0)
239 				return (ENOTCONN);
240 		}
241 printf("to udp_output\n");
242 		udp_output(inp, m);
243 		if (addr)
244 			in_pcbdisconnect(inp);
245 		break;
246 
247 	case PRU_ABORT:
248 		in_pcbdetach(inp);
249 		sofree(so);
250 		soisdisconnected(so);
251 		break;
252 
253 	case PRU_CONTROL:
254 		return (EOPNOTSUPP);
255 
256 	default:
257 		panic("udp_usrreq");
258 	}
259 	return (0);
260 }
261