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