]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/mip6_io.c
739a1177f35cec10f48833b48e2819d9515bd6dc
1 /* $KAME: mip6_io.c,v 1.7 2000/03/25 07:23:53 sumikawa Exp $ */
4 * Copyright (C) 1995, 1996, 1997, 1998, 1999 and 2000 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * Copyright (c) 1999 and 2000 Ericsson Radio Systems AB
34 * All rights reserved.
36 * Author: Conny Larsson <conny.larsson@era.ericsson.se>
40 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/malloc.h>
48 #include <sys/domain.h>
49 #include <sys/protosw.h>
50 #include <sys/socket.h>
51 #include <sys/errno.h>
53 #include <sys/kernel.h>
55 #include <net/if_types.h>
56 #include <net/route.h>
57 #include <netinet/in.h>
58 #include <netinet/in_var.h>
59 #include <netinet/ip6.h>
60 #include <netinet6/ip6_var.h>
61 #include <netinet/icmp6.h>
62 #include <netinet6/mip6.h>
63 #include <netinet6/mip6_common.h>
66 void (*mip6_icmp6_output_hook
)(struct mbuf
*) = 0;
67 struct mip6_esm
* (*mip6_esm_find_hook
)(struct in6_addr
*) = 0;
70 /* Declaration of Global variables. */
71 struct mip6_indata
*mip6_inp
= NULL
;
72 struct mip6_output
*mip6_outq
= NULL
;
77 ##############################################################################
80 # These functions receives the incoming IPv6 packet and further processing of
81 # the packet depends on the content in the packet.
83 ##############################################################################
87 ******************************************************************************
88 * Function: mip6_new_packet
89 * Description: Called once when a new IPv6 packet is received. Resets the
90 * mip6_inp variable needed later when options in the dest-
91 * ination header are validated.
92 * Ret value: 0 if OK. Otherwise IPPROTO_DONE.
93 * Note: A prerequisite for this function is that the AH or ESP header
94 * is included in the same IPv6 packet as the destination header,
95 * i.e we are using transport mode and not tunneling mode.
96 ******************************************************************************
100 struct mbuf
*m
; /* Mbuf containing IPv6 header */
102 /* If memory for global variable mip6_indata already allocated,
104 if (mip6_inp
!= NULL
) {
105 if (mip6_inp
->bu_opt
!= NULL
)
106 FREE(mip6_inp
->bu_opt
, M_TEMP
);
107 if (mip6_inp
->ba_opt
!= NULL
)
108 FREE(mip6_inp
->ba_opt
, M_TEMP
);
109 if (mip6_inp
->br_opt
!= NULL
)
110 FREE(mip6_inp
->br_opt
, M_TEMP
);
111 if (mip6_inp
->ha_opt
!= NULL
)
112 FREE(mip6_inp
->ha_opt
, M_TEMP
);
113 if (mip6_inp
->uid
!= NULL
)
114 FREE(mip6_inp
->uid
, M_TEMP
);
115 if (mip6_inp
->coa
!= NULL
)
116 FREE(mip6_inp
->coa
, M_TEMP
);
117 if (mip6_inp
->hal
!= NULL
)
118 FREE(mip6_inp
->hal
, M_TEMP
);
119 FREE(mip6_inp
, M_TEMP
);
123 /* Allocate memory for global variable mip6_inp */
124 mip6_inp
= (struct mip6_indata
*)
125 MALLOC(sizeof(struct mip6_indata
), M_TEMP
, M_WAITOK
);
126 if (mip6_inp
== NULL
)
127 panic("%s: We should not come here !!!!", __FUNCTION__
);
128 bzero(mip6_inp
, sizeof(struct mip6_indata
));
136 ******************************************************************************
137 * Function: mip6_store_dstopt_pre
138 * Description: Pre-processing used by the hook function.
139 * Ret value: 0 if OK. Otherwise IPPROTO_DONE
140 ******************************************************************************
143 mip6_store_dstopt_pre(m
, opt
, off
, dstlen
)
144 struct mbuf
*m
; /* Pointer to the beginning of mbuf */
145 u_int8_t
*opt
; /* Pointer to the beginning of current option in mbuf */
146 u_int8_t off
; /* Offset from beginning of mbuf to end of dest header */
147 u_int8_t dstlen
; /* Remaining length of Destination header */
149 u_int8_t type
; /* Destination option type */
152 if (type
== IP6OPT_BINDING_UPDATE
) {
153 if (dstlen
< IP6OPT_BUMINLEN
) {
154 ip6stat
.ip6s_toosmall
++;
158 if (mip6_store_dstopt(m
, opt
, off
-dstlen
) != 0)
160 } else if (type
== IP6OPT_BINDING_ACK
) {
161 if (dstlen
< IP6OPT_BAMINLEN
) {
162 ip6stat
.ip6s_toosmall
++;
166 if (mip6_store_dstopt(m
, opt
, off
-dstlen
) != 0)
168 } else if (type
== IP6OPT_BINDING_REQ
) {
169 if (dstlen
< IP6OPT_BRMINLEN
) {
170 ip6stat
.ip6s_toosmall
++;
174 if (mip6_store_dstopt(m
, opt
, off
-dstlen
) != 0)
176 } else if (type
== IP6OPT_HOME_ADDRESS
) {
177 if (dstlen
< IP6OPT_HAMINLEN
) {
178 ip6stat
.ip6s_toosmall
++;
182 if (mip6_store_dstopt(m
, opt
, off
-dstlen
) != 0)
192 ******************************************************************************
193 * Function: mip6_store_dstopt
194 * Description: Save each MIPv6 option from the Destination header continously.
195 * They will be evaluated when the entire destination header has
198 * Otherwise protocol error code from netinet/in.h
199 ******************************************************************************
202 mip6_store_dstopt(mp
, opt
, optoff
)
203 struct mbuf
*mp
; /* Pointer to the beginning of mbuf */
204 u_int8_t
*opt
; /* Pointer to the beginning of current option in mbuf */
205 u_int8_t optoff
; /* Offset from beginning of mbuf to start of current
208 struct mip6_opt_bu
*bu_opt
; /* Ptr to BU option data */
209 struct mip6_opt_ba
*ba_opt
; /* Ptr to BA option data */
210 struct mip6_opt_br
*br_opt
; /* Ptr to BR option data */
211 struct mip6_opt_ha
*ha_opt
; /* Ptr to HA option data */
212 int tmplen
; /* Tmp length for positioning in option */
213 int totlen
; /* Total length of option + sub-option */
216 /* Find out what kind of buffer we are dealing with */
218 case IP6OPT_BINDING_UPDATE
:
219 /* Allocate and store Binding Update option data */
220 mip6_inp
->bu_opt
= (struct mip6_opt_bu
*)
221 MALLOC(sizeof(struct mip6_opt_bu
), M_TEMP
, M_WAITOK
);
222 if (mip6_inp
->bu_opt
== NULL
)
224 bzero(mip6_inp
->bu_opt
, sizeof(struct mip6_opt_bu
));
226 bu_opt
= mip6_inp
->bu_opt
;
227 m_copydata(mp
, optoff
, sizeof(bu_opt
->type
),
228 (caddr_t
)&bu_opt
->type
);
229 tmplen
= sizeof(bu_opt
->type
);
230 m_copydata(mp
, optoff
+ tmplen
, sizeof(bu_opt
->len
),
231 (caddr_t
)&bu_opt
->len
);
232 tmplen
+= sizeof(bu_opt
->len
);
233 m_copydata(mp
, optoff
+ tmplen
, sizeof(bu_opt
->flags
),
234 (caddr_t
)&bu_opt
->flags
);
235 tmplen
+= sizeof(bu_opt
->flags
);
236 m_copydata(mp
, optoff
+ tmplen
, sizeof(bu_opt
->prefix_len
),
237 (caddr_t
)&bu_opt
->prefix_len
);
238 tmplen
+= sizeof(bu_opt
->prefix_len
);
239 m_copydata(mp
, optoff
+ tmplen
, sizeof(bu_opt
->seqno
),
240 (caddr_t
)&bu_opt
->seqno
);
241 tmplen
+= sizeof(bu_opt
->seqno
);
242 m_copydata(mp
, optoff
+ tmplen
, sizeof(bu_opt
->lifetime
),
243 (caddr_t
)&bu_opt
->lifetime
);
244 tmplen
+= sizeof(bu_opt
->lifetime
);
246 bu_opt
->seqno
= ntohs(bu_opt
->seqno
);
247 bu_opt
->lifetime
= ntohl(bu_opt
->lifetime
);
249 /* Set the BU option present flag */
250 mip6_inp
->optflag
|= MIP6_DSTOPT_BU
;
252 /* If sub-options are present, store them as well. */
253 if (bu_opt
->len
> IP6OPT_BULEN
) {
254 totlen
= bu_opt
->len
+ 2;
255 error
= mip6_store_dstsubopt(mp
, opt
, optoff
, totlen
, tmplen
);
260 case IP6OPT_BINDING_ACK
:
261 /* Allocate and store all Binding Acknowledgement option data */
262 mip6_inp
->ba_opt
= (struct mip6_opt_ba
*)
263 MALLOC(sizeof(struct mip6_opt_ba
), M_TEMP
, M_WAITOK
);
264 if (mip6_inp
->ba_opt
== NULL
)
266 bzero(mip6_inp
->ba_opt
, sizeof(struct mip6_opt_ba
));
268 ba_opt
= mip6_inp
->ba_opt
;
269 m_copydata(mp
, optoff
, sizeof(ba_opt
->type
),
270 (caddr_t
)&ba_opt
->type
);
271 tmplen
= sizeof(ba_opt
->type
);
272 m_copydata(mp
, optoff
+ tmplen
, sizeof(ba_opt
->len
),
273 (caddr_t
)&ba_opt
->len
);
274 tmplen
+= sizeof(ba_opt
->len
);
275 m_copydata(mp
, optoff
+ tmplen
, sizeof(ba_opt
->status
),
276 (caddr_t
)&ba_opt
->status
);
277 tmplen
+= sizeof(ba_opt
->status
);
278 m_copydata(mp
, optoff
+ tmplen
, sizeof(ba_opt
->seqno
),
279 (caddr_t
)&ba_opt
->seqno
);
280 tmplen
+= sizeof(ba_opt
->seqno
);
281 m_copydata(mp
, optoff
+ tmplen
, sizeof(ba_opt
->lifetime
),
282 (caddr_t
)&ba_opt
->lifetime
);
283 tmplen
+= sizeof(ba_opt
->lifetime
);
284 m_copydata(mp
, optoff
+ tmplen
, sizeof(ba_opt
->refresh
),
285 (caddr_t
)&ba_opt
->refresh
);
286 tmplen
+= sizeof(ba_opt
->refresh
);
288 ba_opt
->seqno
= ntohs(ba_opt
->seqno
);
289 ba_opt
->lifetime
= ntohl(ba_opt
->lifetime
);
290 ba_opt
->refresh
= ntohl(ba_opt
->refresh
);
292 /* Set the BA option present flag */
293 mip6_inp
->optflag
|= MIP6_DSTOPT_BA
;
295 /* If sub-options are present, store them as well */
296 if (ba_opt
->len
> IP6OPT_BALEN
) {
297 totlen
= ba_opt
->len
+ 2;
298 error
= mip6_store_dstsubopt(mp
, opt
, optoff
, totlen
, tmplen
);
303 case IP6OPT_BINDING_REQ
:
304 /* Allocate and store Binding Update option data */
305 mip6_inp
->br_opt
= (struct mip6_opt_br
*)
306 MALLOC(sizeof(struct mip6_opt_br
), M_TEMP
, M_WAITOK
);
307 if (mip6_inp
->br_opt
== NULL
)
309 bzero(mip6_inp
->br_opt
, sizeof(struct mip6_opt_br
));
311 br_opt
= mip6_inp
->br_opt
;
312 m_copydata(mp
, optoff
, sizeof(br_opt
->type
),
313 (caddr_t
)&br_opt
->type
);
314 tmplen
= sizeof(br_opt
->type
);
315 m_copydata(mp
, optoff
+ tmplen
, sizeof(br_opt
->len
),
316 (caddr_t
)&br_opt
->len
);
317 tmplen
+= sizeof(br_opt
->len
);
319 /* Set the BR option present flag */
320 mip6_inp
->optflag
|= MIP6_DSTOPT_BR
;
322 /* If sub-options are present, store them as well. */
323 if (br_opt
->len
> IP6OPT_BRLEN
) {
324 totlen
= br_opt
->len
+ 2;
325 error
= mip6_store_dstsubopt(mp
, opt
, optoff
, totlen
, tmplen
);
330 case IP6OPT_HOME_ADDRESS
:
331 /* Allocate and store Home Address option data */
332 mip6_inp
->ha_opt
= (struct mip6_opt_ha
*)
333 MALLOC(sizeof(struct mip6_opt_ha
), M_TEMP
, M_WAITOK
);
334 if (mip6_inp
->ha_opt
== NULL
)
336 bzero(mip6_inp
->ha_opt
, sizeof(struct mip6_opt_ha
));
338 /* Store Home Address option data */
339 ha_opt
= mip6_inp
->ha_opt
;
340 m_copydata(mp
, optoff
, sizeof(ha_opt
->type
),
341 (caddr_t
)&ha_opt
->type
);
342 tmplen
= sizeof(ha_opt
->type
);
343 m_copydata(mp
, optoff
+ tmplen
, sizeof(ha_opt
->len
),
344 (caddr_t
)&ha_opt
->len
);
345 tmplen
+= sizeof(ha_opt
->len
);
346 m_copydata(mp
, optoff
+ tmplen
, sizeof(ha_opt
->home_addr
),
347 (caddr_t
)&ha_opt
->home_addr
);
348 tmplen
+= sizeof(ha_opt
->home_addr
);
350 /* Set the HA option present flag */
351 mip6_inp
->optflag
|= MIP6_DSTOPT_HA
;
354 /* We will not come here since the calling function knows
355 which options to call this function for. */
363 ******************************************************************************
364 * Function: mip6_store_dstsubopt
365 * Description: Save each MIPv6 suboption from the Destination header.
366 * They will be evaluated when the entire destination header has
369 * Otherwise protocol error code from netinet/in.h
370 ******************************************************************************
373 mip6_store_dstsubopt(mp
, opt
, optoff
, totlen
, tmplen
)
374 struct mbuf
*mp
; /* Pointer to start of mbuf */
375 u_int8_t
*opt
; /* Pointer to start of current option in mbuf */
376 u_int8_t optoff
; /* Offset from start of mbuf to current option */
377 int totlen
; /* Total length for option + sub-options */
378 int tmplen
; /* Tmp length for positioning in option */
380 struct mip6_subopt_hal
*hal
;
381 struct mip6_subopt_coa
*coa
;
384 /* Loop over the sub-options. */
385 while (tmplen
< totlen
) {
386 switch (*(opt
+ tmplen
)) {
391 tmplen
+= *(opt
+ tmplen
+ 1) + 2;
393 case IP6SUBOPT_UNIQUEID
:
394 /* Make sure that the length is OK */
395 if (*(opt
+ tmplen
+ 1) != IP6OPT_UIDLEN
) {
400 /* Allocate and store additional sub-option data */
401 mip6_inp
->uid
= (struct mip6_subopt_id
*)
402 MALLOC(sizeof(struct mip6_subopt_id
), M_TEMP
, M_WAITOK
);
403 if (mip6_inp
->uid
== NULL
)
405 bzero(mip6_inp
->uid
, sizeof(struct mip6_subopt_id
));
407 m_copydata(mp
, optoff
+ tmplen
, sizeof(struct mip6_subopt_id
),
408 (caddr_t
)mip6_inp
->uid
);
409 tmplen
+= sizeof(struct mip6_subopt_id
);
410 mip6_inp
->uid
->id
= ntohs(mip6_inp
->uid
->id
);
412 /* Set the Unique Id sub-option present flag */
413 mip6_inp
->optflag
|= MIP6_DSTOPT_UID
;
415 case IP6SUBOPT_HALIST
:
416 /* Make sure that the length is OK */
417 if (*(opt
+ tmplen
+ 1) % IP6OPT_HALISTLEN
) {
422 /* Allocate and store additional sub-option data */
423 len
= *(opt
+ tmplen
+1) / IP6OPT_HALISTLEN
;
424 mip6_inp
->hal
= (struct mip6_subopt_hal
*)
425 MALLOC(sizeof(struct mip6_subopt_hal
) +
426 (len
- 1) * sizeof(struct in6_addr
),
428 if (mip6_inp
->hal
== NULL
) {
434 m_copydata(mp
, optoff
+ tmplen
, sizeof(hal
->type
),
435 (caddr_t
)&hal
->type
);
436 tmplen
+= sizeof(hal
->type
);
437 m_copydata(mp
, optoff
+ tmplen
, sizeof(hal
->len
),
439 tmplen
+= sizeof(hal
->len
);
441 /* Loop over the addresses */
442 for (ii
= 0; ii
< len
; ii
++) {
443 m_copydata(mp
, optoff
, tmplen
, (caddr_t
)&hal
->halist
[ii
]);
444 tmplen
+= sizeof(struct in6_addr
);
447 /* Set the BA HA List sub-option present flag */
448 mip6_inp
->optflag
|= MIP6_DSTOPT_HAL
;
450 case IP6SUBOPT_ALTCOA
:
451 /* Make sure that the length is OK */
452 if (*(opt
+ tmplen
+ 1) != IP6OPT_COALEN
) {
457 /* Allocate and store additional sub-option data */
458 mip6_inp
->coa
= (struct mip6_subopt_coa
*)
459 MALLOC(sizeof(struct mip6_subopt_coa
), M_TEMP
, M_WAITOK
);
460 if (mip6_inp
->coa
== NULL
)
462 bzero(mip6_inp
->coa
, sizeof(struct mip6_subopt_coa
));
465 m_copydata(mp
, optoff
+ tmplen
, sizeof(coa
->type
),
466 (caddr_t
)&coa
->type
);
467 tmplen
+= sizeof(coa
->type
);
468 m_copydata(mp
, optoff
+ tmplen
, sizeof(coa
->len
),
470 tmplen
+= sizeof(coa
->len
);
471 m_copydata(mp
, optoff
+ tmplen
, sizeof(coa
->coa
),
473 tmplen
+= sizeof(coa
->coa
);
475 /* Set the Alternate COA sub-option present flag */
476 mip6_inp
->optflag
|= MIP6_DSTOPT_COA
;
479 /* Quietly ignore and skip over the sub-option.
480 No statistics done. */
481 tmplen
+= *(opt
+ tmplen
+ 1) + 2;
490 ##############################################################################
493 # Functions used for processing of the outgoing IPv6 packet.
495 ##############################################################################
499 ******************************************************************************
500 * Function: mip6_output
501 * Description: This function is always called by function ip6_output. If there
502 * are any Destination Header options they will be added. A Home
503 * Address option MUST be added if the MN is roaming. Otherwise
505 * The options are stored in an output queue as a chain of mbufs
506 * associated with a destination address. This approach makes it
507 * possible to send it in any IPv6 packet carrying any payload,
510 * Otherwise any appropriate error code
511 ******************************************************************************
514 mip6_output(m
, pktopt
)
515 struct mbuf
*m
; /* Includes IPv6 header */
516 struct ip6_pktopts
**pktopt
; /* Packet Extension headers, options and data */
518 struct ip6_pktopts
*opt
; /* Packet Extension headers (local) */
519 struct mip6_output
*outp
; /* Ptr to mip6 output element */
520 struct mip6_esm
*esp
; /* Ptr to entry in event state list */
521 struct ip6_hdr
*ip6
; /* IPv6 header */
522 struct mip6_bc
*bcp
; /* Binding Cache list entry */
523 struct mip6_bul
*bulp
;
524 struct mip6_bul
*bulp_hr
;
525 struct in6_addr
*dst_addr
; /* Original dst address for the packet */
526 int error
; /* Error code from function call */
527 int off
; /* Offset from start of Destination Header in bytes */
528 u_int8_t opttype
; /* Option type */
530 ip6
= mtod(m
, struct ip6_hdr
*);
533 /* We have to maintain a list of all prefixes announced by the
534 rtadvd deamon (for on-link determination). */
535 if (MIP6_IS_HA_ACTIVE
) {
536 if (ip6
->ip6_nxt
== IPPROTO_ICMPV6
)
537 if (mip6_icmp6_output_hook
) (*mip6_icmp6_output_hook
)(m
);
540 /* If a COA for the destination address exist, i.e a BC entry is found,
541 then add a Routing Header and change the destination address to the
543 dst_addr
= &ip6
->ip6_dst
;
544 bcp
= mip6_bc_find(&ip6
->ip6_dst
);
546 dst_addr
= &bcp
->home_addr
;
547 if ((error
= mip6_add_rh(&opt
, bcp
)) != 0)
551 /* If this is a MN and the source address is one of the home addresses
552 for the MN then a Home Address option must be inserted. */
554 if (MIP6_IS_MN_ACTIVE
) {
555 if (mip6_esm_find_hook
)
556 esp
= (*mip6_esm_find_hook
)(&ip6
->ip6_src
);
558 if ((esp
!= NULL
) && (esp
->state
>= MIP6_STATE_DEREG
)) {
560 opt
= (struct ip6_pktopts
*)
561 MALLOC(sizeof(struct ip6_pktopts
), M_TEMP
, M_WAITOK
);
564 bzero(opt
, sizeof(struct ip6_pktopts
));
565 opt
->ip6po_hlim
= -1; /* -1 means to use default hop limit */
568 mip6_dest_offset(opt
->ip6po_dest2
, &off
);
569 if ((error
= mip6_add_ha(&opt
->ip6po_dest2
,
570 &off
, &ip6
->ip6_src
, &esp
->coa
)) != 0)
573 /* If the MN initiate the traffic it should add a BU option
574 to the packet if no BUL entry exist and there is a BUL
575 "home registration" entry. */
576 bulp
= mip6_bul_find(dst_addr
, &esp
->home_addr
);
577 bulp_hr
= mip6_bul_find(NULL
, &esp
->home_addr
);
578 if ((bulp
== NULL
) && (bulp_hr
!= NULL
)) {
579 /* Create BUL entry and BU option. */
580 bulp
= mip6_bul_create(dst_addr
, &esp
->home_addr
,
582 bulp_hr
->lifetime
, 0);
585 mip6_queue_bu(bulp
, &esp
->home_addr
, &esp
->coa
, 0,
591 /* BU, BR and BA should not be sent to link-local, loop-back and
592 multicast addresses. */
593 if (IN6_IS_ADDR_LINKLOCAL(dst_addr
) || IN6_IS_ADDR_LOOPBACK(dst_addr
) ||
594 IN6_IS_ADDR_MULTICAST(dst_addr
)) {
599 /* If the packet has not been generated completely by MIP6 the
600 output queue is searched. */
602 if (mip6_config
.enable_outq
) {
603 for (outp
= mip6_outq
; outp
; outp
= outp
->next
) {
604 if ((outp
->flag
== NOT_SENT
) &&
605 (IN6_ARE_ADDR_EQUAL(&outp
->ip6_dst
, dst_addr
)))
614 /* Destination option (either BU, BR or BA) found in the output list.
615 Add it to the existing destination options. */
617 opt
= (struct ip6_pktopts
*)MALLOC(sizeof(struct ip6_pktopts
),
621 bzero(opt
, sizeof(struct ip6_pktopts
));
622 opt
->ip6po_hlim
= -1; /* -1 means to use default hop limit */
625 mip6_dest_offset(opt
->ip6po_dest2
, &off
);
626 bcopy((caddr_t
)outp
->opt
, (caddr_t
)&opttype
, 1);
627 if (opttype
== IP6OPT_BINDING_UPDATE
) {
628 /* Add my Binding Update option to the Destination Header */
629 error
= mip6_add_bu(&opt
->ip6po_dest2
, &off
,
630 (struct mip6_opt_bu
*)outp
->opt
,
631 (struct mip6_subbuf
*)outp
->subopt
);
634 } else if (opttype
== IP6OPT_BINDING_ACK
) {
635 /* Add my BA option to the Destination Header */
636 error
= mip6_add_ba(&opt
->ip6po_dest2
, &off
,
637 (struct mip6_opt_ba
*)outp
->opt
,
638 (struct mip6_subbuf
*)outp
->subopt
);
641 } else if (opttype
== IP6OPT_BINDING_REQ
) {
642 /* Add my BR option to the Destination Header */
643 error
= mip6_add_br(&opt
->ip6po_dest2
, &off
,
644 (struct mip6_opt_br
*)outp
->opt
,
645 (struct mip6_subbuf
*)outp
->subopt
);
650 /* Set flag for entry in output queueu to indicate that it has
660 ##############################################################################
663 # Miscellaneous functions needed for the internal processing of incoming and
664 # outgoing control signals.
666 ##############################################################################
670 ******************************************************************************
671 * Function: mip6_add_rh
672 * Description: Add a Routing Header type 0 to the outgoing packet, if its not
673 * already present, and add the COA for the MN.
674 * If a Routing Header type 0 exist, but contains no data, or the
675 * COA for the MN is missing it is added to the Routing Header.
676 * If the Routing Header is not of type 0 the function returns.
677 * Ret value: 0 OK. Routing Header might have been added
678 * ENOBUFS No memory available
679 * Note: The destination address for the outgoing packet is not changed
680 * since this is taken care of in the ip6_output function.
681 ******************************************************************************
684 mip6_add_rh(opt
, bcp
)
685 struct ip6_pktopts
**opt
; /* Packet Ext headers, options and data */
686 struct mip6_bc
*bcp
; /* Binding Cache list entry */
688 struct ip6_pktopts
*opt_local
; /* Pkt Ext headers, options & data */
689 struct ip6_rthdr0
*rthdr0
; /* Routing header type 0 */
690 struct in6_addr
*ip6rt_addr
; /* IPv6 routing address(es) */
691 caddr_t ptr
; /* Temporary pointer */
692 int ii
, len
, new_len
, idx
;
694 /* A Multicast address must not appear in a Routing Header. */
695 if (IN6_IS_ADDR_MULTICAST(&bcp
->coa
))
699 if (opt_local
== NULL
) {
700 /* No Packet options present at all. Add a Routing Header. */
701 opt_local
= (struct ip6_pktopts
*)MALLOC(sizeof(struct ip6_pktopts
),
703 if (opt_local
== NULL
)
705 bzero(opt_local
, sizeof(struct ip6_pktopts
));
706 opt_local
->ip6po_hlim
= -1; /* -1 means to use default hop limit */
708 opt_local
->ip6po_rhinfo
.ip6po_rhi_rthdr
=
709 mip6_create_rh(&bcp
->coa
, IPPROTO_IP
);
710 if(opt_local
->ip6po_rhinfo
.ip6po_rhi_rthdr
== NULL
)
712 } else if (opt_local
->ip6po_rhinfo
.ip6po_rhi_rthdr
== NULL
) {
713 /* Packet extension header allocated but no RH present, add one. */
714 opt_local
->ip6po_rhinfo
.ip6po_rhi_rthdr
=
715 mip6_create_rh(&bcp
->coa
, IPPROTO_IP
);
716 if(opt_local
->ip6po_rhinfo
.ip6po_rhi_rthdr
== NULL
)
719 /* A RH exist. Don't do anything if the type is not 0. */
720 if (opt_local
->ip6po_rhinfo
.ip6po_rhi_rthdr
->ip6r_type
!=
724 /* If the outgoing packet contains a BA the Routing Header is
725 correct generated by MIP6. No further action is needed. */
726 if (opt_local
->ip6po_dest2
== NULL
)
729 len
= (opt_local
->ip6po_dest2
->ip6d_len
+ 1) << 3;
731 ptr
= (caddr_t
)opt_local
->ip6po_dest2
+ 2;
733 if (*ptr
== IP6OPT_PAD1
) {
738 if (*ptr
== IP6OPT_BINDING_ACK
)
740 ii
+= *(ptr
+ 1) + 2;
741 ptr
+= *(ptr
+ 1) + 2;
744 /* A routing header exist and the outgoing packet does not include
745 a BA. The routing header has been generated by a user and must
746 be checked. If the last segment is not equal to the MN's COA,
748 len
= opt_local
->ip6po_rhinfo
.ip6po_rhi_rthdr
->ip6r_len
;
754 rthdr0
= (struct ip6_rthdr0
*)
755 opt_local
->ip6po_rhinfo
.ip6po_rhi_rthdr
;
756 ptr
= (caddr_t
)rthdr0
+ sizeof(struct ip6_rthdr0
);
757 ip6rt_addr
= (struct in6_addr
*)ptr
;
758 if (IN6_ARE_ADDR_EQUAL(&bcp
->coa
, ip6rt_addr
+ idx
))
762 rthdr0
= (struct ip6_rthdr0
*)
763 MALLOC(sizeof(struct ip6_rthdr0
) +
764 (new_len
/ 2) * sizeof(struct in6_addr
), M_TEMP
, M_WAITOK
);
768 bcopy((caddr_t
)opt_local
->ip6po_rhinfo
.ip6po_rhi_rthdr
,
769 (caddr_t
)rthdr0
, (len
+ 1) * 8);
770 bcopy((caddr_t
)&bcp
->coa
, (caddr_t
)rthdr0
+ (len
+ 1) * 8,
771 sizeof(struct in6_addr
));
772 rthdr0
->ip6r0_len
= new_len
;
773 rthdr0
->ip6r0_segleft
= new_len
/ 2;
775 FREE(opt_local
->ip6po_rhinfo
.ip6po_rhi_rthdr
, M_IP6OPT
);
776 opt_local
->ip6po_rhinfo
.ip6po_rhi_rthdr
=
777 (struct ip6_rthdr
*)rthdr0
;
780 /* Change the IP destination address to the COA for the MN. */
788 ******************************************************************************
789 * Function: mip6_align
790 * Description: Align the outgoing Destination Header to 8-byte
792 ******************************************************************************
795 mip6_align(dstopt
, off
)
796 struct ip6_dest
*dstopt
; /* IPv6 destination options for the packet */
797 int *off
; /* Offset from start of Destination Header (byte) */
799 int rest
; /* Rest of modulo division */
800 u_int8_t padlen
; /* Number of bytes to pad */
801 u_int8_t padn
; /* Number for option type PADN */
808 /* Add a PAD1 option */
809 bzero((caddr_t
)dstopt
+ *off
, 1);
812 /* Add a PADN option */
813 bzero((caddr_t
)dstopt
+ *off
, padlen
);
814 bcopy(&padn
, (caddr_t
)dstopt
+ *off
, 1);
816 bcopy(&padlen
, (caddr_t
)dstopt
+ *off
+ 1, 1);
825 ******************************************************************************
826 * Function: mip6_dest_offset
827 * Description: Calculate offset for new data in the Destination Header.
828 * Additional options will be added beginning at the offset.
829 ******************************************************************************
832 mip6_dest_offset(dstopt
, off
)
833 struct ip6_dest
*dstopt
; /* IPv6 destination options for the packet */
834 int *off
; /* Offset from start of Destination Header (byte) */
836 int ii
; /* Internal counter */
837 u_int8_t opttype
; /* Option type found in Destination Header*/
838 u_int8_t optlen
; /* Option length incl type and length */
839 u_int32_t len
; /* Length of Destination Header in bytes */
841 if (dstopt
== NULL
) {
846 len
= (dstopt
->ip6d_len
+ 1) << 3;
849 for (ii
= 2; ii
< len
;) {
850 bcopy((caddr_t
)dstopt
+ ii
, (caddr_t
)&opttype
, 1);
851 if (opttype
== IP6OPT_PAD1
) {
856 bcopy((caddr_t
)dstopt
+ ii
+ 1, (caddr_t
)&optlen
, 1);
857 if (opttype
== IP6OPT_PADN
) {
870 ******************************************************************************
871 * Function: mip6_add_ha
872 * Description: Add Home Address option to the Destination Header. Change the
873 * IPv6 source address to the care-of address of the MN.
875 * Otherwise any appropriate error code
876 ******************************************************************************
879 mip6_add_ha(dstopt
, off
, src_addr
, coa
)
880 struct ip6_dest
**dstopt
; /* IPv6 destination options for the packet */
881 int *off
; /* Offset from start of Dest Header (byte) */
882 struct in6_addr
*src_addr
; /* IPv6 header source address */
883 struct in6_addr
*coa
; /* MN's care-of address */
885 struct ip6_dest
*new_opt
; /* Old dest options + Home address option */
886 struct ip6_dest
*dest
; /* Local variable for destination option */
887 int ii
; /* Internal counter */
888 int rest
; /* Rest of modulo division */
889 u_int8_t padn
; /* Number for option type PADN */
890 u_int8_t opttype
; /* Option type */
891 u_int8_t optlen
; /* Option length excluding type and length */
892 u_int8_t dstlen
; /* destination Header length in 8-bytes */
893 u_int32_t len
; /* Length of Destination Header in bytes */
895 /* Allocate memory for the Home Address option */
898 dest
= (struct ip6_dest
*)MALLOC(sizeof(struct ip6_dest
) +
899 sizeof(struct mip6_opt_ha
),
903 bzero(dest
, sizeof(struct ip6_dest
) + sizeof(struct mip6_opt_ha
));
906 len
= (dest
->ip6d_len
+ 1) << 3;
907 new_opt
= (struct ip6_dest
*)MALLOC(len
+
908 sizeof(struct mip6_opt_ha
),
912 bzero(new_opt
, len
+ sizeof(struct mip6_opt_ha
));
913 bcopy((caddr_t
)dest
, (caddr_t
)new_opt
, len
);
914 FREE(dest
, M_IP6OPT
);
918 /* Make sure that the offset is correct for adding a Home Address
923 /* Add a PADN option with length 0 */
924 bzero((caddr_t
)dest
+ *off
, 2);
925 bcopy(&padn
, (caddr_t
)dest
+ *off
, 1);
927 } else if (rest
== 1) {
928 /* Add a PAD1 option */
929 bzero((caddr_t
)dest
+ *off
, 1);
931 } else if (rest
== 3) {
932 /* Add a PADN option with length 1 */
933 bzero((caddr_t
)dest
+ *off
, 3);
934 bcopy(&padn
, (caddr_t
)dest
+ *off
, 1);
935 bcopy(&padn
, (caddr_t
)dest
+ *off
+ 1, 1);
939 /* Add the options in the way they shall be added. */
940 opttype
= IP6OPT_HOME_ADDRESS
;
941 optlen
= IP6OPT_HALEN
;
943 bcopy(&opttype
, (caddr_t
)dest
+ *off
, 1);
945 bcopy(&optlen
, (caddr_t
)dest
+ *off
, 1);
948 for (ii
= 0; ii
< 4; ii
++) {
949 bcopy((caddr_t
)&src_addr
->s6_addr32
[ii
], (caddr_t
)dest
+ *off
, 4);
953 /* Align the Destination Header to 8-byte */
954 mip6_align(dest
, off
);
956 /* Change the total length of the Destination header */
957 dstlen
= (*off
>> 3) - 1;
958 bcopy(&dstlen
, (caddr_t
)dest
+ 1, 1);
960 /* Change the IP6 source address to the care-of address */
961 src_addr
->s6_addr32
[0] = coa
->s6_addr32
[0];
962 src_addr
->s6_addr32
[1] = coa
->s6_addr32
[1];
963 src_addr
->s6_addr32
[2] = coa
->s6_addr32
[2];
964 src_addr
->s6_addr32
[3] = coa
->s6_addr32
[3];
972 ******************************************************************************
973 * Function: mip6_add_bu
974 * Description: Copy BU option and sub-option (if present) to a Destination
976 * Memory in the Destination Header for the BU is created, the
977 * header is aligned to 8-byte alignment and the total length of
978 * the header is updated.
980 * Otherwise any appropriate error code
981 ******************************************************************************
984 mip6_add_bu(dstopt
, off
, optbu
, subopt
)
985 struct ip6_dest
**dstopt
; /* IPv6 destination options for the packet */
986 int *off
; /* Offset from start of Dest Header (byte) */
987 struct mip6_opt_bu
*optbu
; /* BU option data */
988 struct mip6_subbuf
*subopt
; /* BU sub-option data (NULL if not present) */
990 struct ip6_dest
*new_opt
; /* Old destination options + BU option */
991 struct ip6_dest
*dest
; /* Local variable for destination option */
992 u_int8_t padn
; /* Number for option type PADN */
993 u_int8_t dstlen
; /* Destination Header length in 8-bytes */
994 int offlen
; /* Offset for option length in the buffer */
995 int rest
; /* Rest of modulo division */
996 int optlen
; /* Length of BU option incl sub-options */
997 int tmp16
; /* Temporary converting of 2-byte */
998 int tmp32
; /* Temporary converting of 4-byte */
999 int len
; /* Length of allocated memory */
1006 /* Allocate memory for the BU option and sub-option (if present). */
1009 len
= sizeof(struct ip6_dest
) + sizeof(struct mip6_opt_bu
) + 8;
1013 dest
= (struct ip6_dest
*)MALLOC(len
, M_TEMP
, M_WAITOK
);
1019 len
= (dest
->ip6d_len
+ 1) << 3;
1020 len
+= sizeof(struct mip6_opt_bu
) + 8;
1024 new_opt
= (struct ip6_dest
*)MALLOC(len
, M_TEMP
, M_WAITOK
);
1025 if (new_opt
== NULL
)
1028 bzero(new_opt
, len
);
1029 bcopy((caddr_t
)dest
, (caddr_t
)new_opt
, (dest
->ip6d_len
+ 1) << 3);
1030 FREE(dest
, M_IP6OPT
);
1034 /* Compensate for the alignment requirement. */
1038 /* Add a PADN option with length 0 */
1039 bzero((caddr_t
)dest
+ *off
, 2);
1040 bcopy(&padn
, (caddr_t
)dest
+ *off
, 1);
1042 } else if (rest
== 1) {
1043 /* Add a PAD1 option */
1044 bzero((caddr_t
)dest
+ *off
, 1);
1046 } else if (rest
== 3) {
1047 /* Add a PADN option with length 1 */
1048 bzero((caddr_t
)dest
+ *off
, 3);
1049 bcopy(&padn
, (caddr_t
)dest
+ *off
, 1);
1050 bcopy(&padn
, (caddr_t
)dest
+ *off
+ 1, 1);
1055 /* Reset BU option length in case of retransmission. */
1056 optbu
->len
= IP6OPT_BULEN
;
1058 /* Copy the BU data from the internal structure to the Dest Header */
1059 bcopy((caddr_t
)&optbu
->type
, (caddr_t
)dest
+ *off
, sizeof(optbu
->type
));
1060 *off
+= sizeof(optbu
->type
);
1061 bcopy((caddr_t
)&optbu
->len
, (caddr_t
)dest
+ *off
, sizeof(optbu
->len
));
1062 *off
+= sizeof(optbu
->len
);
1063 bcopy((caddr_t
)&optbu
->flags
, (caddr_t
)dest
+ *off
, sizeof(optbu
->flags
));
1064 *off
+= sizeof(optbu
->flags
);
1065 bcopy((caddr_t
)&optbu
->prefix_len
, (caddr_t
)dest
+ *off
,
1066 sizeof(optbu
->prefix_len
));
1067 *off
+= sizeof(optbu
->prefix_len
);
1068 tmp16
= htons(optbu
->seqno
);
1069 bcopy((caddr_t
)&tmp16
, (caddr_t
)dest
+ *off
, sizeof(optbu
->seqno
));
1070 *off
+= sizeof(optbu
->seqno
);
1071 tmp32
= htonl(optbu
->lifetime
);
1072 bcopy((caddr_t
)&tmp32
, (caddr_t
)dest
+ *off
, sizeof(optbu
->lifetime
));
1073 *off
+= sizeof(optbu
->lifetime
);
1075 /* If sub-options are present, add them as well. */
1076 optlen
= optbu
->len
;
1078 /* Align the Destination Header to 8-byte before sub-options
1081 mip6_align(dest
, off
);
1083 optlen
+= after
- before
;
1085 bcopy((caddr_t
)subopt
->buffer
, (caddr_t
)dest
+ *off
, subopt
->len
);
1086 *off
+= subopt
->len
;
1087 optlen
+= subopt
->len
;
1088 optbu
->len
+= subopt
->len
;
1091 /* Make sure that the option length is correct. */
1092 bcopy((caddr_t
)&optlen
, (caddr_t
)dest
+ offlen
, 1);
1094 /* Align the Destination Header to 8-byte */
1095 mip6_align(dest
, off
);
1097 /* Change the total length of the Destination header */
1098 dstlen
= (*off
>> 3) - 1;
1099 bcopy(&dstlen
, (caddr_t
)dest
+ 1, 1);
1107 ******************************************************************************
1108 * Function: mip6_add_ba
1109 * Description: Copy BA option and sub-option (if present) to a Destination
1111 * Memory in the Destination Header for the BU is created, the
1112 * header is aligned to 8-byte alignment and the total length of
1113 * the header is updated.
1114 * Ret value: 0 if OK
1115 * Otherwise any appropriate error code
1116 ******************************************************************************
1119 mip6_add_ba(dstopt
, off
, optba
, subopt
)
1120 struct ip6_dest
**dstopt
; /* IPv6 dest options for the packet */
1121 int *off
; /* Offset from start of dest Header (byte) */
1122 struct mip6_opt_ba
*optba
; /* BA option data */
1123 struct mip6_subbuf
*subopt
; /* BA sub-option data (NULL if not present) */
1125 struct ip6_dest
*new_opt
; /* Old destination options + BA option */
1126 struct ip6_dest
*dest
; /* Local variable for destination option */
1127 u_int8_t padn
; /* Number for option type PADN */
1128 u_int8_t dstlen
; /* Destination Header length in 8-bytes */
1129 int offlen
; /* Offset for option length in the buffer */
1130 int optlen
; /* Length of BA option incl sub-options */
1131 int rest
; /* Rest of modulo division */
1132 int tmp16
; /* Temporary converting of 2-byte */
1133 int tmp32
; /* Temporary converting of 4-byte */
1134 int len
; /* Length of allocated memory */
1141 /* Allocate memory for the BA option and sub-option (if present). */
1144 len
= sizeof(struct ip6_dest
) + sizeof(struct mip6_opt_ba
) + 8;
1148 dest
= (struct ip6_dest
*)MALLOC(len
, M_TEMP
, M_WAITOK
);
1154 len
= (dest
->ip6d_len
+ 1) << 3;
1155 len
+= sizeof(struct mip6_opt_ba
) + 8;
1159 new_opt
= (struct ip6_dest
*)MALLOC(len
, M_TEMP
, M_WAITOK
);
1160 if (new_opt
== NULL
)
1162 bzero(new_opt
, len
);
1163 bcopy((caddr_t
)dest
, (caddr_t
)new_opt
, (dest
->ip6d_len
+ 1) << 3);
1164 FREE(dest
, M_IP6OPT
);
1168 /* Compensate for the alignment requirement. */
1172 /* Add a PADN option with length 0 */
1173 bzero((caddr_t
)dest
+ *off
, 2);
1174 bcopy(&padn
, (caddr_t
)dest
+ *off
, 1);
1176 } else if (rest
== 2) {
1177 /* Add a PAD1 option */
1178 bzero((caddr_t
)dest
+ *off
, 1);
1180 } else if (rest
== 0) {
1181 /* Add a PADN option with length 1 */
1182 bzero((caddr_t
)dest
+ *off
, 3);
1183 bcopy(&padn
, (caddr_t
)dest
+ *off
, 1);
1184 bcopy(&padn
, (caddr_t
)dest
+ *off
+ 1, 1);
1189 /* Copy the BA data from the internal structure to mbuf */
1190 bcopy((caddr_t
)&optba
->type
, (caddr_t
)dest
+ *off
, sizeof(optba
->type
));
1191 *off
+= sizeof(optba
->type
);
1192 bcopy((caddr_t
)&optba
->len
, (caddr_t
)dest
+ *off
, sizeof(optba
->len
));
1193 *off
+= sizeof(optba
->len
);
1194 bcopy((caddr_t
)&optba
->status
, (caddr_t
)dest
+ *off
,
1195 sizeof(optba
->status
));
1196 *off
+= sizeof(optba
->status
);
1197 tmp16
= htons(optba
->seqno
);
1198 bcopy((caddr_t
)&tmp16
, (caddr_t
)dest
+ *off
, sizeof(optba
->seqno
));
1199 *off
+= sizeof(optba
->seqno
);
1200 tmp32
= htonl(optba
->lifetime
);
1201 bcopy((caddr_t
)&tmp32
, (caddr_t
)dest
+ *off
, sizeof(optba
->lifetime
));
1202 *off
+= sizeof(optba
->lifetime
);
1203 tmp32
= htonl(optba
->refresh
);
1204 bcopy((caddr_t
)&tmp32
, (caddr_t
)dest
+ *off
, sizeof(optba
->refresh
));
1205 *off
+= sizeof(optba
->refresh
);
1207 /* If sub-options are present, add them as well. */
1208 optlen
= IP6OPT_BALEN
;
1210 /* Align the Destination Header to 8-byte before sub-options
1213 mip6_align(dest
, off
);
1215 optlen
+= after
- before
;
1217 bcopy((caddr_t
)subopt
->buffer
, (caddr_t
)dest
+ *off
, subopt
->len
);
1218 *off
+= subopt
->len
;
1219 optlen
+= subopt
->len
;
1220 optba
->len
+= subopt
->len
;
1223 /* Make sure that the option length is correct. */
1224 bcopy((caddr_t
)&optlen
, (caddr_t
)dest
+ offlen
, 1);
1226 /* Align the Destination Header to 8-byte */
1227 mip6_align(dest
, off
);
1229 /* Change the total length of the Destination header */
1230 dstlen
= (*off
>> 3) - 1;
1231 bcopy(&dstlen
, (caddr_t
)dest
+ 1, 1);
1239 ******************************************************************************
1240 * Function: mip6_add_br
1241 * Description: Copy BR option and sub-option (if present) to a Destination
1243 * Memory in the Destination Header for the BU is created, the
1244 * header is aligned to 8-byte alignment and the total length of
1245 * the header is updated.
1246 * Ret value: 0 if OK
1247 * Otherwise any appropriate error code
1248 ******************************************************************************
1251 mip6_add_br(dstopt
, off
, optbr
, subopt
)
1252 struct ip6_dest
**dstopt
; /* IPv6 destination options for the packet */
1253 int *off
; /* Offset from start of Dest Header (byte) */
1254 struct mip6_opt_br
*optbr
; /* BR option data */
1255 struct mip6_subbuf
*subopt
; /* BR sub-option data (NULL if not present) */
1257 struct ip6_dest
*new_opt
; /* Old destination options + BU option */
1258 struct ip6_dest
*dest
; /* Local variable for destination option */
1259 u_int8_t dstlen
; /* Destination Header length in 8-bytes */
1260 int offlen
; /* Offset for option length in the buffer */
1261 int rest
; /* Rest of modulo division */
1262 int optlen
; /* Length of BR option incl sub-options */
1263 int len
; /* Length of allocated memory */
1270 /* Allocate memory for the BR option and sub-option (if present). */
1273 len
= sizeof(struct ip6_dest
) + sizeof(struct mip6_opt_br
) + 8;
1277 dest
= (struct ip6_dest
*)MALLOC(len
, M_TEMP
, M_WAITOK
);
1284 len
= (dest
->ip6d_len
+ 1) << 3;
1285 len
+= sizeof(struct mip6_opt_br
) + 8;
1289 new_opt
= (struct ip6_dest
*)MALLOC(len
, M_TEMP
, M_WAITOK
);
1290 if (new_opt
== NULL
)
1293 bzero(new_opt
, len
);
1294 bcopy((caddr_t
)dest
, (caddr_t
)new_opt
, (dest
->ip6d_len
+ 1) << 3);
1295 FREE(dest
, M_IP6OPT
);
1299 /* Compensate for the alignment requirement. */
1301 if ((rest
== 1) || (rest
== 3)) {
1302 /* Add a PAD1 option */
1303 bzero((caddr_t
)dest
+ *off
, 1);
1308 /* Copy the BR data from the internal structure to mbuf */
1309 bcopy((caddr_t
)&optbr
->type
, (caddr_t
)dest
+ *off
, sizeof(optbr
->type
));
1310 *off
+= sizeof(optbr
->type
);
1311 bcopy((caddr_t
)&optbr
->len
, (caddr_t
)dest
+ *off
, sizeof(optbr
->len
));
1312 *off
+= sizeof(optbr
->len
);
1315 /* If sub-options are present, add them as well. */
1316 optlen
= IP6OPT_BRLEN
;
1318 /* Align the Destination Header to 8-byte before sub-options
1321 mip6_align(dest
, off
);
1323 optlen
+= after
- before
;
1325 bcopy((caddr_t
)subopt
->buffer
, (caddr_t
)dest
+ *off
, subopt
->len
);
1326 *off
+= subopt
->len
;
1327 optlen
+= subopt
->len
;
1328 optbr
->len
+= subopt
->len
;
1331 /* Make sure that the option length is correct. */
1332 bcopy((caddr_t
)&optlen
, (caddr_t
)dest
+ offlen
, 1);
1334 /* Align the Destination Header to 8-byte */
1335 mip6_align(dest
, off
);
1337 /* Change the total length of the Destination header */
1338 dstlen
= (*off
>> 3) - 1;
1339 bcopy(&dstlen
, (caddr_t
)dest
+ 1, 1);
1347 ******************************************************************************
1348 * Function: mip6_store_subopt
1349 * Description: Store a sub-option in a buffer. The buffer must be allocated
1350 * by the calling function and big enough to hold all the sub-
1351 * options that may be added to an option (BU, BR or BA).
1352 * Alignement requirement for the different sub-options are taken
1353 * care of before its added to the buffer.
1354 * Ret value: 0 if OK. Otherwise 1
1355 ******************************************************************************
1358 mip6_store_subopt(subbuf
, subopt
)
1359 struct mip6_subbuf
**subbuf
; /* Buffert containing sub-options */
1360 caddr_t subopt
; /* TLV coded sub-option */
1362 struct mip6_subopt_id
*uid
;
1363 struct mip6_subopt_hal
*hal
;
1364 struct mip6_subopt_coa
*altcoa
;
1365 struct mip6_subbuf
*buf
;
1366 u_int8_t pad1
, padn
;
1368 int rest
, no
, ii
, padlen
;
1370 /* Make sure that a sub-option is present. */
1374 /* Allocate memory for buffer if not already allocated. */
1377 buf
= (struct mip6_subbuf
*)MALLOC(sizeof(struct mip6_subbuf
),
1381 bzero(buf
, sizeof(struct mip6_subbuf
));
1384 /* Find offset in the current buffer */
1389 case IP6SUBOPT_UNIQUEID
:
1390 /* Make sure that the length is OK */
1391 uid
= (struct mip6_subopt_id
*)subopt
;
1392 if (uid
->len
!= IP6OPT_UIDLEN
)
1395 /* Compensate for the alignment requirement. */
1396 rest
= buf
->len
% 2;
1398 bcopy(&pad1
, (caddr_t
)buf
->buffer
+ buf
->len
, 1);
1402 /* Copy the sub-option to the buffer. */
1403 bcopy(&uid
->type
, (caddr_t
)buf
->buffer
+ buf
->len
,
1405 buf
->len
+= sizeof(uid
->type
);
1407 bcopy(&uid
->len
, (caddr_t
)buf
->buffer
+ buf
->len
,
1409 buf
->len
+= sizeof(uid
->len
);
1411 tmp16
= htons(uid
->id
);
1412 bcopy(&tmp16
, (caddr_t
)buf
->buffer
+ buf
->len
, sizeof(tmp16
));
1413 buf
->len
+= sizeof(tmp16
);
1415 case IP6SUBOPT_HALIST
:
1416 /* Make sure that the length is OK */
1417 hal
= (struct mip6_subopt_hal
*)subopt
;
1418 if (hal
->len
% IP6OPT_HALISTLEN
)
1421 /* Compensate for the alignment requirement. */
1422 rest
= buf
->len
% 8;
1425 bcopy(&padn
, (caddr_t
)buf
->buffer
+ buf
->len
, 1);
1427 bcopy(&padlen
, (caddr_t
)buf
->buffer
+ buf
->len
, 1);
1429 bzero((caddr_t
)buf
->buffer
+ buf
->len
, padlen
);
1431 } else if (rest
== 3) {
1432 bcopy(&pad1
, (caddr_t
)buf
->buffer
+ buf
->len
, 1);
1434 } else if (rest
<= 1) {
1436 bcopy(&padn
, (caddr_t
)buf
->buffer
+ buf
->len
, 1);
1438 bcopy(&padlen
, (caddr_t
)buf
->buffer
+ buf
->len
, 1);
1440 bzero((caddr_t
)buf
->buffer
+ buf
->len
, padlen
);
1444 /* Copy the sub-option to the buffer. */
1445 bcopy(&hal
->type
, (caddr_t
)buf
->buffer
+ buf
->len
,
1447 buf
->len
+= sizeof(hal
->type
);
1449 bcopy(&hal
->len
, (caddr_t
)buf
->buffer
+ buf
->len
,
1451 buf
->len
+= sizeof(hal
->len
);
1453 /* Loop over the addresses */
1454 no
= hal
->len
/ IP6OPT_HALISTLEN
;
1455 for (ii
= 0; ii
< no
; ii
++) {
1456 bcopy(&hal
->halist
[ii
], (caddr_t
)buf
->buffer
+ buf
->len
,
1457 sizeof(hal
->halist
));
1458 buf
->len
+= sizeof(hal
->halist
);
1461 case IP6SUBOPT_ALTCOA
:
1462 /* Make sure that the length is OK */
1463 altcoa
= (struct mip6_subopt_coa
*)subopt
;
1464 if (altcoa
->len
% IP6OPT_COALEN
)
1467 /* Compensate for the alignment requirement. */
1468 rest
= buf
->len
% 8;
1471 bcopy(&padn
, (caddr_t
)buf
->buffer
+ buf
->len
, 1);
1473 bcopy(&padlen
, (caddr_t
)buf
->buffer
+ buf
->len
, 1);
1475 bzero((caddr_t
)buf
->buffer
+ buf
->len
, padlen
);
1477 } else if (rest
== 3) {
1478 bcopy(&pad1
, (caddr_t
)buf
->buffer
+ buf
->len
, 1);
1480 } else if (rest
<= 1) {
1482 bcopy(&padn
, (caddr_t
)buf
->buffer
+ buf
->len
, 1);
1484 bcopy(&padlen
, (caddr_t
)buf
->buffer
+ buf
->len
, 1);
1486 bzero((caddr_t
)buf
->buffer
+ buf
->len
, padlen
);
1490 /* Copy the sub-option to the buffer. */
1491 bcopy(&altcoa
->type
, (caddr_t
)buf
->buffer
+ buf
->len
,
1492 sizeof(altcoa
->type
));
1493 buf
->len
+= sizeof(altcoa
->type
);
1495 bcopy(&altcoa
->len
, (caddr_t
)buf
->buffer
+ buf
->len
,
1496 sizeof(altcoa
->len
));
1497 buf
->len
+= sizeof(altcoa
->len
);
1499 bcopy(&altcoa
->coa
, (caddr_t
)buf
->buffer
+ buf
->len
,
1500 sizeof(altcoa
->coa
));
1501 buf
->len
+= sizeof(altcoa
->coa
);