xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 5051)
1 /*	udp_usrreq.c	4.9	81/11/23	*/
2 
3 #include "../h/param.h"
4 #include "../h/dir.h"
5 #include "../h/user.h"
6 #include "../h/mbuf.h"
7 #define	PRUREQUESTS
8 #include "../h/protosw.h"
9 #include "../h/socket.h"
10 #include "../h/socketvar.h"
11 #include "../net/inet.h"
12 #include "../net/inet_pcb.h"
13 #include "../net/inet_systm.h"
14 #include "../net/ip.h"
15 #include "../net/ip_var.h"
16 #include "../net/udp.h"
17 #include "../net/udp_var.h"
18 
19 /*
20  * UDP protocol implementation.
21  * Per RFC 768, August, 1980.
22  */
23 udp_init()
24 {
25 
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 	/*
41 	 * Get ip and udp header together in first mbuf.
42 	 */
43 	m = m0;
44 	if (m->m_len < sizeof (struct udpiphdr) &&
45 	    m_pullup(m, sizeof (struct udpiphdr)) == 0) {
46 		udpstat.udps_hdrops++;
47 		goto bad;
48 	}
49 	ui = mtod(m, struct udpiphdr *);
50 	if (ui->ui_len > sizeof (struct ip))
51 		ip_stripoptions((struct ip *)ui, (char *)0);
52 
53 	/*
54 	 * Make mbuf data length reflect udp length.
55 	 * If not enough data to reflect udp length, drop.
56 	 */
57 	ulen = ntohs((u_short)ui->ui_ulen);
58 	len = sizeof (struct udpiphdr) + ulen;
59 	if (((struct ip *)ui)->ip_len != len) {
60 		if (len > ((struct ip *)ui)->ip_len) {
61 			udpstat.udps_badlen++;
62 			goto bad;
63 		}
64 		m_adj(m, ((struct ip *)ui)->ip_len - len);
65 		/* (struct ip *)ui->ip_len = len; */
66 	}
67 
68 	/*
69 	 * Checksum extended udp header and data.
70 	 */
71 	if (udpcksum) {
72 		ui->ui_next = ui->ui_prev = 0;
73 		ui->ui_x1 = 0;
74 		ui->ui_len = htons((u_short)(sizeof (struct udpiphdr) + ulen));
75 		if ((ui->ui_sum = inet_cksum(m, len)) != 0xffff) {
76 			udpstat.udps_badsum++;
77 			printf("udp cksum %x\n", ui->ui_sum);
78 			m_freem(m);
79 			return;
80 		}
81 	}
82 
83 	/*
84 	 * Convert addresses and ports to host format.
85 	 * Locate pcb for datagram.
86 	 */
87 	inp = in_pcblookup(&udb,
88 	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport);
89 	if (inp == 0)
90 		goto bad;
91 
92 	/*
93 	 * Construct sockaddr format source address.
94 	 * Stuff source address and datagram in user buffer.
95 	 */
96 	udp_in.sin_port = ui->ui_sport;
97 	udp_in.sin_addr = ui->ui_src;
98 	m->m_len -= sizeof (struct udpiphdr);
99 	m->m_off += sizeof (struct udpiphdr);
100 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0)
101 		goto bad;
102 	sorwakeup(inp->inp_socket);
103 	return;
104 bad:
105 	m_freem(m);
106 }
107 
108 udp_ctlinput(m)
109 	struct mbuf *m;
110 {
111 
112 	printf("udp_ctlinput\n");
113 	m_freem(m);
114 }
115 
116 /*ARGSUSED*/
117 udp_output(inp, m0)
118 	struct inpcb *inp;
119 	struct mbuf *m0;
120 {
121 	register struct mbuf *m;
122 	register struct udpiphdr *ui;
123 	register int len = 0;
124 
125 	/*
126 	 * Calculate data length and get a mbuf
127 	 * for udp and ip headers.
128 	 */
129 	for (m = m0; m; m = m->m_next)
130 		len += m->m_len;
131 	m = m_get(0);
132 	if (m == 0)
133 		goto bad;
134 
135 	/*
136 	 * Fill in mbuf with extended udp header
137 	 * and addresses and length put into network format.
138 	 */
139 	m->m_off = MMAXOFF - sizeof (struct udpiphdr);
140 	m->m_len = sizeof (struct udpiphdr);
141 	m->m_next = m0;
142 	ui = mtod(m, struct udpiphdr *);
143 	ui->ui_next = ui->ui_prev = 0;
144 	ui->ui_x1 = 0;
145 	ui->ui_pr = IPPROTO_UDP;
146 	ui->ui_len = sizeof (struct udpiphdr) + len;
147 	ui->ui_src = inp->inp_laddr;
148 	ui->ui_dst = inp->inp_faddr;
149 	ui->ui_sport = inp->inp_lport;
150 	ui->ui_dport = inp->inp_fport;
151 	ui->ui_ulen = htons((u_short)len);
152 
153 	/*
154 	 * Stuff checksum and output datagram.
155 	 */
156 	ui->ui_sum = 0;
157 	ui->ui_sum = inet_cksum(m, sizeof (struct udpiphdr) + len);
158 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
159 	((struct ip *)ui)->ip_ttl = MAXTTL;
160 	ip_output(m);
161 	return;
162 bad:
163 	m_freem(m);
164 }
165 
166 /*ARGSUSED*/
167 udp_usrreq(so, req, m, addr)
168 	struct socket *so;
169 	int req;
170 	struct mbuf *m;
171 	caddr_t addr;
172 {
173 	struct inpcb *inp = sotoinpcb(so);
174 	int error;
175 
176 	if (inp == 0 && req != PRU_ATTACH)
177 		return (EINVAL);
178 	switch (req) {
179 
180 	case PRU_ATTACH:
181 		if (inp != 0)
182 			return (EINVAL);
183 		error = in_pcballoc(so, &udb, 2048, 2048, (struct sockaddr_in *)addr);
184 		if (error)
185 			return (error);
186 		break;
187 
188 	case PRU_DETACH:
189 		if (inp == 0)
190 			return (ENOTCONN);
191 		in_pcbfree(inp);
192 		break;
193 
194 	case PRU_CONNECT:
195 		if (inp->inp_faddr.s_addr)
196 			return (EISCONN);
197 		error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
198 		if (error)
199 			return (error);
200 		soisconnected(so);
201 		break;
202 
203 	case PRU_ACCEPT:
204 		return (EOPNOTSUPP);
205 
206 	case PRU_DISCONNECT:
207 		if (inp->inp_faddr.s_addr == 0)
208 			return (ENOTCONN);
209 		inp->inp_faddr.s_addr = 0;
210 		soisdisconnected(so);
211 		break;
212 
213 	case PRU_SHUTDOWN:
214 		socantsendmore(so);
215 		break;
216 
217 	case PRU_SEND:
218 		if (addr) {
219 			if (inp->inp_faddr.s_addr)
220 				return (EISCONN);
221 			error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
222 			if (error)
223 				return (error);
224 		} else {
225 			if (inp->inp_faddr.s_addr == 0)
226 				return (ENOTCONN);
227 		}
228 		udp_output(inp, m);
229 		if (addr)
230 			inp->inp_faddr.s_addr = 0;
231 		break;
232 
233 	case PRU_ABORT:
234 		in_pcbfree(inp);
235 		sofree(so);
236 		soisdisconnected(so);
237 		break;
238 
239 	case PRU_CONTROL:
240 		return (EOPNOTSUPP);
241 
242 	default:
243 		panic("udp_usrreq");
244 	}
245 	return (0);
246 }
247 
248 /*ARGSUSED*/
249 udp_sense(m)
250 	struct mbuf *m;
251 {
252 
253 	printf("udp_sense\n");
254 	return (EOPNOTSUPP);
255 }
256