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