Famous software China mirror:
Apache |
PHP |
Debian |
Mysql |
Proftp |
Qmail |
Samba |
Squid |
Xfree86 |
CPAN |
LDP |
GNU |
China Linux Forum Home Technology Forum |
Articles
经 经 | Member Mail | Project Plan | Online Survey | Software Warehouse | About this site |
Discussion Area | Search Articles | New User Registration | Login Forum | Online User | FAQ
Linux Advanced Applications >> Linux Kernel Technology This topic Reads: 3137
Flat pattern tree pattern
Opera (enthusiast) 05/22/01 14:00
The generation of the IP package and the generation and transmission interface of the IP package ============================== (1) There are three basic IP package generators in the Linux core, They are ip_build_xmit (), ip_queue_xmit (), ip_build_and_send_pkt (). Ip_build_and_send_pkt () is a simple IP Package Package interface, which is directly output after the route of the input package is directly output, not fractional processing, TCP_V4_SEND_SYNACK (). IP_send_reply () is a function based on IP_BUILD_XMIT () for TCP_V4_SEND_ACK () and TCP_V4_SEND_RESET (). (2) ip_build_xmit () Use user-defined callback functions to directly read user data segments to generate IP packet output If you need a fragmentation, IP_build_Xmit () generates an IP packet according to the order of the last fragment to the first segment, because the data area of the first IP packet may contain check code to the entire IP package data area, In the callback function, the user may calculate the check code of the output data, and the sequence of output data can be used naturally in the first segment. (3) ip_queue_xmit () Full-oriented connection socket The route of the output package and the IP packet package. When the socket is in the connection state, all the packages emitted from the socket have a determined route without having to query its destination inlet for each output package, and can directly Binding to the route entry, which is completed by the purpose buffer pointer (DST_CACHE) of the socket. IP_QUE_XMIT () first establishes an IP header for the input package. After the filter is filled, the IP package is output (IP_FRAGMENT) If needed. (4) The output of the IP package generator enters the plug-in entry after the packet filter, for the on-demand address, input to the IP output (ip_output); for broadcast or commission addresses Enter the IP homage output (IP_MC_OUTPUT). In the IP output, the routing filter, enter the "neighbor" entry (DST-> neighbour-> output) or hardware frame head buffer entry (DST- " > hh-> hh_output). Neighbor refers to an adjacent host from the host from the network interface device level. Neighbor is responsible for resolving the hardware delivery address of the output package, delivering the package to the adjacent destination host or gateway host. When the neighbor successfully analyzes the hardware delivery address of the package, the hardware frame head buffer structure (DST-> HH) will be created on the entrance of the package, so that the rear package can be Use the assembled frame header directly to pass the package to the package schema (dev_queue_xmit). The package scheduler is rearranged according to the priority of the package, and finally submits the package to the device driver (dev-> hard_start_xmit). IP package Generate interface
----------------
Net / IPv4 / ip_output.c:
INT SYSCTL_IP_DEFAULT_TTL = ipdefttl; the default IP package is 64
/ *
* Add an ip header to a skbuff and send it out.
* /
INT ip_build_and_send_pkt (struct SK_Buff * SKB, STRUCT SOCK * SK, add IP header after adding IP header to the package) U32 Saddr, U32 Daddr, Struct IP_OPTIONS * OPT)
{
Struct RTable * RT = (struct RTable *) SKB-> DST;
Struct iphdr * iph;
/ * Build the ip header. * /
IF (OPT)
IPH = (struct iPhdr *) SKB_PUSH (SKB, SIZEOF (STRUCT IPHDR) OPT-> OPTLEN);
Else
IPH = (struct iphdr *) SKB_PUSH (SKB, SIZEOF (Struct iPhdr));
IPH-> Version = 4;
IPH-> IHL = 5;
IPH-> TOS = SK-> Protinfo.af_Inet.tos;
IPH-> FRAG_OFF = 0;
IF (ip_dont_fragment (SK, & RT-> U.DST)) If the destination port of the IP package is forbidden
IPH-> FRAG_OFF | = HTONS (IP_DF);
IPH-> TTL = SK-> protinfo.af_inet.ttl; Survival in the Tablet Protocol Options
IPH-> DADDR = RT-> RT_DST; take the destination address of the IP packet routing
IPH-> saddr = rt-> rt_src; take the source address of the IP packet
IPH-> protocol = SK-> protocol; Take the socket IP protocol code
IPH-> TOT_LEN = HTONS (SKB-> LEN); IP Package Total Length
IP_SELECT_IDENT (IPH, & RT-> u.dst); assigns an identification number for the IP package, the IP packet identifier of the disabled fragment is zero
SKB-> NH.IPH = IPH;
IF (OPT && Opt-> Optlen) {
IPH-> IHL = OPT-> OPTLEN >> 2;
IP_OPTIONS_BUILD (SKB, OPT, DADDR, RT, 0); Set IP Options Area
}
IP_send_check (iph); setup of IP Baotou
/ * Send it out. * /
Return nf_hook (PF_INET, NF_IP_LOCAL_OUT, SKB, NULL, RT-> u.dst.dev,
OUTPUT_MAYBE_ROUTE); filter output and destination path may be changed
}
INT ip_build_xmit (Struct Sock * SK,
int GETFRAG (Const void *,
Char *,
Unsigned int,
Unsigned int), the function pointer to the data fragment
Const void * Frag, call parameters of the above functions
Unsigned Length,
Struct IPCM_COOKIE * IPC, IP Packet Configuration Information
Struct RTable * RT,
INT FLAGS) Establish IP Package from User Data
{
Int Err;
Struct SK_Buff * SKB;
INT DF;
Struct iphdr * iph;
/ *
* Try The Simple Case First. This Leaves Fragmented Frames, And B
* Choice Raw Frames With 20 Bytes of Maximum Size (Rare) To The Long Path
* /
if (! SK-> Protinfo.af_INET.HDRINCL) {If the IP Baotou is not created by the user
Length = sizeof (struct iPhdr); Take the total length of IP package
/ *
* Check for Slow Path.
* /
IF (Length> rt-> u.dst.pmtu || IPC-> opt! = null) If the package length is greater than the maximum segmentation of the entrance of the destination
Return IP_BUILD_XMIT_SLOW (SK, GetFrag, Frag, Length, IPC, RT, FLAGS);
} else {
IF (Length> RT-> U.DST.DEV-> MTU) {The maximum segment of the inlet device greater than the destination
IP_LOCAL_ERROR (SK, EMSGSIZE, RT-> RT_DST, SK-> DPORT, RT-> U.DST.DEV-> MTU);
Return-Emsgsize;
}
}
IF (Flags & MSG_PROBE) test operation
Goto Out;
/ *
* Do Path MTU Discovery if Needed.
* /
DF = 0;
IF (ip_dont_fragment (SK, & RT-> U.DST) If the slice is disabled
DF = htons (ip_df);
/ *
* Fast Path for unfragmented frames without options.
* /
{
INTHH_LEN = (RT-> u.dst.dev-> hard_header_len 15) & ~ 15;
SKB = SOCK_ALLOC_SEND_SKB (SK, LENGTH HH_LEN 15,
0, flags & msg_dontwait, & err); allocated to the socket
IF (SKB == NULL)
Goto error;
SKB_RESERVE (SKB, HH_LEN); keep hardware frame headspace
}
SKB-> priority = SK-> priority; priority to the socket
SKB-> DST = DST_CLONE (& RT-> u.dst); to take the route's destination entrance
SKB-> NH.IPH = IPH = (struct iPhdr *) SKB_PUT (SKB, Length);
IF (! SK-> protinfo.af_inet.hdrincl) {
IPH-> Version = 4;
IPH-> IHL = 5;
IPH-> TOS = SK-> Protinfo.af_Inet.tos;
IPH-> TOT_LEN = HTons (Length);
IPH-> FRAG_OFF = DF;
IPH-> TTL = SK-> Protinfo.af_INET.MC_TTL;
IP_SELECT_IDENT (IPH, & RT-> U.DST);
IF (RT-> RT_TYPE! = RTN_MULTITIAST)
IPH-> TTL = SK-> Protinfo.af_Inet.ttl;
iPh-> protocol = SK-> protocol;
IPH-> saddr = rt-> rt_src;
IPH-> DADDR = RT-> RT_DST;
IPH-> CHECK = 0;
IPH-> CHECK = IP_FAST_CSUM ((unsigned char *) iPh, iPh-> IHL);
Err = getfrag (FRAG, ((char *) iPh) iPh-> IHL * 4, 0, Length-iPh-> ihl * 4); Read a user
}
Else If the IP Baotou is created by the user, read the user data into the IP header location
Err = getfrag (Frag, (void *) iPh, 0, length);
IF (ERR)
Goto error_fault;
Err = NF_HOOK (PF_INET, NF_IP_LOCAL_OUT, SKB, NULL, RT-> u.dst.dev,
OUTPUT_MAYBE_ROUTE);
IF (Err> 0)
Err = SK-> protinfo.af_inet.recverr? NET_XMIT_ERRNO (ERR): 0;
IF (ERR)
Goto error;
OUT:
Return 0;
Error_Fault:
Err = -efault;
Kfree_skb (SKB);
Error:
IP_INC_STATS (iPoutDiscards);
Return ERR;
}
Static int ip_build_xmit_slow (Struct Sock * SK,
int GETFRAG (Const void *,
Char *,
Unsigned int,
Unsigned int),
Const void * Frag,
Unsigned Length,
Struct IPCM_COOKIE * IPC,
Struct RTable * RT,
INT FLAGS) Establish an IP option area or fragmentation output
{
Unsigned int fraglen, maxfraglen, fragheaderlen
Int Err;
INT Offset, MF;
Int MTU;
U16 ID = 0;
INTHH_LEN = (RT-> u.dst.dev-> hard_header_len 15) & ~ 15;
INT NFRAGS = 0;
Struct ip_options * OPT = IPC-> OPT;
INT DF = 0;
MTU = RT-> u.dst.pmtu;
IF (ip_dont_fragment (SK, & RT-> U.DST))
DF = htons (ip_df);
Length - = SizeOf (struct iPhdr);
IF (OPT) {
Fragheaderlen = sizeof (struct iPhdr) OPT-> Optlen;
Maxfraglen = ((mtu-sizeof (struct iphdr) -opt-> optlen) & ~ 7) Fragheaderlen
} else {
Fragheaderlen = sizeof (struct iPhdr);
/ *
* Fragheaderlen is The size of 'Overhead' on each buffer. Now Work
* Out the size of the frames to send.
* /
MaxFraglen = ((MTU-sizeof (struct iPhdr)) & ~ 7) Fragheaderlen
} Ask the maximum IP package
IF (Length Fragheaderlen> 0xfff) {
IP_LOCAL_ERROR (SK, EMSGSIZE, RT-> RT_DST, SK-> DPORT, MTU);
Return-Emsgsize;
}
/ *
* Start at the end of the frame by handling the remainder. * /
OFFSET = Length - (Maxfraglen - Fragheaderlen); take the data offset of the last fragment
/ *
* Amount of Memory to Allocate for final fragment.
* /
Fraglen = Length - offset fragheaderlen; Full length of the next fragment IP package
if (length-offset == 0) {If the user data is exactly the integer multiple of the maximum single-chip data length
Fraglen = MaxFraglen;
OFFSET - = MAXFRAGLEN-FRAGHEADERLEN
}
/ *
* The Last Fragment Will Not Have MF (More Fragments) Set.
* /
Mf = 0;
/ *
* Don't Fragment Packets for Path Mtu Discovery.
* /
IF (Offset> 0 && Sk-> Protinfo.af_INET.PMTUDISC == IP_PMTUDISC_DO) {
IP_LOCAL_ERROR (SK, EMSGSIZE, RT-> RT_DST, SK-> DPORT, MTU);
Return-Emsgsize;
}
IF (Flags & MSG_PROBE)
Goto Out;
/ *
* Begin outputting the bytes.
* /
Do {
CHAR * DATA;
Struct SK_Buff * SKB;
/ *
* Get The Memory We Require with Some Space Left for alignment.
* /
SKB = SOCK_ALLOC_SEND_SKB (SK, Fraglen HH_LEN 15, 0, Flags & MSG_DONTWAIT, & ERR);
IF (SKB == NULL)
Goto error;
/ *
* Fill in The Control Structure
* /
SKB-> Priority = SK-> Priority
SKB-> DST = DST_CLONE (& RT-> U.dst);
SKB_RESERVE (SKB, HH_LEN);
/ *
* Find where to start putting bytes.
* /
Data = SKB_PUT (SKB, FRAGLEN);
SKB-> NH.IPH = (struct iPhdr *) DATA;
/ *
* ONLY WRITE IP HEADER ONTO NON-RAW PACKETS
* /
{
Struct iphdr * iPh = (struct iPhdr *) DATA;
IPH-> Version = 4;
IPH-> IHL = 5;
IF (OPT) {
IPH-> IHL = OPT-> OPTLEN >> 2;
IP_OPTIONS_BUILD (SKB, OPT,
IPC-> Addr, RT, Offset
}
IPH-> TOS = SK-> Protinfo.af_Inet.tos;
IPH-> TOT_LEN = HTONS (Fraglen - Fragheaderlen iPh-> IHL * 4);
IPH-> FRAG_OFF = HTONS (Offset >> 3) | MF | DF; IPH-> ID = ID;
IF (! mf) {
IF (offset ||! df) {
/ * SELECT An unpredictable Ident Only
* for packets without df or haVing
* been fragmented.
* /
__ip_select_ident (iPh, & rt-> u.dst);
ID = iPh-> ID;
}
/ *
* Any Further Fragments Will Have MF Set.
* /
Mf = HTONS (IP_MF);
}
IF (RT-> RT_TYPE == RTN_MULTITIST)
IPH-> TTL = SK-> Protinfo.af_INET.MC_TTL;
Else
IPH-> TTL = SK-> Protinfo.af_Inet.ttl;
iPh-> protocol = SK-> protocol;
IPH-> CHECK = 0;
IPH-> saddr = rt-> rt_src;
IPH-> DADDR = RT-> RT_DST;
IPH-> CHECK = IP_FAST_CSUM ((unsigned char *) iPh, iPh-> IHL);
Data = iPh-> ihl * 4;
}
/ *
* User Data Callback
* /
IF (Getfrag (Frag, Data, Offset, Fraglen-fragheaderlen) {
Err = -efault;
Kfree_skb (SKB);
Goto error;
}
OFFSET - = (Maxfraglen-fragheaderlen); fragments segmented forward, is to facilitate the TCP package
Fraglen = MaxFraglen;
NFRAGS ;
Err = NF_HOOK (PF_INET, NF_IP_LOCAL_OUT, SKB, NULL,
SKB-> DST-> dev, output_maybe_reroute;
IF (err) {
IF (Err> 0)
Err = SK-> protinfo.af_inet.recverr? NET_XMIT_ERRNO (ERR): 0;
IF (ERR)
Goto error;
}
} while (offset> = 0);
IF (nfrags> 1)
IP_STATISTICS [SMP_PROCESSOR_ID () * 2 ! In_softirq ()]. IPFragcreates = NFRAGS;
OUT:
Return 0;
Error:
IP_INC_STATS (iPoutDiscards);
IF (nfrags> 1)
IP_STATISTICS [SMP_PROCESSOR_ID () * 2 ! In_softirq ()]. IPFragcreates = NFRAGS;
Return ERR;
}
/ *
* Generic function to send a packet as reply to another packet.
* Used to send TCP Resets so far. ICMP Should Use this function TOO.
*
* SHOULD Run Single Threaded Per Socket Because It Uses The Sock * Structure to Pass Arguments.
* /
Void ip_send_reply (Struct Sock * SK, STRUCT SK_BUFF * SKB, STRUCT IP_REPLY_ARG * ARG,
Unsigned int LEN
{
Struct {
Struct ip_options opt;
Char Data [40]; store IP option block
} replyopts;
Struct IPCM_Cookie IPC;
U32 DADDR;
Struct RTable * RT = (struct RTable *) SKB-> DST;
IF (ip_options_echo (& replyopts.opt, SKB) refreshes the IP option of the package SKB to the Replyopts structure
Return;
Daddr = ipc.addr = rt-> rt_src;
IPC.OPT = NULL;
IF (replyopts.opt.optlen) {
IPC.OPT = & replyopts.opt;
IF (IPC.OPT-> SRR)
Daddr = replyopts.opt.faddr;
}
IF (IP_ROUTE_OUTPUT (& RT, Daddr, RT-> RT_SPEC_DST, RT_TOS (SKB-> NH.IPH-> TOS), 0))
Return;
/ * And let ip do all the hard work.
This Chunk is not reenterable, Hence Spinlock.
Note That It Uses The Fact, That this function is called
WITH LOCALLY DISABED BH AND THAT SK CANNOT BE Already SpinLocked.
* /
BH_LOCK_SOCK (SK);
SK-> Protinfo.af_Inet.tos = SKB-> NH.IPH-> TOS;
SK-> priority = SKB-> priority;
SK-> Protocol = SKB-> NH.IPH-> Protocol;
IP_BUILD_XMIT (SK, IP_REPLY_GLUE_BITS, ARG, LEN, & IPC, RT, MSG_DONTWAIT);
BH_UNLOCK_SOCK (SK);
IP_RT_PUT (RT);
}
Struct ip_reply_arg {
Struct Iovec IOV [2];
INT N_IOV; / * Redundant * /
U32 CSUM;
INT CSUMOFFSET; / * U16 Offset of Csum in Iov [0] .iov_base * /
/ * -1 if not needed * /
}
/ *
* Fetch Data from Kernel Space and Fill in Checksum if Needed.
* /
Static int ip_reply_glue_bits (const void * dptr, char * to, unsigned int offset,
Unsigned int fraglen
{
Struct ip_reply_arg * dp = (struct ip_reply_arg *) DPTR;
U16 * pktp = (u16 *) TO;
Struct Iovec * IOV;
Int Len;
INT HDRFLAG = 1; IOV = & dp-> IOV [0];
IF (Offset> = IOV-> IOV_LEN) {
OFFSET - = IOV-> IOV_LEN;
IOV ;
HDRFLAG = 0;
}
Len = IOV-> IOV_LEN - OFFSET;
IF (Fraglen> Len) {/ * overlapping. * /
DP-> CSUM = CSUM_PARTIAL_COPY_NOCHECK (IOV-> IOV_BASE OFFSET, TO, LEN,
DP-> CSUM;
OFFSET = 0;
Fraglen - = len;
TO = LEN;
IOV ;
}
DP-> CSUM = CSUM_PARTIAL_COPY_NOCHECK (IOV-> IOV_BASE OFFSET, TO, FRAGLEN,
DP-> CSUM;
IF (HDRFLAG && DP-> CSUMOFFSET)
* (PKTP DP-> CSUMOFFSET) = CSUM_FOLD (DP-> CSUM); / * Fill in checksum * /
Return 0;
}
INT IP_QUE_XMIT (Struct Sk_buff * SKB)
{
Struct Sock * SK = SKB-> SK;
Struct ip_options * OPT = SK-> protinfo.af_inet.opt;
Struct RTable * rt;
Struct iphdr * iph;
/ * Make Sure We Can Route this packet. * /
RT = (STRUCT RTABLE *) __ SK_DST_CHECK (SK, 0); Take the destination route entry of the sending package buffered by the socket
IF (RT == NULL) {If it is not buffered
U32 DADDR;
/ * USE CORRECT DESTINATION Address if we have options. * /
Daddr = SK-> DADDR; Take the peer address of the socket as the destination address
IF (Opt && Opt-> SRR) If you have a source routing option
Daddr = OPT-> Faddr; the forwarding address of the trust source is the destination address
/ * If this fails, Retransmit Mechanism of Transport Layer Will
* Keep Trying Until Route APPEARS or the connection Times Itself
* OUT.
* /
IF (IP_ROUTE_OUTPUT (& RT, Daddr, Sk-> Saddr,
RT_TOS (SK-> Protinfo.af_INET.TOS) | RTO_CONN | SK-> Localroute,
SK-> bound_dev_if)) Query the route destination port of the destination address
Goto no_route;
__sk_dst_set (SK, & RT-> U.DST); burst the route into the socket
}
SKB-> DST = DST_CLONE (& RT-> U.dst); bind the route entry to the send package
IF (OPT && Opt-> is_strictroute &<-> rt_dst! = rt-> rt_gateway)
Goto no_route; if it is specified, the strict source route is specified and its forwarding address is not equal to the gateway address, the operation failed / * OK, We know where to send it, allocate and build ip header. * /
IPH = (STRUCT IPHDR *) SKB_PUSH (SKB, SIZEOF (STRUCT IPHDR) (OPT? OPT-> OPTLEN: 0));
* ((__ u16 *) iPh) = htons ((4 << 12) | (5 << 8) | (SK-> Protinfo.af_Inet.tos & 0xFF));
IPH-> TOT_LEN = HTONS (SKB-> LEN);
IPH-> FRAG_OFF = 0;
IPH-> TTL = SK-> Protinfo.af_Inet.ttl;
iPh-> protocol = SK-> protocol;
IPH-> saddr = rt-> rt_src;
IPH-> DADDR = RT-> RT_DST;
SKB-> NH.IPH = IPH;
/ * Transport Layer Set SET SKB-> H.foo itself. * /
IF (OPT && Opt-> Optlen) {Establish IP Options Area
IPH-> IHL = OPT-> OPTLEN >> 2;
IP_OPTIONS_BUILD (SKB, OPT, SK-> DADDR, RT, 0);
}
Return nf_hook (PF_INET, NF_IP_LOCAL_OUT, SKB, NULL, RT-> u.dst.dev,
IP_QUEUE_XMIT2); Filter output
NO_ROUTE:
IP_INC_STATS (iPoutnorouts);
Kfree_skb (SKB);
Return-Ehostunreach;
}
/ * Queues a packet to be sample, and starts the transmitter if Necessary.
* This Routine Also Needs to Putin The Total Length and Compute The Total Length
* Checksum. we use to do this in two two, ip_build_header () THEN
* This, But That Scheme Created a Mess When Routes Disappeared ETC.
* So We do it all here, and the TCP Send Engine Has Been Changed To
* Match. (no more unroduction fin disphase, etc. whee ...) this will
* MOST LIKELY MAKE OTHER RELIABLE TRANSPORT LAYERS Above IP Easier
* TO IMPLEMENT Under Linux.
* /
Static Inline INT IP_QUEUE_XMIT2 (Struct Sk_buff * SKB)
{
Struct Sock * SK = SKB-> SK;
Struct RTable * RT = (struct RTable *) SKB-> DST;
Struct Net_Device * dev;
Struct iphdr * iph = SKB-> NH.IPH;
DEV = RT-> u.dst.de;
/ * This can happen when the transfer * with a cached route, and by the time we get here
* RE-ROUTED TO A Device with a Different MTU Than THE Original
* Device. Sick, But Weme Must Cover IT.
* /
IF (SKB_HEADROOM (SKB)
Struct SK_Buff * SKB2;
SKB2 = SKB_REALLOC_HEADROOM (SKB, (dev-> hard_header_len 15) & ~ 15); copy and reassign the original package
Kfree_skb (SKB);
IF (SKB2 == NULL)
Return -ENMEM;
IF (SK)
SKB_SET_OWNER_W (SKB2, SK); Setup package has a socket
SKB = SKB2;
IPH = SKB-> NH.IPH;
}
IF (SKB-> LEN> RT-> u.dst.pmtu)
Goto fragment;
IF (ip_dont_fragment (SK, & RT-> U.DST))
IPH-> FRAG_OFF | = __constant_htons (ip_df);
IP_SELECT_IDENT (IPH, & RT-> U.DST);
/ * Add an ip checksum. * /
IP_send_check (iph);
SKB-> Priority = SK-> Priority
Return SKB-> DST-> OUTPUT (SKB);
Fragment:
IF (ip_dont_fragment (SK, & RT-> U.DST) {
/ * REJECT PACKET ONLY TCP Might Fragment
* ITTSelf, if were caleful enough.
* /
IPH-> FRAG_OFF | = __constant_htons (ip_df);
NetDebug (Printk (kern_debug "sending pkt_too_big to self / n")));
ICMP_SEND (SKB, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
HTONL (RT-> u.dst.pmtu);
Kfree_skb (SKB);
Return-Emsgsize;
}
IP_SELECT_IDENT (IPH, & RT-> U.DST);
Return IP_Fragment (SKB, SKB-> DST-> OUTPUT);
}
/ *
* This ip DataGram is to large to be self in one piece. Break it up INTO
* Smaller Pieces (Each of Size Equal to IP Header Plus
* a Block of the data of the original ip data part) That Will Yet Fit in A
* Single Device Frame, and queue such a frame for sending.
*
* Yes this is INEfficient, Feel Free To Submit a Quicker One.
* /
INT IP_FRAGMENT (STRUCT SK_BUFF * SKB, INT (* OUTPUT) (Struct Sk_Buff *))
{
Struct iphdr * iph;
UNSIGNED Char * RAW;
UNSIGNED Char * PTR;
Struct Net_Device * dev;
Struct SK_Buff * SKB2;
Unsigned int MTU, HLEN, LEFT, LEN;
Int offset
INT not_last_frag;
Struct RTable * RT = (struct RTable *) SKB-> DST;
INT ERR = 0;
DEV = RT-> u.dst.de;
/ *
* Point INTO The IP DataGram Header.
* /
RAW = SKB-> NH.RAW;
IPH = (struct iphdr *) RAW;
/ *
* Setup starting value.
* /
HLEN = iPh-> ihl * 4;
Left = ntoHS (iPh-> Tot_len) - Hlen; / * Space Per frame * /
MTU = RT-> u.dst.pmtu - hlen; / * size of data space * /
PTR = Raw Hlen; / * Where to start from * /
/ *
* Fragment The DataGram.
* /
OFFSET = (NTOHS (iPh-> Frag_off) & ip_offset) << 3;
NOT_LAST_FRAG = iPh-> Frag_off & Htons (IP_MF);
/ *
* Keep Copying Data Until We Run OUT.
* /
While (Left> 0) {
Len = Left;
/ * If: it's 'mtu' - the data space left * /
IF (Len> MTU)
Len = MTU;
/ * If: we are not sending upto and incruDing the packet end
Then align the next start on an electric byte boundary * /
IF (len Len & = ~ 7; } / * * Allocate Buffer. * / IF ((SKB2 = Alloc_skb (Len Hlen Dev-> HARD_HEADER_LEN 15, GFP_ATOMIC)) == NULL) { NetDebug (Printk (Kern_info "IP: FRAG: No Memory for New Fragment! / N")) Err = -enomem; Goto fail; } / * * SET UP DATA on Packet * / SKB2-> PKT_TYPE = SKB-> PKT_TYPE; SKB2-> Priority = SKB-> Priority; SKB_RESERVE (SKB2, (Dev-> Hard_Header_len 15) & ~ 15); SKB_PUT (SKB2, LEN HLEN); SKB2-> nh.raw = SKB2-> DATA; SKB2-> H.RAW = SKB2-> Data Hlen; / * * Charge the memory for the Fragment to any Owner * IT Might Possess * / IF (SKB-> SK) SKB_SET_OWNER_W (SKB2, SKB-> SK); SKB2-> DST = DST_CLONE (SKB-> DST); SKB2-> dev = SKB-> DEV; / * * Copy The Packet Header INTO The New Buffer. * / Memcpy (SKB2-> NH.RAW, RAW, HLEN); / * * Copy A Block of the IP DataGram. * / Memcpy (SKB2-> H.RAW, PTR, LEN); LEFT - = LEN; / * * Fill in The New Header Fields. * / IPH = SKB2-> NH.IPH; IPH-> FRAG_OFF = HTONS ((Offset >> 3)); / * Ank: Dirty, But Effective Trick. Upgrade Options ONLY IF * The segment to be fragmented Was the first (Otherwise, * Options are already fixed) and make it it overce * on The initial SKB, SO That All The Following Fragments * Will inherit fixed options. * / IF (Offset == 0) IP_OPTIONS_FRAGMENT (SKB); / * * Added AC: if we are fragmenting a fragment thing's not the * Last Fragment Then Keep Mf on Each Bit * / IF (Left> 0 || Not_Last_Frag) IPH-> FRAG_OFF | = HTONS (IP_MF); PTR = LEN; OFFSET = LEN; #ifdef config_netfilter / * Connection Association Is Same as pre-frag packet * / SKB2-> NFCT = SKB-> NFCT; NF_CONNTRACK_GET (SKB2-> NFCT); #ifdef config_netfilter_debug SKB2-> nf_debug = SKB-> NF_DEBUG; #ENDIF #ENDIF / * * Put this fragment info the sending queue. * / IP_inc_stats (ipfragcreates); IPH-> TOT_LEN = HTONS (LEN HLEN); IP_send_check (iph); Err = OUTPUT (SKB2); IF (ERR) Goto fail; } Kfree_skb (SKB); IP_INC_STATS (IPFragoks); Return ERR; Fail: Kfree_skb (SKB); IP_INC_STATS (ipfragfails); Return ERR; } IP package output interface ---------------- / * Don't just hand nf_hook SKB-> DST-> Output, In Case Netfilter Hookchanges Route * / Static Inline INT The destination portal pointer of the package may be changed by the packet filter, so the output function of the destination inlet cannot be provided directly to the package filter. OUTPUT_MAYBE_REROUTE (STRUCT SK_BUFF * SKB) { Return SKB-> DST-> OUTPUT (SKB); through the purpose of the destination, for the Unicast address, point ip_output () } INT ip_output (STRUCT SK_BUFF * SKB) on demand address IP package output { #ifdef config_ip_route_nat Struct RTable * RT = (struct RTable *) SKB-> DST; #ENDIF IP_INC_STATS (iPoutRequests); #ifdef config_ip_route_nat IF (RT-> RT_FLAGS & RTCF_NAT) IP_DO_NAT (SKB); #ENDIF Return IP_FINISH_OUTPUT (SKB); } __INline__ int ip_finish_output (struct SK_Buff * SKB) { Struct Net_Device * dev = SKB-> DST-> DEV; SKB-> DEV = dev; set the output device of the package SKB-> protocol = __constant_htons (eth_p_ip); Settings the frame type Return nf_hook (PF_INET, NF_IP_POST_ROUTING, SKB, NULL, DEV, IP_FINISH_OUTPUT2); } Static Inline INT IP_FINISH_OUTPUT2 (Struct SK_Buff * SKB) { STRUCT DST_ENTRY * DST = SKB-> DST; Take the entry of the IP package binding Struct hh_cache * hh = dst-> hh; the hardware frame head buffer structure of the extraction #ifdef config_netfilter_debug NF_DEBUG_IP_FINISH_OUTPUT2 (SKB); #ENDIF / * config_netfilter_debug * / If (hh) {if the frame head buffer exists Read_lock_bh (& HH-> HH_LOCK); Memcpy (SKB-> DATA - 16, HH-> HH_DATA, 16); directly copy hardware frame header Read_unlock_bh (& HH-> HH_LOCK); SKB_PUSH (SKB, HH-> HH_LEN); Return hh-> hh_output (SKB); through the frame head buffer output, generally point to dev_queue_xmit () } Else if (DST-> neighbour) outputs through neighborhood (device hardware address resolution, and buffer structure) Return DST-> neighbour-> output (SKB); point to neigh_resolve_output () About the Neighbour structure and the ARP process can be seen from the "Linux Hardware Address Analysis Process" post Printk (kern_debug "khm / n"); Kfree_skb (SKB); Return-EinVal; } IP package creation process during options ---------------------------- Net / IPv4 / ip_options.c: Struct ip_options {ip option area index structure, when receiving IP packets, the front of the packet buffer is the front of the front, which is the structure __U32 faddr; / * Saved first hop address * / UNSIGNED Char Optlen; UNSIGNED CHAR SRR; UNSIGNED Char RR; UNSIGNED CHAR TS; Unsigned char is_setbyuser: 1, / * set by setsockopt? * / IS_DATA: 1, / * OPTIONS IN __DATA, Rather Than SKB * / IS_STRICTROUTE: 1, / * STRICT SOURCE ROUTE * / SRR_IS_HIT: 1, / * PACKET DESTINATION AddR Was Our One * / IS_CHANGED: 1, / * ip checksum more not valid * / RR_NEEDADDR: 1, / * NEED TO RECORD ADDR OF OUTGOING DEV * / TS_NEEDTIME: 1, / * NEED TO RECORD TIMESTAMP * / TS_NEEDADDR: 1; / * NEED TO RECORD Addr of Outgoing Dev * / UNSIGNED Char router_alert; Unsigned char __pad1; Unsigned char __pad2; Unsigned char __data [0]; } Struct inet_skb_parm { Struct ip_options opt; / * compiled ip options * / Unsigned char flags; #define ipskb_masqueraded 1 #define ipskb_translated 2 #define ipskb_forwarded 4 } #define IPCB (SKB) (Struct INET_SKB_PARM *) ((SKB) -> CB)) / * * Options "fragmenting", Just Fill Options Not * ALLOWED IN FRAGENTS with noops. * Simple and stupid 8), But the Most Efficient Way. * / Void ip_options_fragment (struct SK_Buff * SKB) { Unsigned char * OPTPTR = SKB-> nh.raw; ??? Isn't it point to IP #, how to use it as an IP option area??? Struct ip_options * OPT = & (IPCB (SKB) -> OPT); Pack Buffer Control Block (CB) INT L = OPT-> OPTLEN; Int Optlen; While (l> 0) { Switch (* optptr) { Case ipopt_end: Return; Case ipopt_noop: L -; OPTPTR ; CONTINUE; } Optlen = OPTPTR [1]; IF (Optlen <2 || Optlen> L) Return; if (! iPopt_copied (* OPTPTR)) replace all options with the segment copy flag to an empty option MEMSET (Optptr, iPopt_noop, Optlen); L - = Optlen; Optptr = Optlen; } OPT-> TS = 0; OPT-> rr = 0; OPT-> rr_needaddr = 0; OPT-> TS_NEEDADDR = 0; OPT-> TS_NEEDTIME = 0; Return; } / * * Write Options to ip Header, Record Destination Address To * Source Route Option, Address of Outgoing Interface * (We Should Already Know It, So That "Function is allowed BE * Called Only After Routing Decision) and timestamp, * if We Originate this DataGram. * * Daddr Is Real Destination Address, Next Hop is Recorded In IP Header. * Saddr is address of outgoing interface. * / Void ip_options_build (struct SK_Buff * SKB, Struct ip_options * OPT, U32 Daddr, Struct RTable * RT, INT IS_FRAG) { Unsigned char * iph = SKB-> nh.raw; Memcpy (& (IPCB) -> OPT), OPT, SIZEOF (Struct IP_Options)); copy the IP option parameter to the package buffer Memcpy (IPH SIZEOF (STRUCT IPHDR), OPT -> __ Data, Opt-> Optlen; copy the IP option data block to the IP package option area OPT = & (IPCB (SKB) -> OPT); OPT-> IS_DATA = 0; IF (OPT-> SRR) Copy the address DADDR to the last item of the source routing option table Memcpy (iPH OPT-> SRR IPH [OPT-> SRR 1] -4, & DADDR, 4); IF (! is_frag) {If it is not a fragment IF (OPT-> RR_NEEDDR) Record the address of the output device IP_RT_GET_SOURCE (IPH OPT-> RR IPH [OPT-> RR 2] -5, RT); IF (OPT-> TS_NEEDADDR) Record Time Stamp Address IP_RT_GET_SOURCE (IPH OPT-> TS IPH [OPT-> TS 2] -9, RT); IF (OPT-> TS_NEEDTIME) {Record Time Stamp Struct TimeVal TV; __U32 MIDTIME; DO_GETTIMEOFDAY (& TV); Midtime = HTONL ((TV.tv_sec% 86400) * 1000 TV.tv_usec / 1000); Memcpy (iPh OPT-> TS IPH [OPT-> TS 2] -5, & MidTime, 4); } Return; } IF (OPT-> RR) {Fill into IT MEMSET (iPh OPT-> RR, IPOPT_NOP, IPH [OPT-> RR 1]); OPT-> rr = 0; OPT-> r_needaddr = 0; } IF (OPT-> TS) { MEMSET (iPh OPT-> TS, IPOPT_NOP, IPH [OPT-> TS 1]); OPT-> TS = 0; OPT-> TS_NEEDADDR = OPT-> TS_NEEDTIME = 0; } / * * Provided (Sopt, SKB) Points to Received Options, * Build in Dopt Compiled Option Set Appropriate for Answering. * i.e. Invert srr option, Copy Another, * And grab room in rr / ts Options. * * Note: Dopt Cannot Point to SKB. * / INT ip_options_echo (struct ip_options * DOPT, STRUCT SK_BUFF * SKB) { Struct ip_options * sopt; UNSIGNED Char * SPTR, * DPTR; Int Soffset, Doffset; Int Optlen; U32 DADDR; MEMSET (DOPT, 0, SIZEOF (Struct IP_Options); clear the output option area index structure DOPT-> IS_DATA = 1; SOPT = & (IPCB (SKB) -> OPT); IF (sl-> optlen == 0) { DOPT-> OPTLEN = 0; Return 0; } SPTR = SKB-> NH.RAW; DPTR = DOPT -> __ data; point to the output options area IF (SKB-> DST) Daddr = (Struct RTable *) SKB-> DST) -> RT_SPEC_DST; Else Daddr = SKB-> NH.IPH-> DADDR; IF (SOPT-> RR) { Optlen = SPTR [SOPT-> RR 1]; Take the IP Packet Routing Record Table Length Soffset = SPTR [SOPT-> RR 2]; take the current address record index DOPT-> rr = DOPT-> OPTLEN SIZEOF (Struct iPhdr); take the output option area tail Memcpy (DPTR, SPTR SOPT-> RR, OPTLEN); Copy Routing Record Table IF (Sopt-> r_needaddr && software <= OPTLEN) { IF (Soffset 3> Optlen) Return-EinVal; DPTR [2] = SOFFSET 4; Update Address Record Index DOPT-> rr_needaddr = 1; } DPTR = OPTLEN; Update Options Output Pointer DOPT-> OPTLEN = Optlen; Update Options Length Variable } IF (SOPT-> TS) { Optlen = SPTR [SOPT-> TS 1]; Take timestamp table option length Soffset = SPTR [SOPT-> TS 2]; take the current timestamp record index DOPT-> TS = DOPT-> OPTLEN SIZEOF (struct iPhdr); Memcpy (DPTR, SPTR SOPT-> TS, OPTLEN); copy timestamp table IF (SoffSet <= OPTLEN) { IF (SOPT-> TS_NEEDADDR) { IF (Soffset 3> Optlen) Return-EinVal; DOPT-> TS_NEEDADDR = 1; Soffset = 4; } IF (Sopt-> TS_NEEDTIME) { IF (Soffset 3> Optlen) Return-EinVal; IF ((DPTR [3] & 0xF)! = iPopt_ts_prespec) { DOPT-> TS_NEEDTIME = 1; Soffset = 4; } else {If you take a specified address DOPT-> TS_NEEDTIME = 0; IF (Soffset 8 <= OPTLEN) { __U32 addr; Memcpy (& Addr, SPTR Soffset-1, 4); IF (INET_ADDR_TYPE (AddR)! = RTN_LOCAL) { DOPT-> TS_NEEDTIME = 1; SOFFSET = 8; } } } } DPTR [2] = Soffset; } DPTR = Optlen; DOPT-> OPTLEN = Optlen; } IF (SOPT-> SRR) { Unsigned char * start = sptr sopt-> sr; U32 faddr; Optlen = start [1]; Soffset = start [2]; DOFFSET = 0; IF (Soffset> Optlen) Soffset = Optlen 1; Soffset - = 4; IF (Soffset> 3) { Memcpy (& Faddr, & Start [Soffset-1], 4); For (Soffset- = 4, Doffset = 4; Soffset> 3; Soffset- = 4, DOFFSET = 4) Memcpy (& DPTR [DOFFSET-1], & Start [Soffset-1], 4); / * * RFC1812 Requires to FIX ILLEGAL SOURCE ROUTES. * / IF (Memcmp (& SKB-> NH.IPH-> Saddr, & Start [Soffset 3], 4) == 0) DOFFSET - = 4; } IF (DOFFSET> 3) { Memcpy (& Start [Doffset-1], & DADDR, 4); DOPT-> FADDR = Faddr; DPTR [0] = START [0]; DPTR [1] = DOFFSET 3; DPTR [2] = 4; DPTR = DOFFSET 3; DOPT-> SRR = DOPT-> OPTLEN SIZEOF (Struct iPhdr); DOPT-> OPTLEN = DOFFSET 3; DOPT-> is_stricttroute = SOPT-> is_stricTroute; } } While (DOPT-> OPTLEN & 3) { * DPTR = iPopt_end; DOPT-> OPTLEN ; } Return 0; } Some related functions ---------------- Static Inline Struct DST_ENTRY * __sk_dst_check (Struct Sock * SK, U32 cookie) Verify the entrance to the buffer set { Struct DST_ENTRY * DST = SK-> DST_CACHE; IF (DST && DST-> Obsolete && Dst-> Ops-> Check (DST, Cookie) == NULL) { SK-> DST_CACHE = NULL; Return NULL; } Return DST; } Static STRUCT DST_ENTRY * IPv4_DST_CHECK (Struct DST_ENTRY * DST, U32 cookie) {; IPv4 protocol's destination portal calibration function DST_RELEASE (DST); Return NULL; } Static inline INT IP_DONT_FRAGMENT (STRUCT SOCK * SK, STRUCT DST_ENTRY * DST) Whether IP fragmentation is allowed { Return (SK-> Protinfo.af_Inet.pmtudisc == ip_pmtudisc_do || (SK-> Protinfo.af_Inet.pmtudisc == ip_pmtudisc_want && ! (DST-> MXLOCK & (1 < } Static Inline Void IP_SELECT_IDENT (Struct iPhdr * iPh, Struct DST_ENTRY * DST) Assign IP package identification { IF (iph-> frag_off & __ constant_htons (ip_df)) IPH-> ID = 0; Else __IP_SELECT_IDENT (IPH, DST); } / * Generate a checksum for an outgoing ip database ip DataM. * / __INline__ void ip_send_check (struct iPhdr * iPh) check IP Baotou { IPH-> CHECK = 0; IPH-> CHECK = IP_FAST_CSUM ((unsigned char *) iPh, iPh-> IHL); } #define SKB_EXT_ERR (SKB) (Struct Sock_exterr_skb *) ((SKB) -> CB)) Void IP_LOCAL_ERROR (Struct Sock * SK, Int Err, U32 Daddr, U16 Port, U32 INFO) Generate an error packet { Struct Sock_exterr_skb * SERR; Struct iphdr * iph; Struct SK_Buff * SKB; IF (! SK-> protinfo.af_inet.recverr) Return; SKB = Alloc_skb (SIZEOF (STRUCT IPHDR), GFP_ATOMIC); IF (! SKB) Return; IPH = (struct iphdr *) SKB_PUT (SKB, SIZEOF (Struct Iphdr)); SKB-> NH.IPH = IPH; IPH-> DADDR = DADDR; SERR = SKB_EXT_ERR (SKB); pick buffer control block (CB) Serr-> ee.ee_errno = err; error code Serr-> EE.EE_ORIGIN = so_ee_origin_local; error source Serr-> EE.EE_TYPE = 0; Serr-> EE.EE_CODE = 0; Serr-> EE.EE_PAD = 0; Serr-> EE.EE_INFO = INFO; error parameters Serr-> EE.EE_DATA = 0; Serr-> addr_offset = (u8 *) & iPh-> daddr - skb-> nh.raw; SERR-> port = port; SKB-> H.RAW = SKB-> TAIL; SKB_PULL (SKB, SKB-> TAIL - SKB-> DATA); IF (SOCK_QUEUE_ERR_SKB (SK, SKB)) Add to the Error Packet Queue Kfree_skb (SKB); } Static Inline Int Sock_Queue_ERR_SKB (Struct Sock * SK, STRUCT SK_BUFF * SKB) { / * CAST SKB-> RCVBUF to Unsigned ... it's pointless, but reduces Number of Warnings When Compiling with -w --ank * / IF (Atomic_Read (& Sk-> RMEM_alloc) SKB-> Truesize> = (unsigned) SK-> RCVBUF) Return -ENMEM; SKB_SET_OWNER_R (SKB, SK); SKB_QUEUE_TAIL (& SK-> Error_Queue, SKB); IF (! SK-> DEAD) SK-> Data_Ready (SK, SKB-> LEN); Wake-up Sockets Waiting for Queue Return 0; } / * * Queue a Received DataGram if IT Will Fit. Stream and sequenced * protocols can't normally use this as the name need to fit buffers in * And play with them. * * Inlined As It's Very Short and Called for Pretty Much Every * packet Ever received. * / Static Inline Void SKB_SET_OWNER_W (Struct SK_Buff * SKB, STRUCT SOCK * SK) Set the socket of the send package { SOCK_HOLD (SK); SKB-> SK = SK; SKB-> DESTRUCTOR = SOCK_WFREE; Atomic_add (SKB-> TRUESIZE, & SK-> WMEM_ALLOC); refreshing the distribution amount of the sending memory } Static Inline Void SKB_SET_OWNER_R (Struct Sk_buff * SKB, STRUCT SOCK * SK) Set a socket with the receiving package { SKB-> SK = SK; SKB-> Destructor = SOCK_RFREE; Atomic_add (SKB-> TRUESIZE, & SK-> RMEM_ALLOC); Refresh the amount of distribution receiving memory } / * * Write Buffer Destructor Automatic or Called from kfree_skb. * / Void Sock_WFree (Struct SK_Buff * SKB) { Struct Sock * SK = SKB-> SK; / * In case it might be waiting for more memory. * / Atomic_sub (SKB-> TRUESIZE, & SK-> WMEM_ALLOC); SK-> Write_Space (SK); Wake up the process that is waiting to write SOCK_PUT (SK); } / * * Read Buffer Destructor Automatic or Called from kfree_skb. * / Void Sock_rfree (STRUCT SK_BUFF * SKB) { Struct Sock * SK = SKB-> SK; Atomic_sub (SKB-> TRUESIZE, & SK-> RMEM_alloc); } Static Inline Long Sock_sndtimeo (Struct Sock * SK, INT Noblock) Take the timeout of the socket { RETURN NOBLOCK? 0: SK-> SNDTIMEO; } Static Inline Int Sock_ERROR (STRUCT SOCK * SK) read and reset the socket error number { INT Err = XCHG (& SK-> Err, 0); Return -ERR; } / * We do not cache source address of outgoing interface, Because it is used Only by IP RR, TS AND SRR OPTIONS, SO That it out of fast path. BTW Remember: "AddR" is allowed to be not aligned In ip options! * / Void IP_RT_GET_SOURCE (U8 * Addr, Struct RTable * RT) Recent the address of the route output device { U32 SRC; Struct Fib_Result RES; IF (rt-> key.iif == 0) SRC = RT-> RT_SRC; Else IF (Fib_lookup (& RT-> Key, & RES) == 0) { #ifdef config_ip_route_nat IF (res.type == rtn_nat) SRC = INET_SELECT_ADDR (RT-> u.dst.dev, RT-> RT_GATEWAY, RT_SCOPE_UNIVERSE); Else #ENDIF SRC = FIB_RES_PREFSRC (RES); FIB_RES_PUT (& RES); Else SRC = INET_SELECT_ADDR (RT-> u.dst.dev, RT-> RT_GATEWAY, RT_SCOPE_UNIVERSE); Memcpy (Addr, & SRC, 4); } Struct SK_Buff * Sock_alloc_send_skb (Struct Sock * SK, Unsigned long size, Unsigned long fallback, int number { Int Err; Struct SK_Buff * SKB; Long Timeo; Timeo = SOCK_SNDTIMEO (SK, NOBLOCK); Take the timeout of the socket While (1) { Unsigned long try_size = size; Err = SOCK_ERROR (SK); read and reset the error code of the socket IF (Err! = 0) Goto failure; / ** We shop send Sigpipe in these case according to * 1003.1g Draft 6.4. If we (the user) DID A Shutdown () * Call However We Should Not. * * Note: This Routine isnt Just Used for DataGrams and * Anyway Some DataGram Protocols Have a notion of * Close Down. * / Err = -EPIPE; IF (SK-> Shutdown & Send_Shutdown) Goto failure; IF (atomic_read (& Sk-> WMEM_ALLOC) If the transmission memory assigned to the socket is smaller than its transmission buffer IF (fallback) { / * The Buffer Get Won't block, or use the atomic queue. * IT Does Produce Annoying No Free Page Messages Still. * / SKB = alloc_skb (size, gfp_buffer); IF (SKB) Break; TRY_SIZE = Fallback; } SKB = alloc_skb (try_size, sk-> allocation); IF (SKB) Break; Err = -enobufs; Goto failure; } / * * This means we have to many buffers for this socket already. * / Set_bit (SOCK_ASYNC_NOSPACE, & SK-> Socket-> Flags); Set_bit (SOCK_NOSPACE, & SK-> Socket-> Flags); Err = -eagain; IF (! Timeo) Goto failure; IF (Signal_Pending (CURRENT)) Goto Interrupted; Timeo = SOCK_WAIT_FOR_WMEM (SK, TIMEO); } SKB_SET_OWNER_W (SKB, SK); Return SKB; Interrupted: Err = SOCK_INTR_ERRNO (TIMEO); Failure: * errcode = ERR; Return NULL; } / * IT is almost wait_for_tcp_memory minus release_sock / lock_sock. I Think, The Locks Should Be Removed for DataGram Sockets. * / Static Long Sock_wait_for_wmem (Struct Sock * SK, Long Timeo) Waiting for a socket to be assignable to send memory { Declare_WaitQueue (Wait, CURRENT); Clear_bit (SOCK_ASYNC_NOSPACE, & SK-> Socket-> Flags); Add_Wait_Queue (SK-> Sleep, & Wait); For (;;) { IF (Signal_Pending (CURRENT)) Break; Set_bit (SOCK_NOSPACE, & SK-> Socket-> Flags); set_current_state; Task_Interruptible IF (atomic_read (& SK-> WMEM_ALLOC) IF (SK-> Shutdown & Send_Shutdown) Break; IF (SK-> ERR) Break; Timeo = schedule_timeout (Timeo); } __set_current_state (task_running); REMOVE_WAIT_QUEUE (SK-> Sleep, & Wait); Return Timeo; } Edited by lucian_yao on 07/02/01 02:38 PM. Article Options: jiangk2001 (STRANGER) 12/302 16:43 Re: IP package generation and sending interface [Re: Opera] too exciting article options: print Flat pattern tree pattern Contact US LinuxForum.net