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