Generation and transmission interface of IP package

xiaoxiao2021-03-06  76

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

print

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) hard_header_len && dev-> hard_header) {If the package available hardware frame header is insufficient

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) SNDBUF) {

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) SNDBUF) BREAK;

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

转载请注明原文地址:https://www.9cbs.com/read-109641.html

New Post(0)