📄 skbuff.c
字号:
1 /*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * A saner implementation of the skbuff stuff scattered everywhere
7 * in the old NET2D code.
8 *
9 * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
10 *
11 * Fixes:
12 * Alan Cox : Tracks memory and number of buffers for kernel memory report
13 * and memory leak hunting.
14 * Alan Cox : More generic kfree handler
15 */
16
17 #include <linux/config.h>
18 #include <linux/types.h>
19 #include <linux/kernel.h>
20 #include <linux/sched.h>
21 #include <asm/segment.h>
22 #include <asm/system.h>
23 #include <linux/mm.h>
24 #include <linux/interrupt.h>
25 #include <linux/in.h>
26 #include "inet.h"
27 #include "dev.h"
28 #include "ip.h"
29 #include "protocol.h"
30 #include "arp.h"
31 #include "route.h"
32 #include "tcp.h"
33 #include "udp.h"
34 #include "skbuff.h"
35 #include "sock.h"
36
37
38 /* Socket buffer operations. Ideally much of this list swap stuff ought to be using
39 exch instructions on the 386, and CAS/CAS2 on a 68K. This is the boring generic
40 slow C version. No doubt when Linus sees this comment he'll do horrible things
41 to this code 8-)
42 */
43
44 /*
45 * Resource tracking variables
46 */
47
48 volatile unsigned long net_memory=0;
49 volatile unsigned long net_skbcount=0;
50
51 /*
52 * Debugging paranoia. Can go later when this crud stack works
53 */
54
55
56
57 void skb_check(struct sk_buff *skb, int line, char *file)
58 {
59 if(skb->magic_debug_cookie==SK_FREED_SKB)
60 {
61 printk("File: %s Line %d, found a freed skb lurking in the undergrowth!\n",
62 file,line);
63 printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n",
64 skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
65 }
66 if(skb->magic_debug_cookie!=SK_GOOD_SKB)
67 {
68 printk("File: %s Line %d, passed a non skb!\n", file,line);
69 printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n",
70 skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
71 }
72 if(skb->mem_len!=skb->truesize)
73 {
74 printk("File: %s Line %d, Dubious size setting!\n",file,line);
75 printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p\n",
76 skb,skb->truesize,skb->mem_len,skb->magic,skb->list);
77 }
78 /* Guess it might be acceptable then */
79 }
80
81 /*
82 * Insert an sk_buff at the start of a list.
83 */
84
85 void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk)
86 {
87 unsigned long flags;
88
89 IS_SKB(newsk);
90 if(newsk->list)
91 printk("Suspicious queue head: sk_buff on list!\n");
92 save_flags(flags);
93 cli();
94 newsk->list=list;
95
96 newsk->next=*list;
97
98 if(*list)
99 newsk->prev=(*list)->prev;
100 else
101 newsk->prev=newsk;
102 newsk->prev->next=newsk;
103 newsk->next->prev=newsk;
104 IS_SKB(newsk->prev);
105 IS_SKB(newsk->next);
106 *list=newsk;
107 restore_flags(flags);
108 }
109
110 /*
111 * Insert an sk_buff at the end of a list.
112 */
113
114 void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
115 {
116 unsigned long flags;
117
118 if(newsk->list)
119 printk("Suspicious queue tail: sk_buff on list!\n");
120
121 IS_SKB(newsk);
122 save_flags(flags);
123 cli();
124
125 newsk->list=list;
126 if(*list)
127 {
128 (*list)->prev->next=newsk;
129 newsk->prev=(*list)->prev;
130 newsk->next=*list;
131 (*list)->prev=newsk;
132 }
133 else
134 {
135 newsk->next=newsk;
136 newsk->prev=newsk;
137 *list=newsk;
138 }
139 IS_SKB(newsk->prev);
140 IS_SKB(newsk->next);
141 restore_flags(flags);
142
143 }
144
145 /*
146 * Remove an sk_buff from a list. This routine is also interrupt safe
147 * so you can grab read and free buffers as another process adds them.
148 */
149
150 struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
151 {
152 long flags;
153 struct sk_buff *result;
154
155 save_flags(flags);
156 cli();
157
158 if(*list==NULL)
159 {
160 restore_flags(flags);
161 return(NULL);
162 }
163
164 result=*list;
165 if(result->next==result)
166 *list=NULL;
167 else
168 {
169 result->next->prev=result->prev;
170 result->prev->next=result->next;
171 *list=result->next;
172 }
173
174 IS_SKB(result);
175 restore_flags(flags);
176
177 if(result->list!=list)
178 printk("Dequeued packet has invalid list pointer\n");
179
180 result->list=0;
181 result->next=0;
182 result->prev=0;
183 return(result);
184 }
185
186 /*
187 * Insert a packet before another one in a list.
188 */
189
190 void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
191 {
192 unsigned long flags;
193
194 IS_SKB(old);
195 IS_SKB(newsk);
196
197 if(!old->list)
198 printk("insert before unlisted item!\n");
199 if(newsk->list)
200 printk("inserted item is already on a list.\n");
201
202 save_flags(flags);
203 cli();
204 newsk->list=old->list;
205 newsk->next=old;
206 newsk->prev=old->prev;
207 newsk->next->prev=newsk;
208 newsk->prev->next=newsk;
209
210 restore_flags(flags);
211 }
212
213 /*
214 * Place a packet after a given packet in a list.
215 */
216
217 void skb_append(struct sk_buff *old, struct sk_buff *newsk)
218 {
219 unsigned long flags;
220
221 IS_SKB(old);
222 IS_SKB(newsk);
223
224 if(!old->list)
225 printk("append before unlisted item!\n");
226 if(newsk->list)
227 printk("append item is already on a list.\n");
228
229 save_flags(flags);
230 cli();
231 newsk->list=old->list;
232 newsk->prev=old;
233 newsk->next=old->next;
234 newsk->next->prev=newsk;
235 newsk->prev->next=newsk;
236
237 restore_flags(flags);
238 }
239
240 /*
241 * Remove an sk_buff from its list. Works even without knowing the list it
242 * is sitting on, which can be handy at times. It also means that THE LIST
243 * MUST EXIST when you unlink. Thus a list must have its contents unlinked
244 * _FIRST_.
245 */
246
247 void skb_unlink(struct sk_buff *skb)
248 {
249 unsigned long flags;
250 save_flags(flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -