?? udp.c
字號:
1 /*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * The User Datagram Protocol (UDP).
7 *
8 * Version: @(#)udp.c 1.0.13 06/02/93
9 *
10 * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
11 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
12 *
13 * Fixes:
14 * Alan Cox : verify_area() calls
15 * Alan Cox : stopped close while in use off icmp
16 * messages. Not a fix but a botch that
17 * for udp at least is 'valid'.
18 * Alan Cox : Fixed icmp handling properly
19 * Alan Cox : Correct error for oversized datagrams
20 * Alan Cox : Tidied select() semantics.
21 * Alan Cox : udp_err() fixed properly, also now
22 * select and read wake correctly on errors
23 * Alan Cox : udp_send verify_area moved to avoid mem leak
24 * Alan Cox : UDP can count its memory
25 * Alan Cox : send to an uknown connection causes
26 * an ECONNREFUSED off the icmp, but
27 * does NOT close.
28 * Alan Cox : Switched to new sk_buff handlers. No more backlog!
29 * Alan Cox : Using generic datagram code. Even smaller and the PEEK
30 * bug no longer crashes it.
31 * Fred Van Kempen : Net2e support for sk->broadcast.
32 * Alan Cox : Uses skb_free_datagram
33 * Alan Cox : Added get/set sockopt support.
34 * Alan Cox : Broadcasting without option set returns EACCES.
35 * Alan Cox : No wakeup calls. Instead we now use the callbacks.
36 * Alan Cox : Use ip_tos and ip_ttl
37 *
38 *
39 * This program is free software; you can redistribute it and/or
40 * modify it under the terms of the GNU General Public License
41 * as published by the Free Software Foundation; either version
42 * 2 of the License, or (at your option) any later version.
43 */
44
45 #include <asm/system.h>
46 #include <asm/segment.h>
47 #include <linux/types.h>
48 #include <linux/sched.h>
49 #include <linux/fcntl.h>
50 #include <linux/socket.h>
51 #include <linux/sockios.h>
52 #include <linux/in.h>
53 #include <linux/errno.h>
54 #include <linux/timer.h>
55 #include <linux/termios.h>
56 #include <linux/mm.h>
57 #include "inet.h"
58 #include "dev.h"
59 #include "ip.h"
60 #include "protocol.h"
61 #include "tcp.h"
62 #include "skbuff.h"
63 #include "sock.h"
64 #include "udp.h"
65 #include "icmp.h"
66
67
68 #define min(a,b) ((a)<(b)?(a):(b))
69
70
71 static void
72 print_udp(struct udphdr *uh)
73 {
74 if (inet_debug != DBG_UDP) return;
75
76 if (uh == NULL) {
77 printk("(NULL)\n");
78 return;
79 }
80 printk("UDP: source = %d, dest = %d\n", ntohs(uh->source), ntohs(uh->dest));
81 printk(" len = %d, check = %d\n", ntohs(uh->len), ntohs(uh->check));
82 }
83
84
85 /*
86 * This routine is called by the ICMP module when it gets some
87 * sort of error condition. If err < 0 then the socket should
88 * be closed and the error returned to the user. If err > 0
89 * it's just the icmp type << 8 | icmp code.
90 * Header points to the ip header of the error packet. We move
91 * on past this. Then (as it used to claim before adjustment)
92 * header points to the first 8 bytes of the udp header. We need
93 * to find the appropriate port.
94 */
95 void
96 udp_err(int err, unsigned char *header, unsigned long daddr,
97 unsigned long saddr, struct inet_protocol *protocol)
98 {
99 struct udphdr *th;
100 struct sock *sk;
101 struct iphdr *ip=(struct iphdr *)header;
102
103 header += 4*ip->ihl;
104
105 th = (struct udphdr *)header;
106
107 DPRINTF((DBG_UDP,"UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n\
108 sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th->dest));
109
110 sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr);
111
112 if (sk == NULL)
113 return; /* No socket for error */
114
115 if (err < 0) /* As per the calling spec */
116 {
117 sk->err = -err;
118 sk->error_report(sk); /* User process wakes to see error */
119 return;
120 }
121
122 if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) { /* Slow down! */
123 if (sk->cong_window > 1)
124 sk->cong_window = sk->cong_window/2;
125 return;
126 }
127
128 sk->err = icmp_err_convert[err & 0xff].errno;
129
130 /* It's only fatal if we have connected to them. */
131 if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) {
132 sk->err=ECONNREFUSED;
133 }
134 sk->error_report(sk);
135 }
136
137
138 static unsigned short
139 udp_check(struct udphdr *uh, int len,
140 unsigned long saddr, unsigned long daddr)
141 {
142 unsigned long sum;
143
144 DPRINTF((DBG_UDP, "UDP: check(uh=%X, len = %d, saddr = %X, daddr = %X)\n",
145 uh, len, saddr, daddr));
146
147 print_udp(uh);
148
149 __asm__("\t addl %%ecx,%%ebx\n"
150 "\t adcl %%edx,%%ebx\n"
151 "\t adcl $0, %%ebx\n"
152 : "=b"(sum)
153 : ""(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256)
154 : "cx","bx","dx" );
155
156 if (len > 3) {
157 __asm__("\tclc\n"
158 "1:\n"
159 "\t lodsl\n"
160 "\t adcl %%eax, %%ebx\n"
161 "\t loop 1b\n"
162 "\t adcl $0, %%ebx\n"
163 : "=b"(sum) , "=S"(uh)
164 : ""(sum), "c"(len/4) ,"1"(uh)
165 : "ax", "cx", "bx", "si" );
166 }
167
168 /* Convert from 32 bits to 16 bits. */
169 __asm__("\t movl %%ebx, %%ecx\n"
170 "\t shrl $16,%%ecx\n"
171 "\t addw %%cx, %%bx\n"
172 "\t adcw $0, %%bx\n"
173 : "=b"(sum)
174 : ""(sum)
175 : "bx", "cx");
176
177 /* Check for an extra word. */
178 if ((len & 2) != 0) {
179 __asm__("\t lodsw\n"
180 "\t addw %%ax,%%bx\n"
181 "\t adcw $0, %%bx\n"
182 : "=b"(sum), "=S"(uh)
183 : ""(sum) ,"1"(uh)
184 : "si", "ax", "bx");
185 }
186
187 /* Now check for the extra byte. */
188 if ((len & 1) != 0) {
189 __asm__("\t lodsb\n"
190 "\t movb $0,%%ah\n"
191 "\t addw %%ax,%%bx\n"
192 "\t adcw $0, %%bx\n"
193 : "=b"(sum)
194 : ""(sum) ,"S"(uh)
195 : "si", "ax", "bx");
196 }
197
198 /* We only want the bottom 16 bits, but we never cleared the top 16. */
199 return((~sum) & 0xffff);
200 }
201
202
203 static void
204 udp_send_check(struct udphdr *uh, unsigned long saddr,
205 unsigned long daddr, int len, struct sock *sk)
206 {
207 uh->check = 0;
208 if (sk && sk->no_check)
209 return;
210 uh->check = udp_check(uh, len, saddr, daddr);
211 if (uh->check == 0) uh->check = 0xffff;
212 }
213
214
215 static int
216 udp_send(struct sock *sk, struct sockaddr_in *sin,
217 unsigned char *from, int len)
218 {
219 struct sk_buff *skb;
220 struct device *dev;
221 struct udphdr *uh;
222 unsigned char *buff;
223 unsigned long saddr;
224 int size, tmp;
225 int err;
226
227 DPRINTF((DBG_UDP, "UDP: send(dst=%s:%d buff=%X len=%d)\n",
228 in_ntoa(sin->sin_addr.s_addr), ntohs(sin->sin_port),
229 from, len));
230
231 err=verify_area(VERIFY_READ, from, len);
232 if(err)
233 return(err);
234
235 /* Allocate a copy of the packet. */
236 size = sizeof(struct sk_buff) + sk->prot->max_header + len;
237 skb = sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);
238 if (skb == NULL) return(-ENOMEM);
239
240 skb->mem_addr = skb;
241 skb->mem_len = size;
242 skb->sk = NULL; /* to avoid changing sk->saddr */
243 skb->free = 1;
244 skb->arp = 0;
245
246 /* Now build the IP and MAC header. */
247 buff = skb->data;
248 saddr = 0;
249 dev = NULL;
250 DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n",
251 saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len));
252 tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
253 &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
254 skb->sk=sk; /* So memory is freed correctly */
255
256 if (tmp < 0 ) {
257 sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
258 return(tmp);
259 }
260 buff += tmp;
261 saddr = dev->pa_addr;
262 DPRINTF((DBG_UDP, "UDP: >> MAC+IP len=%d\n", tmp));
263
264 skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */
265 skb->dev = dev;
266 #ifdef OLD
267 /*
268 * This code used to hack in some form of fragmentation.
269 * I removed that, since it didn't work anyway, and it made the
270 * code a bad thing to read and understand. -FvK
271 */
272 if (len > dev->mtu) {
273 #else
274 if (skb->len > 4095)
275 {
276 #endif
277 printk("UDP: send: length %d > mtu %d (ignored)\n", len, dev->mtu);
278 sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
279 return(-EMSGSIZE);
280 }
281
282 /* Fill in the UDP header. */
283 uh = (struct udphdr *) buff;
284 uh->len = htons(len + sizeof(struct udphdr));
285 uh->source = sk->dummy_th.source;
286 uh->dest = sin->sin_port;
287 buff = (unsigned char *) (uh + 1);
288
289 /* Copy the user data. */
290 memcpy_fromfs(buff, from, len);
291
292 /* Set up the UDP checksum. */
293 udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);
294
295 /* Send the datagram to the interface. */
296 sk->prot->queue_xmit(sk, dev, skb, 1);
297
298 return(len);
299 }
300
301
302 static int
303 udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
304 unsigned flags, struct sockaddr_in *usin, int addr_len)
305 {
306 struct sockaddr_in sin;
307 int tmp;
308 int err;
309
310 DPRINTF((DBG_UDP, "UDP: sendto(len=%d, flags=%X)\n", len, flags));
311
312 /* Check the flags. */
313 if (flags)
314 return(-EINVAL);
315 if (len < 0)
316 return(-EINVAL);
317 if (len == 0)
318 return(0);
319
320 /* Get and verify the address. */
321 if (usin) {
322 if (addr_len < sizeof(sin)) return(-EINVAL);
323 err=verify_area(VERIFY_READ, usin, sizeof(sin));
324 if(err)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -