📄 datagram.c
字号:
/* * SUCS NET2 Debugged. * * Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top * of these would make sense. Not tonight however 8-). * This is used because UDP, RAW, PACKET and the to be released IPX layer all have identical select code and mostly * identical recvfrom() code. So we share it here. The select was shared before but buried in udp.c so I moved it. * * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>. (datagram_select() from old udp.c code) * * Fixes: * Alan Cox : NULL return from skb_peek_copy() understood * Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff. * Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but * AX.25 now works right, and SPX is feasible. * Alan Cox : Fixed write select of non IP protocol crash. */#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <asm/segment.h>#include <asm/system.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/in.h>#include <linux/errno.h>#include <linux/sched.h>#include "inet.h"#include "dev.h"#include "ip.h"#include "protocol.h"#include "arp.h"#include "route.h"#include "tcp.h"#include "udp.h"#include "skbuff.h"#include "sock.h"/* * Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible * races. This replaces identical code in packet,raw and udp, as well as the yet to * be released IPX support. It also finally fixes the long standing peek and read * race for datagram sockets. If you alter this routine remember it must be * re-entrant. */struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err){ struct sk_buff *skb; /* Socket is inuse - so the timer doesn't attack it */restart: sk->inuse = 1; while(sk->rqueue == NULL) /* No data */ { /* If we are shutdown then no more data is going to appear. We are done */ if (sk->shutdown & RCV_SHUTDOWN) { release_sock(sk); *err=0; return NULL; } if(sk->err) { release_sock(sk); *err=-sk->err; sk->err=0; return NULL; } /* Sequenced packets can come disconnected. If so we report the problem */ if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED) { release_sock(sk); *err=-ENOTCONN; return NULL; } /* User doesn't want to wait */ if (noblock) { release_sock(sk); *err=-EAGAIN; return NULL; } release_sock(sk); /* Interrupts off so that no packet arrives before we begin sleeping. Otherwise we might miss our wake up */ cli(); if (sk->rqueue == NULL) { interruptible_sleep_on(sk->sleep); /* Signals may need a restart of the syscall */ if (current->signal & ~current->blocked) { sti(); *err=-ERESTARTSYS; return(NULL); } if(sk->err != 0) /* Error while waiting for packet eg an icmp sent earlier by the peer has finaly turned up now */ { *err = -sk->err; sti(); sk->err=0; return NULL; } } sk->inuse = 1; sti(); } /* Again only user level code calls this function, so nothing interrupt level will suddenely eat the rqueue */ if (!(flags & MSG_PEEK)) { skb=skb_dequeue(&sk->rqueue); if(skb!=NULL) skb->users++; else goto restart; /* Avoid race if someone beats us to the data */ } else { cli(); skb=skb_peek(&sk->rqueue); if(skb!=NULL) skb->users++; sti(); if(skb==NULL) /* shouldn't happen but .. */ *err=-EAGAIN; } return skb;}void skb_free_datagram(struct sk_buff *skb){ unsigned long flags; save_flags(flags); cli(); skb->users--; if(skb->users>0) { restore_flags(flags); return; } /* See if it needs destroying */ if(skb->list == NULL) /* Been dequeued by someone - ie its read */ kfree_skb(skb,FREE_READ); restore_flags(flags);}void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size){ /* We will know all about the fraglist options to allow >4K receives but not this release */ memcpy_tofs(to,skb->h.raw+offset,size);}/* * Datagram select: Again totally generic. Moved from udp.c * Now does seqpacket. */int datagram_select(struct sock *sk, int sel_type, select_table *wait){ select_wait(sk->sleep, wait); switch(sel_type) { case SEL_IN: if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE) { /* Connection closed: Wake up */ return(1); } if (sk->rqueue != NULL || sk->err != 0) { /* This appears to be consistent with other stacks */ return(1); } return(0); case SEL_OUT: if (sk->prot && sk->prot->wspace(sk) >= MIN_WRITE_SPACE) { return(1); } if (sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE) { return(1); } return(0); case SEL_EX: if (sk->err) return(1); /* Socket has gone into error state (eg icmp error) */ return(0); } return(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -