]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /*- | |
23 | * Copyright (c) 1991, 1993 | |
24 | * The Regents of the University of California. All rights reserved. | |
25 | * | |
26 | * Redistribution and use in source and binary forms, with or without | |
27 | * modification, are permitted provided that the following conditions | |
28 | * are met: | |
29 | * 1. Redistributions of source code must retain the above copyright | |
30 | * notice, this list of conditions and the following disclaimer. | |
31 | * 2. Redistributions in binary form must reproduce the above copyright | |
32 | * notice, this list of conditions and the following disclaimer in the | |
33 | * documentation and/or other materials provided with the distribution. | |
34 | * 3. All advertising materials mentioning features or use of this software | |
35 | * must display the following acknowledgement: | |
36 | * This product includes software developed by the University of | |
37 | * California, Berkeley and its contributors. | |
38 | * 4. Neither the name of the University nor the names of its contributors | |
39 | * may be used to endorse or promote products derived from this software | |
40 | * without specific prior written permission. | |
41 | * | |
42 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
43 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
44 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
45 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
46 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
47 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
48 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
49 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
50 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
51 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
52 | * SUCH DAMAGE. | |
53 | * | |
54 | * @(#)clnp_frag.c 8.1 (Berkeley) 6/10/93 | |
55 | */ | |
56 | ||
57 | /*********************************************************** | |
58 | Copyright IBM Corporation 1987 | |
59 | ||
60 | All Rights Reserved | |
61 | ||
62 | Permission to use, copy, modify, and distribute this software and its | |
63 | documentation for any purpose and without fee is hereby granted, | |
64 | provided that the above copyright notice appear in all copies and that | |
65 | both that copyright notice and this permission notice appear in | |
66 | supporting documentation, and that the name of IBM not be | |
67 | used in advertising or publicity pertaining to distribution of the | |
68 | software without specific, written prior permission. | |
69 | ||
70 | IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
71 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
72 | IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
73 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
74 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
75 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
76 | SOFTWARE. | |
77 | ||
78 | ******************************************************************/ | |
79 | ||
80 | /* | |
81 | * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison | |
82 | */ | |
83 | ||
84 | #include <sys/param.h> | |
85 | #include <sys/systm.h> | |
86 | #include <sys/mbuf.h> | |
87 | #include <sys/domain.h> | |
88 | #include <sys/protosw.h> | |
89 | #include <sys/socket.h> | |
90 | #include <sys/socketvar.h> | |
91 | #include <sys/errno.h> | |
92 | ||
93 | #include <net/if.h> | |
94 | #include <net/route.h> | |
95 | ||
96 | #include <netiso/iso.h> | |
97 | #include <netiso/iso_var.h> | |
98 | #include <netiso/clnp.h> | |
99 | #include <netiso/clnp_stat.h> | |
100 | #include <netiso/argo_debug.h> | |
101 | ||
102 | /* all fragments are hung off this list */ | |
103 | struct clnp_fragl *clnp_frags = NULL; | |
104 | ||
105 | struct mbuf *clnp_comp_pdu(); | |
106 | ||
107 | ||
108 | /* | |
109 | * FUNCTION: clnp_fragment | |
110 | * | |
111 | * PURPOSE: Fragment a datagram, and send the itty bitty pieces | |
112 | * out over an interface. | |
113 | * | |
114 | * RETURNS: success - 0 | |
115 | * failure - unix error code | |
116 | * | |
117 | * SIDE EFFECTS: | |
118 | * | |
119 | * NOTES: If there is an error sending the packet, clnp_discard | |
120 | * is called to discard the packet and send an ER. If | |
121 | * clnp_fragment was called from clnp_output, then | |
122 | * we generated the packet, and should not send an | |
123 | * ER -- clnp_emit_er will check for this. Otherwise, | |
124 | * the packet was fragmented during forwarding. In this | |
125 | * case, we ought to send an ER back. | |
126 | */ | |
127 | clnp_fragment(ifp, m, first_hop, total_len, segoff, flags, rt) | |
128 | struct ifnet *ifp; /* ptr to outgoing interface */ | |
129 | struct mbuf *m; /* ptr to packet */ | |
130 | struct sockaddr *first_hop; /* ptr to first hop */ | |
131 | int total_len; /* length of datagram */ | |
132 | int segoff; /* offset of segpart in hdr */ | |
133 | int flags; /* flags passed to clnp_output */ | |
134 | struct rtentry *rt; /* route if direct ether */ | |
135 | { | |
136 | struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); | |
137 | int hdr_len = (int)clnp->cnf_hdr_len; | |
138 | int frag_size = (SN_MTU(ifp, rt) - hdr_len) & ~7; | |
139 | ||
140 | total_len -= hdr_len; | |
141 | if ((clnp->cnf_type & CNF_SEG_OK) && | |
142 | (total_len >= 8) && | |
143 | (frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) { | |
144 | ||
145 | struct mbuf *hdr = NULL; /* save copy of clnp hdr */ | |
146 | struct mbuf *frag_hdr = NULL; | |
147 | struct mbuf *frag_data = NULL; | |
148 | struct clnp_segment seg_part; /* segmentation header */ | |
149 | int frag_base; | |
150 | int error = 0; | |
151 | ||
152 | ||
153 | INCSTAT(cns_fragmented); | |
154 | (void) bcopy(segoff + mtod(m, caddr_t), (caddr_t)&seg_part, | |
155 | sizeof(seg_part)); | |
156 | frag_base = ntohs(seg_part.cng_off); | |
157 | /* | |
158 | * Duplicate header, and remove from packet | |
159 | */ | |
160 | if ((hdr = m_copy(m, 0, hdr_len)) == NULL) { | |
161 | clnp_discard(m, GEN_CONGEST); | |
162 | return(ENOBUFS); | |
163 | } | |
164 | m_adj(m, hdr_len); | |
165 | ||
166 | while (total_len > 0) { | |
167 | int remaining, last_frag; | |
168 | ||
169 | IFDEBUG(D_FRAG) | |
170 | struct mbuf *mdump = frag_hdr; | |
171 | int tot_mlen = 0; | |
172 | printf("clnp_fragment: total_len %d:\n", total_len); | |
173 | while (mdump != NULL) { | |
174 | printf("\tmbuf x%x, m_len %d\n", | |
175 | mdump, mdump->m_len); | |
176 | tot_mlen += mdump->m_len; | |
177 | mdump = mdump->m_next; | |
178 | } | |
179 | printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen); | |
180 | ENDDEBUG | |
181 | ||
182 | frag_size = min(total_len, frag_size); | |
183 | if ((remaining = total_len - frag_size) == 0) | |
184 | last_frag = 1; | |
185 | else { | |
186 | /* | |
187 | * If this fragment will cause the last one to | |
188 | * be less than 8 bytes, shorten this fragment a bit. | |
189 | * The obscure test on frag_size above ensures that | |
190 | * frag_size will be positive. | |
191 | */ | |
192 | last_frag = 0; | |
193 | if (remaining < 8) | |
194 | frag_size -= 8; | |
195 | } | |
196 | ||
197 | ||
198 | IFDEBUG(D_FRAG) | |
199 | printf("clnp_fragment: seg off %d, size %d, remaining %d\n", | |
200 | ntohs(seg_part.cng_off), frag_size, total_len-frag_size); | |
201 | if (last_frag) | |
202 | printf("clnp_fragment: last fragment\n"); | |
203 | ENDDEBUG | |
204 | ||
205 | if (last_frag) { | |
206 | /* | |
207 | * this is the last fragment; we don't need to get any other | |
208 | * mbufs. | |
209 | */ | |
210 | frag_hdr = hdr; | |
211 | frag_data = m; | |
212 | } else { | |
213 | /* duplicate header and data mbufs */ | |
214 | if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) { | |
215 | clnp_discard(hdr, GEN_CONGEST); | |
216 | m_freem(m); | |
217 | return(ENOBUFS); | |
218 | } | |
219 | if ((frag_data = m_copy(m, 0, frag_size)) == NULL) { | |
220 | clnp_discard(hdr, GEN_CONGEST); | |
221 | m_freem(m); | |
222 | m_freem(frag_hdr); | |
223 | return(ENOBUFS); | |
224 | } | |
225 | INCSTAT(cns_fragments); | |
226 | } | |
227 | clnp = mtod(frag_hdr, struct clnp_fixed *); | |
228 | ||
229 | if (!last_frag) | |
230 | clnp->cnf_type |= CNF_MORE_SEGS; | |
231 | ||
232 | /* link together */ | |
233 | m_cat(frag_hdr, frag_data); | |
234 | ||
235 | /* insert segmentation part; updated below */ | |
236 | bcopy((caddr_t)&seg_part, mtod(frag_hdr, caddr_t) + segoff, | |
237 | sizeof(struct clnp_segment)); | |
238 | ||
239 | { | |
240 | int derived_len = hdr_len + frag_size; | |
241 | HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len); | |
242 | if ((frag_hdr->m_flags & M_PKTHDR) == 0) | |
243 | panic("clnp_frag:lost header"); | |
244 | frag_hdr->m_pkthdr.len = derived_len; | |
245 | } | |
246 | /* compute clnp checksum (on header only) */ | |
247 | if (flags & CLNP_NO_CKSUM) { | |
248 | HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); | |
249 | } else { | |
250 | iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len); | |
251 | } | |
252 | ||
253 | IFDEBUG(D_DUMPOUT) | |
254 | struct mbuf *mdump = frag_hdr; | |
255 | printf("clnp_fragment: sending dg:\n"); | |
256 | while (mdump != NULL) { | |
257 | printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); | |
258 | mdump = mdump->m_next; | |
259 | } | |
260 | ENDDEBUG | |
261 | ||
262 | #ifdef TROLL | |
263 | error = troll_output(ifp, frag_hdr, first_hop, rt); | |
264 | #else | |
265 | error = (*ifp->if_output)(ifp, frag_hdr, first_hop, rt); | |
266 | #endif /* TROLL */ | |
267 | ||
268 | /* | |
269 | * Tough situation: if the error occured on the last | |
270 | * fragment, we can not send an ER, as the if_output | |
271 | * routine consumed the packet. If the error occured | |
272 | * on any intermediate packets, we can send an ER | |
273 | * because we still have the original header in (m). | |
274 | */ | |
275 | if (error) { | |
276 | if (frag_hdr != hdr) { | |
277 | /* | |
278 | * The error was not on the last fragment. We must | |
279 | * free hdr and m before returning | |
280 | */ | |
281 | clnp_discard(hdr, GEN_NOREAS); | |
282 | m_freem(m); | |
283 | } | |
284 | return(error); | |
285 | } | |
286 | ||
287 | /* bump segment offset, trim data mbuf, and decrement count left */ | |
288 | #ifdef TROLL | |
289 | /* | |
290 | * Decrement frag_size by some fraction. This will cause the | |
291 | * next fragment to start 'early', thus duplicating the end | |
292 | * of the current fragment. troll.tr_dup_size controls | |
293 | * the fraction. If positive, it specifies the fraction. If | |
294 | * negative, a random fraction is used. | |
295 | */ | |
296 | if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) { | |
297 | int num_bytes = frag_size; | |
298 | ||
299 | if (trollctl.tr_dup_size > 0) | |
300 | num_bytes *= trollctl.tr_dup_size; | |
301 | else | |
302 | num_bytes *= troll_random(); | |
303 | frag_size -= num_bytes; | |
304 | } | |
305 | #endif /* TROLL */ | |
306 | total_len -= frag_size; | |
307 | if (!last_frag) { | |
308 | frag_base += frag_size; | |
309 | seg_part.cng_off = htons(frag_base); | |
310 | m_adj(m, frag_size); | |
311 | } | |
312 | } | |
313 | return(0); | |
314 | } else { | |
315 | cantfrag: | |
316 | INCSTAT(cns_cantfrag); | |
317 | clnp_discard(m, GEN_SEGNEEDED); | |
318 | return(EMSGSIZE); | |
319 | } | |
320 | } | |
321 | ||
322 | /* | |
323 | * FUNCTION: clnp_reass | |
324 | * | |
325 | * PURPOSE: Attempt to reassemble a clnp packet given the current | |
326 | * fragment. If reassembly succeeds (all the fragments | |
327 | * are present), then return a pointer to an mbuf chain | |
328 | * containing the reassembled packet. This packet will | |
329 | * appear in the mbufs as if it had just arrived in | |
330 | * one piece. | |
331 | * | |
332 | * If reassembly fails, then save this fragment and | |
333 | * return 0. | |
334 | * | |
335 | * RETURNS: Ptr to assembled packet, or 0 | |
336 | * | |
337 | * SIDE EFFECTS: | |
338 | * | |
339 | * NOTES: | |
340 | * clnp_slowtimo can not affect this code because clnpintr, and thus | |
341 | * this code, is called at a higher priority than clnp_slowtimo. | |
342 | */ | |
343 | struct mbuf * | |
344 | clnp_reass(m, src, dst, seg) | |
345 | struct mbuf *m; /* new fragment */ | |
346 | struct iso_addr *src; /* src of new fragment */ | |
347 | struct iso_addr *dst; /* dst of new fragment */ | |
348 | struct clnp_segment *seg; /* segment part of fragment header */ | |
349 | { | |
350 | register struct clnp_fragl *cfh; | |
351 | ||
352 | /* look for other fragments of this datagram */ | |
353 | for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) { | |
354 | if (seg->cng_id == cfh->cfl_id && | |
355 | iso_addrmatch1(src, &cfh->cfl_src) && | |
356 | iso_addrmatch1(dst, &cfh->cfl_dst)) { | |
357 | IFDEBUG(D_REASS) | |
358 | printf("clnp_reass: found packet\n"); | |
359 | ENDDEBUG | |
360 | /* | |
361 | * There are other fragments here already. Lets see if | |
362 | * this fragment is of any help | |
363 | */ | |
364 | clnp_insert_frag(cfh, m, seg); | |
365 | if (m = clnp_comp_pdu(cfh)) { | |
366 | register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); | |
367 | HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, | |
368 | seg->cng_tot_len); | |
369 | } | |
370 | return (m); | |
371 | } | |
372 | } | |
373 | ||
374 | IFDEBUG(D_REASS) | |
375 | printf("clnp_reass: new packet!\n"); | |
376 | ENDDEBUG | |
377 | ||
378 | /* | |
379 | * This is the first fragment. If src is not consuming too many | |
380 | * resources, then create a new fragment list and add | |
381 | * this fragment to the list. | |
382 | */ | |
383 | /* TODO: don't let one src hog all the reassembly buffers */ | |
384 | if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) { | |
385 | INCSTAT(cns_fragdropped); | |
386 | clnp_discard(m, GEN_CONGEST); | |
387 | } | |
388 | ||
389 | return(NULL); | |
390 | } | |
391 | ||
392 | /* | |
393 | * FUNCTION: clnp_newpkt | |
394 | * | |
395 | * PURPOSE: Create the necessary structures to handle a new | |
396 | * fragmented clnp packet. | |
397 | * | |
398 | * RETURNS: non-zero if it succeeds, zero if fails. | |
399 | * | |
400 | * SIDE EFFECTS: | |
401 | * | |
402 | * NOTES: Failure is only due to insufficient resources. | |
403 | */ | |
404 | clnp_newpkt(m, src, dst, seg) | |
405 | struct mbuf *m; /* new fragment */ | |
406 | struct iso_addr *src; /* src of new fragment */ | |
407 | struct iso_addr *dst; /* dst of new fragment */ | |
408 | struct clnp_segment *seg; /* segment part of fragment header */ | |
409 | { | |
410 | register struct clnp_fragl *cfh; | |
411 | register struct clnp_fixed *clnp; | |
412 | struct mbuf *m0; | |
413 | ||
414 | clnp = mtod(m, struct clnp_fixed *); | |
415 | ||
416 | /* | |
417 | * Allocate new clnp fragl structure to act as header of all fragments | |
418 | * for this datagram. | |
419 | */ | |
420 | MGET(m0, M_DONTWAIT, MT_FTABLE); | |
421 | if (m0 == NULL) { | |
422 | return (0); | |
423 | } | |
424 | cfh = mtod(m0, struct clnp_fragl *); | |
425 | ||
426 | /* | |
427 | * Duplicate the header of this fragment, and save in cfh. | |
428 | * Free m0 and return if m_copy does not succeed. | |
429 | */ | |
430 | if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) { | |
431 | m_freem(m0); | |
432 | return (0); | |
433 | } | |
434 | ||
435 | /* Fill in rest of fragl structure */ | |
436 | bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr)); | |
437 | bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr)); | |
438 | cfh->cfl_id = seg->cng_id; | |
439 | cfh->cfl_ttl = clnp->cnf_ttl; | |
440 | cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1; | |
441 | cfh->cfl_frags = NULL; | |
442 | cfh->cfl_next = NULL; | |
443 | ||
444 | /* Insert into list of packets */ | |
445 | cfh->cfl_next = clnp_frags; | |
446 | clnp_frags = cfh; | |
447 | ||
448 | /* Insert this fragment into list headed by cfh */ | |
449 | clnp_insert_frag(cfh, m, seg); | |
450 | return(1); | |
451 | } | |
452 | ||
453 | /* | |
454 | * FUNCTION: clnp_insert_frag | |
455 | * | |
456 | * PURPOSE: Insert fragment into list headed by 'cf'. | |
457 | * | |
458 | * RETURNS: nothing | |
459 | * | |
460 | * SIDE EFFECTS: | |
461 | * | |
462 | * NOTES: This is the 'guts' of the reassembly algorithm. | |
463 | * Each fragment in this list contains a clnp_frag | |
464 | * structure followed by the data of the fragment. | |
465 | * The clnp_frag structure actually lies on top of | |
466 | * part of the old clnp header. | |
467 | */ | |
468 | clnp_insert_frag(cfh, m, seg) | |
469 | struct clnp_fragl *cfh; /* header of list of packet fragments */ | |
470 | struct mbuf *m; /* new fragment */ | |
471 | struct clnp_segment *seg; /* segment part of fragment header */ | |
472 | { | |
473 | register struct clnp_fixed *clnp; /* clnp hdr of fragment */ | |
474 | register struct clnp_frag *cf; /* generic fragment ptr */ | |
475 | register struct clnp_frag *cf_sub = NULL; /* frag subsequent to new one */ | |
476 | register struct clnp_frag *cf_prev = NULL; /* frag previous to new one */ | |
477 | u_short first; /* offset of first byte of initial pdu*/ | |
478 | u_short last; /* offset of last byte of initial pdu */ | |
479 | u_short fraglen;/* length of fragment */ | |
480 | ||
481 | clnp = mtod(m, struct clnp_fixed *); | |
482 | first = seg->cng_off; | |
483 | CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen); | |
484 | fraglen -= clnp->cnf_hdr_len; | |
485 | last = (first + fraglen) - 1; | |
486 | ||
487 | IFDEBUG(D_REASS) | |
488 | printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n", | |
489 | first, last, fraglen); | |
490 | printf("clnp_insert_frag: current fragments:\n"); | |
491 | for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) { | |
492 | printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last); | |
493 | } | |
494 | ENDDEBUG | |
495 | ||
496 | if (cfh->cfl_frags != NULL) { | |
497 | /* | |
498 | * Find fragment which begins after the new one | |
499 | */ | |
500 | for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) { | |
501 | if (cf->cfr_first > first) { | |
502 | cf_sub = cf; | |
503 | break; | |
504 | } | |
505 | } | |
506 | ||
507 | IFDEBUG(D_REASS) | |
508 | printf("clnp_insert_frag: Previous frag is "); | |
509 | if (cf_prev == NULL) | |
510 | printf("NULL\n"); | |
511 | else | |
512 | printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last); | |
513 | printf("clnp_insert_frag: Subsequent frag is "); | |
514 | if (cf_sub == NULL) | |
515 | printf("NULL\n"); | |
516 | else | |
517 | printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last); | |
518 | ENDDEBUG | |
519 | ||
520 | /* | |
521 | * If there is a fragment before the new one, check if it | |
522 | * overlaps the new one. If so, then trim the end of the | |
523 | * previous one. | |
524 | */ | |
525 | if (cf_prev != NULL) { | |
526 | if (cf_prev->cfr_last > first) { | |
527 | u_short overlap = cf_prev->cfr_last - first; | |
528 | ||
529 | IFDEBUG(D_REASS) | |
530 | printf("clnp_insert_frag: previous overlaps by %d\n", | |
531 | overlap); | |
532 | ENDDEBUG | |
533 | ||
534 | if (overlap > fraglen) { | |
535 | /* | |
536 | * The new fragment is entirely contained in the | |
537 | * preceeding one. We can punt on the new frag | |
538 | * completely. | |
539 | */ | |
540 | m_freem(m); | |
541 | return; | |
542 | } else { | |
543 | /* Trim data off of end of previous fragment */ | |
544 | /* inc overlap to prevent duplication of last byte */ | |
545 | overlap++; | |
546 | m_adj(cf_prev->cfr_data, -(int)overlap); | |
547 | cf_prev->cfr_last -= overlap; | |
548 | } | |
549 | } | |
550 | } | |
551 | ||
552 | /* | |
553 | * For all fragments past the new one, check if any data on | |
554 | * the new one overlaps data on existing fragments. If so, | |
555 | * then trim the extra data off the end of the new one. | |
556 | */ | |
557 | for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) { | |
558 | if (cf->cfr_first < last) { | |
559 | u_short overlap = last - cf->cfr_first; | |
560 | ||
561 | IFDEBUG(D_REASS) | |
562 | printf("clnp_insert_frag: subsequent overlaps by %d\n", | |
563 | overlap); | |
564 | ENDDEBUG | |
565 | ||
566 | if (overlap > fraglen) { | |
567 | /* | |
568 | * The new fragment is entirely contained in the | |
569 | * succeeding one. This should not happen, because | |
570 | * early on in this code we scanned for the fragment | |
571 | * which started after the new one! | |
572 | */ | |
573 | m_freem(m); | |
574 | printf("clnp_insert_frag: internal error!\n"); | |
575 | return; | |
576 | } else { | |
577 | /* Trim data off of end of new fragment */ | |
578 | /* inc overlap to prevent duplication of last byte */ | |
579 | overlap++; | |
580 | m_adj(m, -(int)overlap); | |
581 | last -= overlap; | |
582 | } | |
583 | } | |
584 | } | |
585 | } | |
586 | ||
587 | /* | |
588 | * Insert the new fragment beween cf_prev and cf_sub | |
589 | * | |
590 | * Note: the clnp hdr is still in the mbuf. | |
591 | * If the data of the mbuf is not word aligned, shave off enough | |
592 | * so that it is. Then, cast the clnp_frag structure on top | |
593 | * of the clnp header. | |
594 | * The clnp_hdr will not be used again (as we already have | |
595 | * saved a copy of it). | |
596 | * | |
597 | * Save in cfr_bytes the number of bytes to shave off to get to | |
598 | * the data of the packet. This is used when we coalesce fragments; | |
599 | * the clnp_frag structure must be removed before joining mbufs. | |
600 | */ | |
601 | { | |
602 | int pad; | |
603 | u_int bytes; | |
604 | ||
605 | /* determine if header is not word aligned */ | |
606 | pad = (int)clnp % 4; | |
607 | if (pad < 0) | |
608 | pad = -pad; | |
609 | ||
610 | /* bytes is number of bytes left in front of data */ | |
611 | bytes = clnp->cnf_hdr_len - pad; | |
612 | ||
613 | IFDEBUG(D_REASS) | |
614 | printf("clnp_insert_frag: clnp x%x requires %d alignment\n", | |
615 | clnp, pad); | |
616 | ENDDEBUG | |
617 | ||
618 | /* make it word aligned if necessary */ | |
619 | if (pad) | |
620 | m_adj(m, pad); | |
621 | ||
622 | cf = mtod(m, struct clnp_frag *); | |
623 | cf->cfr_bytes = bytes; | |
624 | ||
625 | IFDEBUG(D_REASS) | |
626 | printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf, | |
627 | cf->cfr_bytes); | |
628 | ENDDEBUG | |
629 | } | |
630 | cf->cfr_first = first; | |
631 | cf->cfr_last = last; | |
632 | ||
633 | ||
634 | /* | |
635 | * The data is the mbuf itself, although we must remember that the | |
636 | * first few bytes are actually a clnp_frag structure | |
637 | */ | |
638 | cf->cfr_data = m; | |
639 | ||
640 | /* link into place */ | |
641 | cf->cfr_next = cf_sub; | |
642 | if (cf_prev == NULL) | |
643 | cfh->cfl_frags = cf; | |
644 | else | |
645 | cf_prev->cfr_next = cf; | |
646 | } | |
647 | ||
648 | /* | |
649 | * FUNCTION: clnp_comp_pdu | |
650 | * | |
651 | * PURPOSE: Scan the list of fragments headed by cfh. Merge | |
652 | * any contigious fragments into one. If, after | |
653 | * traversing all the fragments, it is determined that | |
654 | * the packet is complete, then return a pointer to | |
655 | * the packet (with header prepended). Otherwise, | |
656 | * return NULL. | |
657 | * | |
658 | * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf chain. | |
659 | * | |
660 | * SIDE EFFECTS: Will colapse contigious fragments into one. | |
661 | * | |
662 | * NOTES: This code assumes that there are no overlaps of | |
663 | * fragment pdus. | |
664 | */ | |
665 | struct mbuf * | |
666 | clnp_comp_pdu(cfh) | |
667 | struct clnp_fragl *cfh; /* fragment header */ | |
668 | { | |
669 | register struct clnp_frag *cf = cfh->cfl_frags; | |
670 | ||
671 | while (cf->cfr_next != NULL) { | |
672 | register struct clnp_frag *cf_next = cf->cfr_next; | |
673 | ||
674 | IFDEBUG(D_REASS) | |
675 | printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n", | |
676 | cf->cfr_first, cf->cfr_last, cf_next->cfr_first, | |
677 | cf_next->cfr_last); | |
678 | ENDDEBUG | |
679 | ||
680 | if (cf->cfr_last == (cf_next->cfr_first - 1)) { | |
681 | /* | |
682 | * Merge fragment cf and cf_next | |
683 | * | |
684 | * - update cf header | |
685 | * - trim clnp_frag structure off of cf_next | |
686 | * - append cf_next to cf | |
687 | */ | |
688 | struct clnp_frag cf_next_hdr; | |
689 | struct clnp_frag *next_frag; | |
690 | ||
691 | cf_next_hdr = *cf_next; | |
692 | next_frag = cf_next->cfr_next; | |
693 | ||
694 | IFDEBUG(D_REASS) | |
695 | struct mbuf *mdump; | |
696 | int l; | |
697 | printf("clnp_comp_pdu: merging fragments\n"); | |
698 | printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n", | |
699 | cf->cfr_first, cf->cfr_last, cf->cfr_bytes); | |
700 | mdump = cf->cfr_data; | |
701 | l = 0; | |
702 | while (mdump != NULL) { | |
703 | printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); | |
704 | l += mdump->m_len; | |
705 | mdump = mdump->m_next; | |
706 | } | |
707 | printf("\ttotal len: %d\n", l); | |
708 | printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n", | |
709 | cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes); | |
710 | mdump = cf_next->cfr_data; | |
711 | l = 0; | |
712 | while (mdump != NULL) { | |
713 | printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); | |
714 | l += mdump->m_len; | |
715 | mdump = mdump->m_next; | |
716 | } | |
717 | printf("\ttotal len: %d\n", l); | |
718 | ENDDEBUG | |
719 | ||
720 | cf->cfr_last = cf_next->cfr_last; | |
721 | /* | |
722 | * After this m_adj, the cf_next ptr is useless because we | |
723 | * have adjusted the clnp_frag structure away... | |
724 | */ | |
725 | IFDEBUG(D_REASS) | |
726 | printf("clnp_comp_pdu: shaving off %d bytes\n", | |
727 | cf_next_hdr.cfr_bytes); | |
728 | ENDDEBUG | |
729 | m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes); | |
730 | m_cat(cf->cfr_data, cf_next_hdr.cfr_data); | |
731 | cf->cfr_next = next_frag; | |
732 | } else { | |
733 | cf = cf->cfr_next; | |
734 | } | |
735 | } | |
736 | ||
737 | cf = cfh->cfl_frags; | |
738 | ||
739 | IFDEBUG(D_REASS) | |
740 | struct mbuf *mdump = cf->cfr_data; | |
741 | printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first, | |
742 | cf->cfr_last); | |
743 | printf("clnp_comp_pdu: data for frag:\n"); | |
744 | while (mdump != NULL) { | |
745 | printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); | |
746 | /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ | |
747 | mdump = mdump->m_next; | |
748 | } | |
749 | ENDDEBUG | |
750 | ||
751 | /* Check if datagram is complete */ | |
752 | if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) { | |
753 | /* | |
754 | * We have a complete pdu! | |
755 | * - Remove the frag header from (only) remaining fragment | |
756 | * (which is not really a fragment anymore, as the datagram is | |
757 | * complete). | |
758 | * - Prepend a clnp header | |
759 | */ | |
760 | struct mbuf *data = cf->cfr_data; | |
761 | struct mbuf *hdr = cfh->cfl_orighdr; | |
762 | struct clnp_fragl *scan; | |
763 | ||
764 | IFDEBUG(D_REASS) | |
765 | printf("clnp_comp_pdu: complete pdu!\n"); | |
766 | ENDDEBUG | |
767 | ||
768 | m_adj(data, (int)cf->cfr_bytes); | |
769 | m_cat(hdr, data); | |
770 | ||
771 | IFDEBUG(D_DUMPIN) | |
772 | struct mbuf *mdump = hdr; | |
773 | printf("clnp_comp_pdu: pdu is:\n"); | |
774 | while (mdump != NULL) { | |
775 | printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); | |
776 | /* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ | |
777 | mdump = mdump->m_next; | |
778 | } | |
779 | ENDDEBUG | |
780 | ||
781 | /* | |
782 | * Remove cfh from the list of fragmented pdus | |
783 | */ | |
784 | if (clnp_frags == cfh) { | |
785 | clnp_frags = cfh->cfl_next; | |
786 | } else { | |
787 | for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { | |
788 | if (scan->cfl_next == cfh) { | |
789 | scan->cfl_next = cfh->cfl_next; | |
790 | break; | |
791 | } | |
792 | } | |
793 | } | |
794 | ||
795 | /* free cfh */ | |
796 | m_freem(dtom(cfh)); | |
797 | ||
798 | return(hdr); | |
799 | } | |
800 | ||
801 | return(NULL); | |
802 | } | |
803 | #ifdef TROLL | |
804 | static int troll_cnt; | |
805 | #include <sys/time.h> | |
806 | /* | |
807 | * FUNCTION: troll_random | |
808 | * | |
809 | * PURPOSE: generate a pseudo-random number between 0 and 1 | |
810 | * | |
811 | * RETURNS: the random number | |
812 | * | |
813 | * SIDE EFFECTS: | |
814 | * | |
815 | * NOTES: This is based on the clock. | |
816 | */ | |
817 | float troll_random() | |
818 | { | |
819 | extern struct timeval time; | |
820 | long t = time.tv_usec % 100; | |
821 | ||
822 | return((float)t / (float) 100); | |
823 | } | |
824 | ||
825 | /* | |
826 | * FUNCTION: troll_output | |
827 | * | |
828 | * PURPOSE: Do something sneaky with the datagram passed. Possible | |
829 | * operations are: | |
830 | * Duplicate the packet | |
831 | * Drop the packet | |
832 | * Trim some number of bytes from the packet | |
833 | * Munge some byte in the packet | |
834 | * | |
835 | * RETURNS: 0, or unix error code | |
836 | * | |
837 | * SIDE EFFECTS: | |
838 | * | |
839 | * NOTES: The operation of this procedure is regulated by the | |
840 | * troll control structure (Troll). | |
841 | */ | |
842 | troll_output(ifp, m, dst, rt) | |
843 | struct ifnet *ifp; | |
844 | struct mbuf *m; | |
845 | struct sockaddr *dst; | |
846 | struct rtentry *rt; | |
847 | { | |
848 | int err = 0; | |
849 | troll_cnt++; | |
850 | ||
851 | if (trollctl.tr_ops & TR_DUPPKT) { | |
852 | /* | |
853 | * Duplicate every Nth packet | |
854 | * TODO: random? | |
855 | */ | |
856 | float f_freq = troll_cnt * trollctl.tr_dup_freq; | |
857 | int i_freq = troll_cnt * trollctl.tr_dup_freq; | |
858 | if (i_freq == f_freq) { | |
859 | struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL); | |
860 | if (dup != NULL) | |
861 | err = (*ifp->if_output)(ifp, dup, dst, rt); | |
862 | } | |
863 | if (!err) | |
864 | err = (*ifp->if_output)(ifp, m, dst, rt); | |
865 | return(err); | |
866 | } else if (trollctl.tr_ops & TR_DROPPKT) { | |
867 | } else if (trollctl.tr_ops & TR_CHANGE) { | |
868 | struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); | |
869 | clnp->cnf_cksum_msb = 0; | |
870 | err = (*ifp->if_output)(ifp, m, dst, rt); | |
871 | return(err); | |
872 | } else { | |
873 | err = (*ifp->if_output)(ifp, m, dst, rt); | |
874 | return(err); | |
875 | } | |
876 | } | |
877 | ||
878 | #endif /* TROLL */ |