Main Page | Class List | File List | Class Members | File Members

raw.c

Go to the documentation of this file.
00001 /* 00002 * INET An implementation of the TCP/IP protocol suite for the LINUX 00003 * operating system. INET is implemented using the BSD Socket 00004 * interface as the means of communication with the user level. 00005 * 00006 * RAW - implementation of IP "raw" sockets. 00007 * 00008 * Version: $Id: raw.c,v 1.63.2.1 2002/03/05 12:47:34 davem Exp $ 00009 * 00010 * Authors: Ross Biro, <bir7@leland.Stanford.Edu> 00011 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> 00012 * 00013 * Fixes: 00014 * Alan Cox : verify_area() fixed up 00015 * Alan Cox : ICMP error handling 00016 * Alan Cox : EMSGSIZE if you send too big a packet 00017 * Alan Cox : Now uses generic datagrams and shared 00018 * skbuff library. No more peek crashes, 00019 * no more backlogs 00020 * Alan Cox : Checks sk->broadcast. 00021 * Alan Cox : Uses skb_free_datagram/skb_copy_datagram 00022 * Alan Cox : Raw passes ip options too 00023 * Alan Cox : Setsocketopt added 00024 * Alan Cox : Fixed error return for broadcasts 00025 * Alan Cox : Removed wake_up calls 00026 * Alan Cox : Use ttl/tos 00027 * Alan Cox : Cleaned up old debugging 00028 * Alan Cox : Use new kernel side addresses 00029 * Arnt Gulbrandsen : Fixed MSG_DONTROUTE in raw sockets. 00030 * Alan Cox : BSD style RAW socket demultiplexing. 00031 * Alan Cox : Beginnings of mrouted support. 00032 * Alan Cox : Added IP_HDRINCL option. 00033 * Alan Cox : Skip broadcast check if BSDism set. 00034 * David S. Miller : New socket lookup architecture. 00035 * 00036 * This program is free software; you can redistribute it and/or 00037 * modify it under the terms of the GNU General Public License 00038 * as published by the Free Software Foundation; either version 00039 * 2 of the License, or (at your option) any later version. 00040 */ 00041 00042 #include <linux/config.h> 00043 #include <asm/system.h> 00044 #include <asm/uaccess.h> 00045 #include <asm/ioctls.h> 00046 #include <linux/types.h> 00047 #include <linux/sched.h> 00048 #include <linux/errno.h> 00049 #include <linux/timer.h> 00050 #include <linux/mm.h> 00051 #include <linux/kernel.h> 00052 #include <linux/fcntl.h> 00053 #include <linux/socket.h> 00054 #include <linux/in.h> 00055 #include <linux/inet.h> 00056 #include <linux/netdevice.h> 00057 #include <linux/mroute.h> 00058 #include <net/ip.h> 00059 #include <net/protocol.h> 00060 #include <linux/skbuff.h> 00061 #include <net/sock.h> 00062 #include <net/icmp.h> 00063 #include <net/udp.h> 00064 #include <net/raw.h> 00065 #include <net/inet_common.h> 00066 #include <net/checksum.h> 00067 00068 struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE]; 00069 rwlock_t raw_v4_lock = RW_LOCK_UNLOCKED; 00070 00071 static void raw_v4_hash(struct sock *sk) 00072 { 00073 struct sock **skp = &raw_v4_htable[sk->num & (RAWV4_HTABLE_SIZE - 1)]; 00074 00075 write_lock_bh(&raw_v4_lock); 00076 if ((sk->next = *skp) != NULL) 00077 (*skp)->pprev = &sk->next; 00078 *skp = sk; 00079 sk->pprev = skp; 00080 sock_prot_inc_use(sk->prot); 00081 sock_hold(sk); 00082 write_unlock_bh(&raw_v4_lock); 00083 } 00084 00085 static void raw_v4_unhash(struct sock *sk) 00086 { 00087 write_lock_bh(&raw_v4_lock); 00088 if (sk->pprev) { 00089 if (sk->next) 00090 sk->next->pprev = sk->pprev; 00091 *sk->pprev = sk->next; 00092 sk->pprev = NULL; 00093 sock_prot_dec_use(sk->prot); 00094 __sock_put(sk); 00095 } 00096 write_unlock_bh(&raw_v4_lock); 00097 } 00098 00099 struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, 00100 unsigned long raddr, unsigned long laddr, 00101 int dif) 00102 { 00103 struct sock *s = sk; 00104 00105 for (s = sk; s; s = s->next) { 00106 if (s->num == num && 00107 !(s->daddr && s->daddr != raddr) && 00108 !(s->rcv_saddr && s->rcv_saddr != laddr) && 00109 !(s->bound_dev_if && s->bound_dev_if != dif)) 00110 break; /* gotcha */ 00111 } 00112 return s; 00113 } 00114 00115 /* 00116 * 0 - deliver 00117 * 1 - block 00118 */ 00119 static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb) 00120 { 00121 int type; 00122 00123 type = skb->h.icmph->type; 00124 if (type < 32) { 00125 __u32 data = sk->tp_pinfo.tp_raw4.filter.data; 00126 00127 return ((1 << type) & data) != 0; 00128 } 00129 00130 /* Do not block unknown ICMP types */ 00131 return 0; 00132 } 00133 00134 /* IP input processing comes here for RAW socket delivery. 00135 * This is fun as to avoid copies we want to make no surplus 00136 * copies. 00137 * 00138 * RFC 1122: SHOULD pass TOS value up to the transport layer. 00139 * -> It does. And not only TOS, but all IP header. 00140 */ 00141 struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) 00142 { 00143 struct sock *sk; 00144 00145 read_lock(&raw_v4_lock); 00146 if ((sk = raw_v4_htable[hash]) == NULL) 00147 goto out; 00148 sk = __raw_v4_lookup(sk, iph->protocol, 00149 iph->saddr, iph->daddr, 00150 skb->dev->ifindex); 00151 00152 while (sk) { 00153 struct sock *sknext = __raw_v4_lookup(sk->next, iph->protocol, 00154 iph->saddr, iph->daddr, 00155 skb->dev->ifindex); 00156 if (iph->protocol != IPPROTO_ICMP || 00157 !icmp_filter(sk, skb)) { 00158 struct sk_buff *clone; 00159 00160 if (!sknext) 00161 break; 00162 clone = skb_clone(skb, GFP_ATOMIC); 00163 /* Not releasing hash table! */ 00164 if (clone) 00165 raw_rcv(sk, clone); 00166 } 00167 sk = sknext; 00168 } 00169 out: 00170 if (sk) 00171 sock_hold(sk); 00172 read_unlock(&raw_v4_lock); 00173 00174 return sk; 00175 } 00176 00177 void raw_err (struct sock *sk, struct sk_buff *skb, u32 info) 00178 { 00179 int type = skb->h.icmph->type; 00180 int code = skb->h.icmph->code; 00181 int err = 0; 00182 int harderr = 0; 00183 00184 /* Report error on raw socket, if: 00185 1. User requested ip_recverr. 00186 2. Socket is connected (otherwise the error indication 00187 is useless without ip_recverr and error is hard. 00188 */ 00189 if (!sk->protinfo.af_inet.recverr && sk->state != TCP_ESTABLISHED) 00190 return; 00191 00192 switch (type) { 00193 default: 00194 case ICMP_TIME_EXCEEDED: 00195 err = EHOSTUNREACH; 00196 break; 00197 case ICMP_SOURCE_QUENCH: 00198 return; 00199 case ICMP_PARAMETERPROB: 00200 err = EPROTO; 00201 harderr = 1; 00202 break; 00203 case ICMP_DEST_UNREACH: 00204 err = EHOSTUNREACH; 00205 if (code > NR_ICMP_UNREACH) 00206 break; 00207 err = icmp_err_convert[code].errno; 00208 harderr = icmp_err_convert[code].fatal; 00209 if (code == ICMP_FRAG_NEEDED) { 00210 harderr = sk->protinfo.af_inet.pmtudisc != 00211 IP_PMTUDISC_DONT; 00212 err = EMSGSIZE; 00213 } 00214 } 00215 00216 if (sk->protinfo.af_inet.recverr) { 00217 struct iphdr *iph = (struct iphdr*)skb->data; 00218 u8 *payload = skb->data + (iph->ihl << 2); 00219 00220 if (sk->protinfo.af_inet.hdrincl) 00221 payload = skb->data; 00222 ip_icmp_error(sk, skb, err, 0, info, payload); 00223 } 00224 00225 if (sk->protinfo.af_inet.recverr || harderr) { 00226 sk->err = err; 00227 sk->error_report(sk); 00228 } 00229 } 00230 00231 static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb) 00232 { 00233 /* Charge it to the socket. */ 00234 00235 if (sock_queue_rcv_skb(sk, skb) < 0) { 00236 IP_INC_STATS(IpInDiscards); 00237 kfree_skb(skb); 00238 return NET_RX_DROP; 00239 } 00240 00241 IP_INC_STATS(IpInDelivers); 00242 return NET_RX_SUCCESS; 00243 } 00244 00245 int raw_rcv(struct sock *sk, struct sk_buff *skb) 00246 { 00247 skb_push(skb, skb->data - skb->nh.raw); 00248 00249 raw_rcv_skb(sk, skb); 00250 return 0; 00251 } 00252 00253 struct rawfakehdr 00254 { 00255 struct iovec *iov; 00256 u32 saddr; 00257 struct dst_entry *dst; 00258 }; 00259 00260 /* 00261 * Send a RAW IP packet. 00262 */ 00263 00264 /* 00265 * Callback support is trivial for SOCK_RAW 00266 */ 00267 00268 static int raw_getfrag(const void *p, char *to, unsigned int offset, 00269 unsigned int fraglen) 00270 { 00271 struct rawfakehdr *rfh = (struct rawfakehdr *) p; 00272 return memcpy_fromiovecend(to, rfh->iov, offset, fraglen); 00273 } 00274 00275 /* 00276 * IPPROTO_RAW needs extra work. 00277 */ 00278 00279 static int raw_getrawfrag(const void *p, char *to, unsigned int offset, 00280 unsigned int fraglen) 00281 { 00282 struct rawfakehdr *rfh = (struct rawfakehdr *) p; 00283 00284 if (memcpy_fromiovecend(to, rfh->iov, offset, fraglen)) 00285 return -EFAULT; 00286 00287 if (!offset) { 00288 struct iphdr *iph = (struct iphdr *)to; 00289 if (!iph->saddr) 00290 iph->saddr = rfh->saddr; 00291 iph->check = 0; 00292 iph->tot_len = htons(fraglen); /* This is right as you can't 00293 frag RAW packets */ 00294 /* 00295 * Deliberate breach of modularity to keep 00296 * ip_build_xmit clean (well less messy). 00297 */ 00298 if (!iph->id) 00299 ip_select_ident(iph, rfh->dst, NULL); 00300 iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); 00301 } 00302 return 0; 00303 } 00304 00305 static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int len) 00306 { 00307 struct ipcm_cookie ipc; 00308 struct rawfakehdr rfh; 00309 struct rtable *rt = NULL; 00310 int free = 0; 00311 u32 daddr; 00312 u8 tos; 00313 int err; 00314 00315 /* This check is ONLY to check for arithmetic overflow 00316 on integer(!) len. Not more! Real check will be made 00317 in ip_build_xmit --ANK 00318 00319 BTW socket.c -> af_*.c -> ... make multiple 00320 invalid conversions size_t -> int. We MUST repair it f.e. 00321 by replacing all of them with size_t and revise all 00322 the places sort of len += sizeof(struct iphdr) 00323 If len was ULONG_MAX-10 it would be cathastrophe --ANK 00324 */ 00325 00326 err = -EMSGSIZE; 00327 if (len < 0 || len > 0xFFFF) 00328 goto out; 00329 00330 /* 00331 * Check the flags. 00332 */ 00333 00334 err = -EOPNOTSUPP; 00335 if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message */ 00336 goto out; /* compatibility */ 00337 00338 /* 00339 * Get and verify the address. 00340 */ 00341 00342 if (msg->msg_namelen) { 00343 struct sockaddr_in *usin = (struct sockaddr_in*)msg->msg_name; 00344 err = -EINVAL; 00345 if (msg->msg_namelen < sizeof(*usin)) 00346 goto out; 00347 if (usin->sin_family != AF_INET) { 00348 static int complained; 00349 if (!complained++) 00350 printk(KERN_INFO "%s forgot to set AF_INET in " 00351 "raw sendmsg. Fix it!\n", 00352 current->comm); 00353 err = -EINVAL; 00354 if (usin->sin_family) 00355 goto out; 00356 } 00357 daddr = usin->sin_addr.s_addr; 00358 /* ANK: I did not forget to get protocol from port field. 00359 * I just do not know, who uses this weirdness. 00360 * IP_HDRINCL is much more convenient. 00361 */ 00362 } else { 00363 err = -EDESTADDRREQ; 00364 if (sk->state != TCP_ESTABLISHED) 00365 goto out; 00366 daddr = sk->daddr; 00367 } 00368 00369 ipc.addr = sk->saddr; 00370 ipc.opt = NULL; 00371 ipc.oif = sk->bound_dev_if; 00372 00373 if (msg->msg_controllen) { 00374 err = ip_cmsg_send(msg, &ipc); 00375 if (err) 00376 goto out; 00377 if (ipc.opt) 00378 free = 1; 00379 } 00380 00381 rfh.saddr = ipc.addr; 00382 ipc.addr = daddr; 00383 00384 if (!ipc.opt) 00385 ipc.opt = sk->protinfo.af_inet.opt; 00386 00387 if (ipc.opt) { 00388 err = -EINVAL; 00389 /* Linux does not mangle headers on raw sockets, 00390 * so that IP options + IP_HDRINCL is non-sense. 00391 */ 00392 if (sk->protinfo.af_inet.hdrincl) 00393 goto done; 00394 if (ipc.opt->srr) { 00395 if (!daddr) 00396 goto done; 00397 daddr = ipc.opt->faddr; 00398 } 00399 } 00400 tos = RT_TOS(sk->protinfo.af_inet.tos) | sk->localroute; 00401 if (msg->msg_flags & MSG_DONTROUTE) 00402 tos |= RTO_ONLINK; 00403 00404 if (MULTICAST(daddr)) { 00405 if (!ipc.oif) 00406 ipc.oif = sk->protinfo.af_inet.mc_index; 00407 if (!rfh.saddr) 00408 rfh.saddr = sk->protinfo.af_inet.mc_addr; 00409 } 00410 00411 err = ip_route_output(&rt, daddr, rfh.saddr, tos, ipc.oif); 00412 00413 if (err) 00414 goto done; 00415 00416 err = -EACCES; 00417 if (rt->rt_flags & RTCF_BROADCAST && !sk->broadcast) 00418 goto done; 00419 00420 if (msg->msg_flags & MSG_CONFIRM) 00421 goto do_confirm; 00422 back_from_confirm: 00423 00424 rfh.iov = msg->msg_iov; 00425 rfh.saddr = rt->rt_src; 00426 rfh.dst = &rt->u.dst; 00427 if (!ipc.addr) 00428 ipc.addr = rt->rt_dst; 00429 err = ip_build_xmit(sk, sk->protinfo.af_inet.hdrincl ? raw_getrawfrag : 00430 raw_getfrag, &rfh, len, &ipc, rt, msg->msg_flags); 00431 00432 done: 00433 if (free) 00434 kfree(ipc.opt); 00435 ip_rt_put(rt); 00436 00437 out: return err < 0 ? err : len; 00438 00439 do_confirm: 00440 dst_confirm(&rt->u.dst); 00441 if (!(msg->msg_flags & MSG_PROBE) || len) 00442 goto back_from_confirm; 00443 err = 0; 00444 goto done; 00445 } 00446 00447 static void raw_close(struct sock *sk, long timeout) 00448 { 00449 /* 00450 * Raw sockets may have direct kernel refereneces. Kill them. 00451 */ 00452 ip_ra_control(sk, 0, NULL); 00453 00454 inet_sock_release(sk); 00455 } 00456 00457 /* This gets rid of all the nasties in af_inet. -DaveM */ 00458 static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) 00459 { 00460 struct sockaddr_in *addr = (struct sockaddr_in *) uaddr; 00461 int ret = -EINVAL; 00462 int chk_addr_ret; 00463 00464 if (sk->state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in)) 00465 goto out; 00466 chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); 00467 ret = -EADDRNOTAVAIL; 00468 if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL && 00469 chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) 00470 goto out; 00471 sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr; 00472 if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) 00473 sk->saddr = 0; /* Use device */ 00474 sk_dst_reset(sk); 00475 ret = 0; 00476 out: return ret; 00477 } 00478 00479 /* 00480 * This should be easy, if there is something there 00481 * we return it, otherwise we block. 00482 */ 00483 00484 int raw_recvmsg(struct sock *sk, struct msghdr *msg, int len, 00485 int noblock, int flags, int *addr_len) 00486 { 00487 int copied = 0; 00488 int err = -EOPNOTSUPP; 00489 struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; 00490 struct sk_buff *skb; 00491 00492 if (flags & MSG_OOB) 00493 goto out; 00494 00495 if (addr_len) 00496 *addr_len = sizeof(*sin); 00497 00498 if (flags & MSG_ERRQUEUE) { 00499 err = ip_recv_error(sk, msg, len); 00500 goto out; 00501 } 00502 00503 skb = skb_recv_datagram(sk, flags, noblock, &err); 00504 if (!skb) 00505 goto out; 00506 00507 copied = skb->len; 00508 if (len < copied) { 00509 msg->msg_flags |= MSG_TRUNC; 00510 copied = len; 00511 } 00512 00513 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); 00514 if (err) 00515 goto done; 00516 00517 sock_recv_timestamp(msg, sk, skb); 00518 00519 /* Copy the address. */ 00520 if (sin) { 00521 sin->sin_family = AF_INET; 00522 sin->sin_addr.s_addr = skb->nh.iph->saddr; 00523 memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); 00524 } 00525 if (sk->protinfo.af_inet.cmsg_flags) 00526 ip_cmsg_recv(msg, skb); 00527 done: 00528 skb_free_datagram(sk, skb); 00529 out: return err ? : copied; 00530 } 00531 00532 static int raw_init(struct sock *sk) 00533 { 00534 struct raw_opt *tp = &(sk->tp_pinfo.tp_raw4); 00535 if (sk->num == IPPROTO_ICMP) 00536 memset(&tp->filter, 0, sizeof(tp->filter)); 00537 return 0; 00538 } 00539 00540 static int raw_seticmpfilter(struct sock *sk, char *optval, int optlen) 00541 { 00542 if (optlen > sizeof(struct icmp_filter)) 00543 optlen = sizeof(struct icmp_filter); 00544 if (copy_from_user(&sk->tp_pinfo.tp_raw4.filter, optval, optlen)) 00545 return -EFAULT; 00546 return 0; 00547 } 00548 00549 static int raw_geticmpfilter(struct sock *sk, char *optval, int *optlen) 00550 { 00551 int len, ret = -EFAULT; 00552 00553 if (get_user(len, optlen)) 00554 goto out; 00555 ret = -EINVAL; 00556 if (len < 0) 00557 goto out; 00558 if (len > sizeof(struct icmp_filter)) 00559 len = sizeof(struct icmp_filter); 00560 ret = -EFAULT; 00561 if (put_user(len, optlen) || 00562 copy_to_user(optval, &sk->tp_pinfo.tp_raw4.filter, len)) 00563 goto out; 00564 ret = 0; 00565 out: return ret; 00566 } 00567 00568 static int raw_setsockopt(struct sock *sk, int level, int optname, 00569 char *optval, int optlen) 00570 { 00571 if (level != SOL_RAW) 00572 return ip_setsockopt(sk, level, optname, optval, optlen); 00573 00574 if (optname == ICMP_FILTER) { 00575 if (sk->num != IPPROTO_ICMP) 00576 return -EOPNOTSUPP; 00577 else 00578 return raw_seticmpfilter(sk, optval, optlen); 00579 } 00580 return -ENOPROTOOPT; 00581 } 00582 00583 static int raw_getsockopt(struct sock *sk, int level, int optname, 00584 char *optval, int *optlen) 00585 { 00586 if (level != SOL_RAW) 00587 return ip_getsockopt(sk, level, optname, optval, optlen); 00588 00589 if (optname == ICMP_FILTER) { 00590 if (sk->num != IPPROTO_ICMP) 00591 return -EOPNOTSUPP; 00592 else 00593 return raw_geticmpfilter(sk, optval, optlen); 00594 } 00595 return -ENOPROTOOPT; 00596 } 00597 00598 static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) 00599 { 00600 switch (cmd) { 00601 case SIOCOUTQ: { 00602 int amount = atomic_read(&sk->wmem_alloc); 00603 return put_user(amount, (int *)arg); 00604 } 00605 case SIOCINQ: { 00606 struct sk_buff *skb; 00607 int amount = 0; 00608 00609 spin_lock_irq(&sk->receive_queue.lock); 00610 skb = skb_peek(&sk->receive_queue); 00611 if (skb != NULL) 00612 amount = skb->len; 00613 spin_unlock_irq(&sk->receive_queue.lock); 00614 return put_user(amount, (int *)arg); 00615 } 00616 00617 default: 00618 #ifdef CONFIG_IP_MROUTE 00619 return ipmr_ioctl(sk, cmd, arg); 00620 #else 00621 return -ENOIOCTLCMD; 00622 #endif 00623 } 00624 } 00625 00626 static void get_raw_sock(struct sock *sp, char *tmpbuf, int i) 00627 { 00628 unsigned int dest = sp->daddr, 00629 src = sp->rcv_saddr; 00630 __u16 destp = 0, 00631 srcp = sp->num; 00632 00633 sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" 00634 " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p", 00635 i, src, srcp, dest, destp, sp->state, 00636 atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), 00637 0, 0L, 0, 00638 sock_i_uid(sp), 0, 00639 sock_i_ino(sp), 00640 atomic_read(&sp->refcnt), sp); 00641 } 00642 00643 int raw_get_info(char *buffer, char **start, off_t offset, int length) 00644 { 00645 int len = 0, num = 0, i; 00646 off_t pos = 128; 00647 off_t begin; 00648 char tmpbuf[129]; 00649 00650 if (offset < 128) 00651 len += sprintf(buffer, "%-127s\n", 00652 " sl local_address rem_address st tx_queue " 00653 "rx_queue tr tm->when retrnsmt uid timeout " 00654 "inode"); 00655 read_lock(&raw_v4_lock); 00656 for (i = 0; i < RAWV4_HTABLE_SIZE; i++) { 00657 struct sock *sk; 00658 00659 for (sk = raw_v4_htable[i]; sk; sk = sk->next, num++) { 00660 if (sk->family != PF_INET) 00661 continue; 00662 pos += 128; 00663 if (pos <= offset) 00664 continue; 00665 get_raw_sock(sk, tmpbuf, i); 00666 len += sprintf(buffer + len, "%-127s\n", tmpbuf); 00667 if (len >= length) 00668 goto out; 00669 } 00670 } 00671 out: 00672 read_unlock(&raw_v4_lock); 00673 begin = len - (pos - offset); 00674 *start = buffer + begin; 00675 len -= begin; 00676 if (len > length) 00677 len = length; 00678 if (len < 0) 00679 len = 0; 00680 return len; 00681 } 00682 00683 struct proto raw_prot = { 00684 name: "RAW", 00685 close: raw_close, 00686 connect: udp_connect, 00687 disconnect: udp_disconnect, 00688 ioctl: raw_ioctl, 00689 init: raw_init, 00690 setsockopt: raw_setsockopt, 00691 getsockopt: raw_getsockopt, 00692 sendmsg: raw_sendmsg, 00693 recvmsg: raw_recvmsg, 00694 bind: raw_bind, 00695 backlog_rcv: raw_rcv_skb, 00696 hash: raw_v4_hash, 00697 unhash: raw_v4_unhash, 00698 };

Generated on Wed Dec 1 21:25:32 2004 for Linux 2.4.23 Networking by doxygen 1.3.8