xref: /csrg-svn/sys/netinet/udp_usrreq.c (revision 5063)
1 /*	udp_usrreq.c	4.10	81/11/24	*/
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 	if (m->m_len < sizeof (struct udpiphdr) &&
44 	    m_pullup(m, sizeof (struct udpiphdr)) == 0) {
45 		udpstat.udps_hdrops++;
46 		goto bad;
47 	}
48 	ui = mtod(m, struct udpiphdr *);
49 	if (ui->ui_len > sizeof (struct ip))
50 		ip_stripoptions((struct ip *)ui, (char *)0);
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)) != 0xffff) {
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 	inp = in_pcblookup(&udb,
87 	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport);
88 	if (inp == 0)
89 		goto bad;
90 
91 	/*
92 	 * Construct sockaddr format source address.
93 	 * Stuff source address and datagram in user buffer.
94 	 */
95 	udp_in.sin_port = ui->ui_sport;
96 	udp_in.sin_addr = ui->ui_src;
97 	m->m_len -= sizeof (struct udpiphdr);
98 	m->m_off += sizeof (struct udpiphdr);
99 	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m) == 0)
100 		goto bad;
101 	sorwakeup(inp->inp_socket);
102 	return;
103 bad:
104 	m_freem(m);
105 }
106 
107 udp_ctlinput(m)
108 	struct mbuf *m;
109 {
110 
111 	printf("udp_ctlinput\n");
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 = sizeof (struct udpiphdr) + len;
146 	ui->ui_src = inp->inp_laddr;
147 	ui->ui_dst = inp->inp_faddr;
148 	ui->ui_sport = inp->inp_lport;
149 	ui->ui_dport = 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 	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
158 	((struct ip *)ui)->ip_ttl = MAXTTL;
159 	ip_output(m);
160 	return;
161 bad:
162 	m_freem(m);
163 }
164 
165 /*ARGSUSED*/
166 udp_usrreq(so, req, m, addr)
167 	struct socket *so;
168 	int req;
169 	struct mbuf *m;
170 	caddr_t addr;
171 {
172 	struct inpcb *inp = sotoinpcb(so);
173 	int error;
174 
175 	if (inp == 0 && req != PRU_ATTACH)
176 		return (EINVAL);
177 	switch (req) {
178 
179 	case PRU_ATTACH:
180 		if (inp != 0)
181 			return (EINVAL);
182 		error = in_pcballoc(so, &udb, 2048, 2048, (struct sockaddr_in *)addr);
183 		if (error)
184 			return (error);
185 		break;
186 
187 	case PRU_DETACH:
188 		if (inp == 0)
189 			return (ENOTCONN);
190 		in_pcbfree(inp);
191 		break;
192 
193 	case PRU_CONNECT:
194 		if (inp->inp_faddr.s_addr)
195 			return (EISCONN);
196 		error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
197 		if (error)
198 			return (error);
199 		soisconnected(so);
200 		break;
201 
202 	case PRU_ACCEPT:
203 		return (EOPNOTSUPP);
204 
205 	case PRU_DISCONNECT:
206 		if (inp->inp_faddr.s_addr == 0)
207 			return (ENOTCONN);
208 		inp->inp_faddr.s_addr = 0;
209 		soisdisconnected(so);
210 		break;
211 
212 	case PRU_SHUTDOWN:
213 		socantsendmore(so);
214 		break;
215 
216 	case PRU_SEND:
217 		if (addr) {
218 			if (inp->inp_faddr.s_addr)
219 				return (EISCONN);
220 			error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
221 			if (error)
222 				return (error);
223 		} else {
224 			if (inp->inp_faddr.s_addr == 0)
225 				return (ENOTCONN);
226 		}
227 		udp_output(inp, m);
228 		if (addr)
229 			inp->inp_faddr.s_addr = 0;
230 		break;
231 
232 	case PRU_ABORT:
233 		in_pcbfree(inp);
234 		sofree(so);
235 		soisdisconnected(so);
236 		break;
237 
238 	case PRU_CONTROL:
239 		return (EOPNOTSUPP);
240 
241 	default:
242 		panic("udp_usrreq");
243 	}
244 	return (0);
245 }
246 
247 /*ARGSUSED*/
248 udp_sense(m)
249 	struct mbuf *m;
250 {
251 
252 	printf("udp_sense\n");
253 	return (EOPNOTSUPP);
254 }
255