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  *		RAW - implementation of IP "raw" sockets.
7  *
8  * Version:	$Id: raw.c,v 1.63.2.1 2002/03/05 12:47:34 davem Exp $
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() fixed up
15  *		Alan Cox	:	ICMP error handling
16  *		Alan Cox	:	EMSGSIZE if you send too big a packet
17  *		Alan Cox	: 	Now uses generic datagrams and shared
18  *					skbuff library. No more peek crashes,
19  *					no more backlogs
20  *		Alan Cox	:	Checks sk->broadcast.
21  *		Alan Cox	:	Uses skb_free_datagram/skb_copy_datagram
22  *		Alan Cox	:	Raw passes ip options too
23  *		Alan Cox	:	Setsocketopt added
24  *		Alan Cox	:	Fixed error return for broadcasts
25  *		Alan Cox	:	Removed wake_up calls
26  *		Alan Cox	:	Use ttl/tos
27  *		Alan Cox	:	Cleaned up old debugging
28  *		Alan Cox	:	Use new kernel side addresses
29  *	Arnt Gulbrandsen	:	Fixed MSG_DONTROUTE in raw sockets.
30  *		Alan Cox	:	BSD style RAW socket demultiplexing.
31  *		Alan Cox	:	Beginnings of mrouted support.
32  *		Alan Cox	:	Added IP_HDRINCL option.
33  *		Alan Cox	:	Skip broadcast check if BSDism set.
34  *		David S. Miller	:	New socket lookup architecture.
35  *
36  *		This program is free software; you can redistribute it and/or
37  *		modify it under the terms of the GNU General Public License
38  *		as published by the Free Software Foundation; either version
39  *		2 of the License, or (at your option) any later version.
40  */
41 
42 #include <linux/config.h>
43 #include <asm/system.h>
44 #include <asm/uaccess.h>
45 #include <asm/ioctls.h>
46 #include <linux/types.h>
47 #include <linux/sched.h>
48 #include <linux/errno.h>
49 #include <linux/timer.h>
50 #include <linux/mm.h>
51 #include <linux/kernel.h>
52 #include <linux/fcntl.h>
53 #include <linux/socket.h>
54 #include <linux/in.h>
55 #include <linux/inet.h>
56 #include <linux/netdevice.h>
57 #include <linux/mroute.h>
58 #include <net/ip.h>
59 #include <net/protocol.h>
60 #include <linux/skbuff.h>
61 #include <net/sock.h>
62 #include <net/icmp.h>
63 #include <net/udp.h>
64 #include <net/raw.h>
65 #include <net/inet_common.h>
66 #include <net/checksum.h>
67 
68 struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE];
69 rwlock_t raw_v4_lock = RW_LOCK_UNLOCKED;
70 
raw_v4_hash(struct sock * sk)71 static void raw_v4_hash(struct sock *sk)
72 {
73 	struct sock **skp = &raw_v4_htable[sk->num & (RAWV4_HTABLE_SIZE - 1)];
74 
75 	write_lock_bh(&raw_v4_lock);
76 	if ((sk->next = *skp) != NULL)
77 		(*skp)->pprev = &sk->next;
78 	*skp = sk;
79 	sk->pprev = skp;
80 	sock_prot_inc_use(sk->prot);
81  	sock_hold(sk);
82 	write_unlock_bh(&raw_v4_lock);
83 }
84 
raw_v4_unhash(struct sock * sk)85 static void raw_v4_unhash(struct sock *sk)
86 {
87  	write_lock_bh(&raw_v4_lock);
88 	if (sk->pprev) {
89 		if (sk->next)
90 			sk->next->pprev = sk->pprev;
91 		*sk->pprev = sk->next;
92 		sk->pprev = NULL;
93 		sock_prot_dec_use(sk->prot);
94 		__sock_put(sk);
95 	}
96 	write_unlock_bh(&raw_v4_lock);
97 }
98 
__raw_v4_lookup(struct sock * sk,unsigned short num,unsigned long raddr,unsigned long laddr,int dif)99 struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
100 			     unsigned long raddr, unsigned long laddr,
101 			     int dif)
102 {
103 	struct sock *s = sk;
104 
105 	for (s = sk; s; s = s->next) {
106 		if (s->num == num 				&&
107 		    !(s->daddr && s->daddr != raddr) 		&&
108 		    !(s->rcv_saddr && s->rcv_saddr != laddr)	&&
109 		    !(s->bound_dev_if && s->bound_dev_if != dif))
110 			break; /* gotcha */
111 	}
112 	return s;
113 }
114 
115 /*
116  *	0 - deliver
117  *	1 - block
118  */
icmp_filter(struct sock * sk,struct sk_buff * skb)119 static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
120 {
121 	int type;
122 
123 	type = skb->h.icmph->type;
124 	if (type < 32) {
125 		__u32 data = sk->tp_pinfo.tp_raw4.filter.data;
126 
127 		return ((1 << type) & data) != 0;
128 	}
129 
130 	/* Do not block unknown ICMP types */
131 	return 0;
132 }
133 
134 /* IP input processing comes here for RAW socket delivery.
135  * This is fun as to avoid copies we want to make no surplus
136  * copies.
137  *
138  * RFC 1122: SHOULD pass TOS value up to the transport layer.
139  * -> It does. And not only TOS, but all IP header.
140  */
raw_v4_input(struct sk_buff * skb,struct iphdr * iph,int hash)141 struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
142 {
143 	struct sock *sk;
144 
145 	read_lock(&raw_v4_lock);
146 	if ((sk = raw_v4_htable[hash]) == NULL)
147 		goto out;
148 	sk = __raw_v4_lookup(sk, iph->protocol,
149 			     iph->saddr, iph->daddr,
150 			     skb->dev->ifindex);
151 
152 	while (sk) {
153 		struct sock *sknext = __raw_v4_lookup(sk->next, iph->protocol,
154 						      iph->saddr, iph->daddr,
155 						      skb->dev->ifindex);
156 		if (iph->protocol != IPPROTO_ICMP ||
157 		    !icmp_filter(sk, skb)) {
158 			struct sk_buff *clone;
159 
160 			if (!sknext)
161 				break;
162 			clone = skb_clone(skb, GFP_ATOMIC);
163 			/* Not releasing hash table! */
164 			if (clone)
165 				raw_rcv(sk, clone);
166 		}
167 		sk = sknext;
168 	}
169 out:
170 	if (sk)
171 		sock_hold(sk);
172 	read_unlock(&raw_v4_lock);
173 
174 	return sk;
175 }
176 
raw_err(struct sock * sk,struct sk_buff * skb,u32 info)177 void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
178 {
179 	int type = skb->h.icmph->type;
180 	int code = skb->h.icmph->code;
181 	int err = 0;
182 	int harderr = 0;
183 
184 	/* Report error on raw socket, if:
185 	   1. User requested ip_recverr.
186 	   2. Socket is connected (otherwise the error indication
187 	      is useless without ip_recverr and error is hard.
188 	 */
189 	if (!sk->protinfo.af_inet.recverr && sk->state != TCP_ESTABLISHED)
190 		return;
191 
192 	switch (type) {
193 	default:
194 	case ICMP_TIME_EXCEEDED:
195 		err = EHOSTUNREACH;
196 		break;
197 	case ICMP_SOURCE_QUENCH:
198 		return;
199 	case ICMP_PARAMETERPROB:
200 		err = EPROTO;
201 		harderr = 1;
202 		break;
203 	case ICMP_DEST_UNREACH:
204 		err = EHOSTUNREACH;
205 		if (code > NR_ICMP_UNREACH)
206 			break;
207 		err = icmp_err_convert[code].errno;
208 		harderr = icmp_err_convert[code].fatal;
209 		if (code == ICMP_FRAG_NEEDED) {
210 			harderr = sk->protinfo.af_inet.pmtudisc !=
211 					IP_PMTUDISC_DONT;
212 			err = EMSGSIZE;
213 		}
214 	}
215 
216 	if (sk->protinfo.af_inet.recverr) {
217 		struct iphdr *iph = (struct iphdr*)skb->data;
218 		u8 *payload = skb->data + (iph->ihl << 2);
219 
220 		if (sk->protinfo.af_inet.hdrincl)
221 			payload = skb->data;
222 		ip_icmp_error(sk, skb, err, 0, info, payload);
223 	}
224 
225 	if (sk->protinfo.af_inet.recverr || harderr) {
226 		sk->err = err;
227 		sk->error_report(sk);
228 	}
229 }
230 
raw_rcv_skb(struct sock * sk,struct sk_buff * skb)231 static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
232 {
233 	/* Charge it to the socket. */
234 
235 	if (sock_queue_rcv_skb(sk, skb) < 0) {
236 		IP_INC_STATS(IpInDiscards);
237 		kfree_skb(skb);
238 		return NET_RX_DROP;
239 	}
240 
241 	IP_INC_STATS(IpInDelivers);
242 	return NET_RX_SUCCESS;
243 }
244 
raw_rcv(struct sock * sk,struct sk_buff * skb)245 int raw_rcv(struct sock *sk, struct sk_buff *skb)
246 {
247 	skb_push(skb, skb->data - skb->nh.raw);
248 
249 	raw_rcv_skb(sk, skb);
250 	return 0;
251 }
252 
253 struct rawfakehdr
254 {
255 	struct	iovec *iov;
256 	u32	saddr;
257 	struct	dst_entry *dst;
258 };
259 
260 /*
261  *	Send a RAW IP packet.
262  */
263 
264 /*
265  *	Callback support is trivial for SOCK_RAW
266  */
267 
raw_getfrag(const void * p,char * to,unsigned int offset,unsigned int fraglen,struct sk_buff * skb)268 static int raw_getfrag(const void *p, char *to, unsigned int offset,
269 		       unsigned int fraglen, struct sk_buff *skb)
270 {
271 	struct rawfakehdr *rfh = (struct rawfakehdr *) p;
272 	return memcpy_fromiovecend(to, rfh->iov, offset, fraglen);
273 }
274 
275 /*
276  *	IPPROTO_RAW needs extra work.
277  */
278 
raw_getrawfrag(const void * p,char * to,unsigned int offset,unsigned int fraglen,struct sk_buff * skb)279 static int raw_getrawfrag(const void *p, char *to, unsigned int offset,
280 				unsigned int fraglen, struct sk_buff *skb)
281 {
282 	struct rawfakehdr *rfh = (struct rawfakehdr *) p;
283 
284 	if (memcpy_fromiovecend(to, rfh->iov, offset, fraglen))
285 		return -EFAULT;
286 
287 	if (!offset) {
288 		struct iphdr *iph = (struct iphdr *)to;
289 		if (!iph->saddr)
290 			iph->saddr = rfh->saddr;
291 		iph->check   = 0;
292 		iph->tot_len = htons(fraglen); /* This is right as you can't
293 						  frag RAW packets */
294 		/*
295 	 	 *	Deliberate breach of modularity to keep
296 	 	 *	ip_build_xmit clean (well less messy).
297 		 */
298 		if (!iph->id)
299 			ip_select_ident(iph, rfh->dst, NULL);
300 		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
301 	}
302 	return 0;
303 }
304 
raw_sendmsg(struct sock * sk,struct msghdr * msg,int len)305 static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int len)
306 {
307 	struct ipcm_cookie ipc;
308 	struct rawfakehdr rfh;
309 	struct rtable *rt = NULL;
310 	int free = 0;
311 	u32 daddr;
312 	u8  tos;
313 	int err;
314 
315 	/* This check is ONLY to check for arithmetic overflow
316 	   on integer(!) len. Not more! Real check will be made
317 	   in ip_build_xmit --ANK
318 
319 	   BTW socket.c -> af_*.c -> ... make multiple
320 	   invalid conversions size_t -> int. We MUST repair it f.e.
321 	   by replacing all of them with size_t and revise all
322 	   the places sort of len += sizeof(struct iphdr)
323 	   If len was ULONG_MAX-10 it would be cathastrophe  --ANK
324 	 */
325 
326 	err = -EMSGSIZE;
327 	if (len < 0 || len > 0xFFFF)
328 		goto out;
329 
330 	/*
331 	 *	Check the flags.
332 	 */
333 
334 	err = -EOPNOTSUPP;
335 	if (msg->msg_flags & MSG_OOB)	/* Mirror BSD error message */
336 		goto out;               /* compatibility */
337 
338 	/*
339 	 *	Get and verify the address.
340 	 */
341 
342 	if (msg->msg_namelen) {
343 		struct sockaddr_in *usin = (struct sockaddr_in*)msg->msg_name;
344 		err = -EINVAL;
345 		if (msg->msg_namelen < sizeof(*usin))
346 			goto out;
347 		if (usin->sin_family != AF_INET) {
348 			static int complained;
349 			if (!complained++)
350 				printk(KERN_INFO "%s forgot to set AF_INET in "
351 						 "raw sendmsg. Fix it!\n",
352 						 current->comm);
353 			err = -EINVAL;
354 			if (usin->sin_family)
355 				goto out;
356 		}
357 		daddr = usin->sin_addr.s_addr;
358 		/* ANK: I did not forget to get protocol from port field.
359 		 * I just do not know, who uses this weirdness.
360 		 * IP_HDRINCL is much more convenient.
361 		 */
362 	} else {
363 		err = -EDESTADDRREQ;
364 		if (sk->state != TCP_ESTABLISHED)
365 			goto out;
366 		daddr = sk->daddr;
367 	}
368 
369 	ipc.addr = sk->saddr;
370 	ipc.opt = NULL;
371 	ipc.oif = sk->bound_dev_if;
372 
373 	if (msg->msg_controllen) {
374 		err = ip_cmsg_send(msg, &ipc);
375 		if (err)
376 			goto out;
377 		if (ipc.opt)
378 			free = 1;
379 	}
380 
381 	rfh.saddr = ipc.addr;
382 	ipc.addr = daddr;
383 
384 	if (!ipc.opt)
385 		ipc.opt = sk->protinfo.af_inet.opt;
386 
387 	if (ipc.opt) {
388 		err = -EINVAL;
389 		/* Linux does not mangle headers on raw sockets,
390 		 * so that IP options + IP_HDRINCL is non-sense.
391 		 */
392 		if (sk->protinfo.af_inet.hdrincl)
393 			goto done;
394 		if (ipc.opt->srr) {
395 			if (!daddr)
396 				goto done;
397 			daddr = ipc.opt->faddr;
398 		}
399 	}
400 	tos = RT_TOS(sk->protinfo.af_inet.tos) | sk->localroute;
401 	if (msg->msg_flags & MSG_DONTROUTE)
402 		tos |= RTO_ONLINK;
403 
404 	if (MULTICAST(daddr)) {
405 		if (!ipc.oif)
406 			ipc.oif = sk->protinfo.af_inet.mc_index;
407 		if (!rfh.saddr)
408 			rfh.saddr = sk->protinfo.af_inet.mc_addr;
409 	}
410 
411 	err = ip_route_output(&rt, daddr, rfh.saddr, tos, ipc.oif);
412 
413 	if (err)
414 		goto done;
415 
416 	err = -EACCES;
417 	if (rt->rt_flags & RTCF_BROADCAST && !sk->broadcast)
418 		goto done;
419 
420 	if (msg->msg_flags & MSG_CONFIRM)
421 		goto do_confirm;
422 back_from_confirm:
423 
424 	rfh.iov		= msg->msg_iov;
425 	rfh.saddr	= rt->rt_src;
426 	rfh.dst		= &rt->u.dst;
427 	if (!ipc.addr)
428 		ipc.addr = rt->rt_dst;
429 	err = ip_build_xmit(sk, sk->protinfo.af_inet.hdrincl ? raw_getrawfrag :
430 		       	    raw_getfrag, &rfh, len, &ipc, rt, msg->msg_flags);
431 
432 done:
433 	if (free)
434 		kfree(ipc.opt);
435 	ip_rt_put(rt);
436 
437 out:	return err < 0 ? err : len;
438 
439 do_confirm:
440 	dst_confirm(&rt->u.dst);
441 	if (!(msg->msg_flags & MSG_PROBE) || len)
442 		goto back_from_confirm;
443 	err = 0;
444 	goto done;
445 }
446 
raw_close(struct sock * sk,long timeout)447 static void raw_close(struct sock *sk, long timeout)
448 {
449         /*
450 	 * Raw sockets may have direct kernel refereneces. Kill them.
451 	 */
452 	ip_ra_control(sk, 0, NULL);
453 
454 	inet_sock_release(sk);
455 }
456 
457 /* This gets rid of all the nasties in af_inet. -DaveM */
raw_bind(struct sock * sk,struct sockaddr * uaddr,int addr_len)458 static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
459 {
460 	struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;
461 	int ret = -EINVAL;
462 	int chk_addr_ret;
463 
464 	if (sk->state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in))
465 		goto out;
466 	chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
467 	ret = -EADDRNOTAVAIL;
468 	if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL &&
469 	    chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)
470 		goto out;
471 	sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr;
472 	if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
473 		sk->saddr = 0;  /* Use device */
474 	sk_dst_reset(sk);
475 	ret = 0;
476 out:	return ret;
477 }
478 
479 /*
480  *	This should be easy, if there is something there
481  *	we return it, otherwise we block.
482  */
483 
raw_recvmsg(struct sock * sk,struct msghdr * msg,int len,int noblock,int flags,int * addr_len)484 int raw_recvmsg(struct sock *sk, struct msghdr *msg, int len,
485 		int noblock, int flags, int *addr_len)
486 {
487 	int copied = 0;
488 	int err = -EOPNOTSUPP;
489 	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
490 	struct sk_buff *skb;
491 
492 	if (flags & MSG_OOB)
493 		goto out;
494 
495 	if (addr_len)
496 		*addr_len = sizeof(*sin);
497 
498 	if (flags & MSG_ERRQUEUE) {
499 		err = ip_recv_error(sk, msg, len);
500 		goto out;
501 	}
502 
503 	skb = skb_recv_datagram(sk, flags, noblock, &err);
504 	if (!skb)
505 		goto out;
506 
507 	copied = skb->len;
508 	if (len < copied) {
509 		msg->msg_flags |= MSG_TRUNC;
510 		copied = len;
511 	}
512 
513 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
514 	if (err)
515 		goto done;
516 
517 	sock_recv_timestamp(msg, sk, skb);
518 
519 	/* Copy the address. */
520 	if (sin) {
521 		sin->sin_family = AF_INET;
522 		sin->sin_addr.s_addr = skb->nh.iph->saddr;
523 		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
524 	}
525 	if (sk->protinfo.af_inet.cmsg_flags)
526 		ip_cmsg_recv(msg, skb);
527 	if (flags & MSG_TRUNC)
528 		copied = skb->len;
529 done:
530 	skb_free_datagram(sk, skb);
531 out:	return err ? : copied;
532 }
533 
raw_init(struct sock * sk)534 static int raw_init(struct sock *sk)
535 {
536 	struct raw_opt *tp = &(sk->tp_pinfo.tp_raw4);
537 	if (sk->num == IPPROTO_ICMP)
538 		memset(&tp->filter, 0, sizeof(tp->filter));
539 	return 0;
540 }
541 
raw_seticmpfilter(struct sock * sk,char * optval,int optlen)542 static int raw_seticmpfilter(struct sock *sk, char *optval, int optlen)
543 {
544 	if (optlen > sizeof(struct icmp_filter))
545 		optlen = sizeof(struct icmp_filter);
546 	if (copy_from_user(&sk->tp_pinfo.tp_raw4.filter, optval, optlen))
547 		return -EFAULT;
548 	return 0;
549 }
550 
raw_geticmpfilter(struct sock * sk,char * optval,int * optlen)551 static int raw_geticmpfilter(struct sock *sk, char *optval, int *optlen)
552 {
553 	int len, ret = -EFAULT;
554 
555 	if (get_user(len, optlen))
556 		goto out;
557 	ret = -EINVAL;
558 	if (len < 0)
559 		goto out;
560 	if (len > sizeof(struct icmp_filter))
561 		len = sizeof(struct icmp_filter);
562 	ret = -EFAULT;
563 	if (put_user(len, optlen) ||
564 	    copy_to_user(optval, &sk->tp_pinfo.tp_raw4.filter, len))
565 		goto out;
566 	ret = 0;
567 out:	return ret;
568 }
569 
raw_setsockopt(struct sock * sk,int level,int optname,char * optval,int optlen)570 static int raw_setsockopt(struct sock *sk, int level, int optname,
571 			  char *optval, int optlen)
572 {
573 	if (level != SOL_RAW)
574 		return ip_setsockopt(sk, level, optname, optval, optlen);
575 
576 	if (optname == ICMP_FILTER) {
577 		if (sk->num != IPPROTO_ICMP)
578 			return -EOPNOTSUPP;
579 		else
580 			return raw_seticmpfilter(sk, optval, optlen);
581 	}
582 	return -ENOPROTOOPT;
583 }
584 
raw_getsockopt(struct sock * sk,int level,int optname,char * optval,int * optlen)585 static int raw_getsockopt(struct sock *sk, int level, int optname,
586 			  char *optval, int *optlen)
587 {
588 	if (level != SOL_RAW)
589 		return ip_getsockopt(sk, level, optname, optval, optlen);
590 
591 	if (optname == ICMP_FILTER) {
592 		if (sk->num != IPPROTO_ICMP)
593 			return -EOPNOTSUPP;
594 		else
595 			return raw_geticmpfilter(sk, optval, optlen);
596 	}
597 	return -ENOPROTOOPT;
598 }
599 
raw_ioctl(struct sock * sk,int cmd,unsigned long arg)600 static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
601 {
602 	switch (cmd) {
603 		case SIOCOUTQ: {
604 			int amount = atomic_read(&sk->wmem_alloc);
605 			return put_user(amount, (int *)arg);
606 		}
607 		case SIOCINQ: {
608 			struct sk_buff *skb;
609 			int amount = 0;
610 
611 			spin_lock_irq(&sk->receive_queue.lock);
612 			skb = skb_peek(&sk->receive_queue);
613 			if (skb != NULL)
614 				amount = skb->len;
615 			spin_unlock_irq(&sk->receive_queue.lock);
616 			return put_user(amount, (int *)arg);
617 		}
618 
619 		default:
620 #ifdef CONFIG_IP_MROUTE
621 			return ipmr_ioctl(sk, cmd, arg);
622 #else
623 			return -ENOIOCTLCMD;
624 #endif
625 	}
626 }
627 
get_raw_sock(struct sock * sp,char * tmpbuf,int i)628 static void get_raw_sock(struct sock *sp, char *tmpbuf, int i)
629 {
630 	unsigned int dest = sp->daddr,
631 		     src = sp->rcv_saddr;
632 	__u16 destp = 0,
633 	      srcp  = sp->num;
634 
635 	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
636 		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",
637 		i, src, srcp, dest, destp, sp->state,
638 		atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
639 		0, 0L, 0,
640 		sock_i_uid(sp), 0,
641 		sock_i_ino(sp),
642 		atomic_read(&sp->refcnt), sp);
643 }
644 
raw_get_info(char * buffer,char ** start,off_t offset,int length)645 int raw_get_info(char *buffer, char **start, off_t offset, int length)
646 {
647 	int len = 0, num = 0, i;
648 	off_t pos = 128;
649 	off_t begin;
650 	char tmpbuf[129];
651 
652 	if (offset < 128)
653 		len += sprintf(buffer, "%-127s\n",
654 			       "  sl  local_address rem_address   st tx_queue "
655 			       "rx_queue tr tm->when retrnsmt   uid  timeout "
656 			       "inode");
657 	read_lock(&raw_v4_lock);
658 	for (i = 0; i < RAWV4_HTABLE_SIZE; i++) {
659 		struct sock *sk;
660 
661 		for (sk = raw_v4_htable[i]; sk; sk = sk->next, num++) {
662 			if (sk->family != PF_INET)
663 				continue;
664 			pos += 128;
665 			if (pos <= offset)
666 				continue;
667 			get_raw_sock(sk, tmpbuf, i);
668 			len += sprintf(buffer + len, "%-127s\n", tmpbuf);
669 			if (len >= length)
670 				goto out;
671 		}
672 	}
673 out:
674 	read_unlock(&raw_v4_lock);
675 	begin = len - (pos - offset);
676 	*start = buffer + begin;
677 	len -= begin;
678 	if (len > length)
679 		len = length;
680 	if (len < 0)
681 		len = 0;
682 	return len;
683 }
684 
685 struct proto raw_prot = {
686 	name:		"RAW",
687 	close:		raw_close,
688 	connect:	udp_connect,
689 	disconnect:	udp_disconnect,
690 	ioctl:		raw_ioctl,
691 	init:		raw_init,
692 	setsockopt:	raw_setsockopt,
693 	getsockopt:	raw_getsockopt,
694 	sendmsg:	raw_sendmsg,
695 	recvmsg:	raw_recvmsg,
696 	bind:		raw_bind,
697 	backlog_rcv:	raw_rcv_skb,
698 	hash:		raw_v4_hash,
699 	unhash:		raw_v4_unhash,
700 };
701