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