Subject: comments on ipngwg-rfc2292bis-01

From: JINMEI Tatuya / 神明達哉<[email-masked]>
Date: Wed, 05 Jan 2000 17:53:27 +0900

I've implemented several parts of rfc2292bis-01 and would like to
comment on the draft based on the implementation experiences.

I don't remember all discussions about this draft in this list or in
the past IETF ipngwg meetings, so some of my comments might have
already been discussed. If so, I apologize in advance.

Note:
In the rest of this mail, lines beginning with white spaces or tab
characters are citation from the draft. Other lines are comments.

2.1.2.  IPv6 Extension Headers

I think it would be useful to define a generic structure to specify
IPv6 extension headers, since we sometimes encounter a situation where
we can't detect the type of an extension header but should deal with
the header. As an example, here is the KAME's structure for this
purpose:

struct	ip6_ext {
	u_char	ip6e_nxt;
	u_char	ip6e_len;
};

2.1.3.  IPv6 Options
(snip)
       /* IPv6 options */
       structip6_opt {
           uint8_tip6o_type;
           uint8_tip6o_len;
       };

There seems to be lack of white spaces in the above code. This should
be, for example, as follows:
       /* IPv6 options */
       struct ip6_opt {
           uint8_t ip6o_type;
           uint8_t ip6o_len;
       };

Moreover, all definitions of macros and structures specified in this
section (2.1.3) have this kind of mistypes.

2.2.1.  ICMPv6 Type and Code Values
...
       #define ICMP6_MEMBERSHIP_QUERY      130
       #define ICMP6_MEMBERSHIP_REPORT     131
       #define ICMP6_MEMBERSHIP_REDUCTION  132

These macro names are based on terms of IGMPv2, not MLD. So I prefer
the names like the followings:

#define MLD_LISTENER_QUERY		130
#define MLD_LISTENER_REPORT		131
#define MLD_LISTENER_DONE		132

I don't necessarily argue that the old names should be removed. I'm
glad if the latter names are *added* in the specification.

2.2.2.  ICMPv6 Neighbor Discovery Type and Code Values

       #define ND_OPT_PI_FLAG_ONLINK        0x80
       #define ND_OPT_PI_FLAG_AUTO          0x40

We may have to define macro names for the "Router Address bit" used in
mobile-ipv6 and the "Site Prefix flag" used in the
ipngwg-site-prefixes draft.
(I'm not sure this is good since they are not officially
 standardized. This is just a comment.)

2.2.3.  Multicast Listener Discovery Type and Code Values

Although the section title contains "Type and Code Values", there are
no such definitions in this section. Only a struture for MLD headers
and short cut macros are defined. Is this your intention?
(it may be good to define MLD_LISTENER_QUERY, etc in this section.)

2.2.4.  ICMPv6 Router Renumbering Type and Code Values

Again, there are no "Type and Code Values" definitions in this
section.

FYI, we use the following definition to specify the type of router
renumbering in the KAME implementation:

#define ICMP6_ROUTER_RENUMBERING	138	/* router renumbering */

       /* PCI code values */
       #define RPM_PCO_ADD              1
       #define RPM_PCO_CHANGE           2
       #define RPM_PCO_SETGLOBAL        3

I think that "PCI" in the comment line is misspelled and should be
"PCO" (Prefix Control Operations).

4.  Access to IPv6 and Extension Headers

   Two different mechanisms exist for sending this optional information:

    1.  Using setsockopt to specify the option content for a socket.
        These are known an "sticky" options since they affect all
        transmitted packets on the socket until either the a new
        setsockopt is done or the options are overridden using ancillary
        data.

When an error occurs during a process of setting a sticky option
(e.g. length mismatch), should a previously specified value of the
option (if any) be kept or be cleared anyway? I guess it should be
kept, but I'm not sure about this point from the draft. (Note that
IPv4 implementation in 4.4 BSD always clears existing IPv4 options
regardless of the result of overriding procedure.)

6.  Packet Information

   An
   application can clear any sticky IPV6_PKTINFO option by either doing
   a setsockopt for option with optlen being zero, or by doing a
   "regular" setsockopt with ipi6_addr being in6addr_any and
   ipi6_ifindex being zero.

Is the latter way necessary? This prohibits implementation from
specifing the unspecified address as source address. (I'm not sure if
it should be allowed, but it might be useful for some purposes.)

6.1.  Specifying/Receiving the Interface

   When the IPV6_PKTINFO socket option is enabled, the received
   interface index is always returned as the ipi6_ifindex member of the
   in6_pktinfo structure.

Is the option name (IPV6_PKTINFO) correct? Shouldn't it be
IPV6_RECVPKTINFO?

6.3.  Specifying/Receiving the Hop Limit

In this section, there is no (explicit) description of how to clear an
existing IPV6_HOPLIMIT sticky option. If specifying -1 is the only
way, it would be better to clearly state the fact in the draft.

6.4.  Specifying the Next Hop Address

There is no description of how to remove an existing IPV6_NEXTHOP
sticky option in this section. I guess that it can be removed by
specifying the option with optlen being zero.

7.  Routing Header Option

   This IPv6 API, however, defines eight
   functions that the application calls to build and examine a Routing
   header, and the ability to use sticky options or ancillary data to
   communicate this information between the application and the kernel
   using the IPV6_RTHDR option.

"eight" in the 1st line should be "six". Though there are eight
functions defined in RFC2292 to handle a routing header, we have only
six functions in rfc2292bis.

   Three functions build a Routing header:

     inet6_rth_space()    - return #bytes required for Routing header
     inet6_rth_init()     - initialize buffer data for Routing header
     inet6_rth_add()      - add one IPv6 address to the Routing header

It might be better to define an additional function to finalize a
Routing header, since we don't necessary know the number of
intermediate hops when initialization. Actually, I encountered such a
situtaion when implementing source routing in traceroute. Note that we
don't necessarily have to define a new function; we can extend
inet6_rth_add() so that the function updates all fields (at least
including the header length field) of the routing header each time it
is called.

   To receive a Routing header the application must enable the
   IPV6_RECVRTHDR socket option:

       int  on = 1;
       setsockopt(fd, IPPROTO_IPV6, IPV6_RECVRTHDR, &on, sizeof(on));

There chould be two or more routing headers in a received packet
(although this wouldn't usually happen). How can we access the second,
third, ... routing headers? Is the each routing header stored in a
separate ancillary data object? Or are all the routing headers stored
in a single object? If the latter is the case, how do we access the
second, third, ... routing headers in the single ancillary data object
(with the defined library functions only)?

7.2.  inet6_rth_init

   This function initializes the buffer pointed to by bp to contain a
   Routing header of the specified type and sets ip6r0_len based on the
   segments parameter. bp_len is only used to verify that the buffer is
   large enough.  The ip6r0_segleft field is set to zero;
   inet6_rth_add() will increment it.

It would be better to change all the "ip6r0_xxx" in the above
paragraph to "ip6r_xxx", since ip6r0_xxx members are specific to the
type-0 routing header. Though we officially have the Type 0 routing
header only, I think the function specification should be as generic
as possible.

   Upon success the return value is the pointer to the buffer (bp), and
   this is then used as the first argument to the next two functions.

"two" in the second line should be removed, because we have only one
more function (i.e. inet6_rth_add) for building the header. The
current text seems to be a relic in RFC2292.

7.4.  inet6_rth_reverse

       int inet6_rth_reverse(const void *in, void *out)

This line should be terminated by a semi-colon (`;') if we try to be
consistent with other prototypes in the draft.

Also, the description of the function is a bit unclear to me. It only
mentions how the address fields are changed. Are other fields
(especially the segment-left field) also updated? Or should a caller
adjust the fields by itself in order to reuse (e.g. resend) the
header? In our implementation, I took the former approach; the value
of the segment-left field will be changed to the number of segments in
the function procedure.

8.2.  Sending Hop-by-Hop Options

   All the Hop-by-Hop options must specified by a single ancillary data
   object.

What should the kernel do if an ancillary data contains multiple
IPV6_HOPOPTS objects? Should it take just one of them or should it
discard the entire ancillary data and return an error? If the former
is the case, which one should the kernel take?

9.1.  Receiving Destination Options

   All the Destination options appearing before a Routing header are
   returned as one ancillary data object described by a cmsghdr
   structure (with cmsg_type set to IPV6_RTHDRDSTOPTS) and all the
   Destination options appearing after a Routing header (or in a packet
   without a Routing header) are returned as another ancillary data
   object described by a cmsghdr structure (with cmsg_type set to
   IPV6_DSTOPTS).

A same kind of question of receiving multiple routing headers can be
applied to the destination options header as well; How can we access
the second, third, ... destination options headers before/after a
routing header? Also, if there is more than one routing header in a
received packet and there is a destination options header between two
routing headers, which part is the destination options header
regarded as, before a routing header or after?

9.2.  Sending Destination Options

   As described in Section 6 one set of Destination options can appear
   before a Routing header, and one set can appear after a Routing
   header (or in a packet with no Routing header).  Each set can consist
   of one or more options but each set is a single extension header.

What should the kernel do if an ancillary data contains multiple
IPV6_DSTOPTS or IPV6_RTHDRDSTOPTS objects? Should it take just one of
them or should it discard the entire ancillary data and return an
error? If the former is the case, which one should the kernel take?

   Any setsockopt or ancillary data for IPV6_RTHDRDSTOPTS is silently
   ignore when sending packets unless a Routing header is also

"ignore" in the second line seems to be a typo and should be
"ignored".

10.1.  inet6_opt_init

       int inet6_opt_init(void *extbuf, size_t extlen);

   This function returns the number of bytes needed for the empty
   extension header i.e. without any options.  If extbuf is not NULL it
   also initializes the extension header to have the correct length
   field.  If the extlen value is not a positive (i.e., non-zero)
   multiple of 8 the function fails and returns -1.

In spite of the last sentence, the sample code in section 24.1 passes
0 as the second argument of the function:

       currentlen = inet6_opt_init(NULL, 0);

In our implementation, I allowed 0 only when the first argument is
NULL. But I'm not sure this is the correct behavior. This should be
clarified in the next draft, anyway.

10.2.  inet6_opt_append

   type is the 8-bit option type.  len is the length of the option data
   (i.e. excluding the option type and option length fields).

"type" and "len" at the beginning of the sentences might have to be
capitalized (I'm not sure this is really correct, but many other
sentences in the draft begin with capitalized variable names.)

   The align parameter must have a value of 1, 2, 4, or 8.  The align
   value can not exceed the value of len.

Is this enough to implement all "Xn + Y" alignment requirements? For
example, can we specify "4n + 3" as alignment requirement using a
single alignment parameter?

10.4.  inet6_opt_set_val

   Databuf should be a pointer returned by inet6_opt_append().  This
   function inserts data items of various sizes (1, 2, 4, or 8 bytes) in
   the data portion of the option.

"(1, 2, 4, or 8 bytes)" seems confusing; it can be interpreted that
only the 4 sizes can be specified. I think it would be better to
simply remove the parenthesis.

   val should point to the data to be
   inserted.  Offset specifies where in the data portion of the option
   ...

"val" might have to be capitalized (see the first comment on 10.2).

10.5.  inet6_opt_next

   This function parses received extension headers returning the next
   option.

Since the function is used only for HbH/Destination options headers,
it would be better to replace "received extension headers" with "(a)
received options header(s)".

   When there are no more options the return value is -1.

What if an error occurs?

10.7.  inet6_opt_get_val

   This function extracts data items of various sizes
   (1, 2, 4, or 8 bytes) in the data portion of the option.

Again, I think it would be better to remove the parenthesis (see the
first comment on section 10.4.) 

   val should
   point to the destination for the extracted data.

"val" might have to be capitalized (see the first comment on 10.2).

   XXX Perhaps we should add a note to point out that
   robust receivers should verify alignment before calling
   inet6_opt_get_val().  XXX Or check alignment and fail by returning
   -1?

I think the former is better, since we can't assume that the function
knows the alignment requirements for all options (including ones
defined in the future and unstandardized options.)

In our implementation the function always uses memcpy to copy the data
(i.e. not using cast to a specific type) for safety.

11.1.  Sending with the Minimum MTU

   This specification defines a mechanism to avoid fragmentation by
   sending at the minimum IPv6 MTU (1280 bytes).

"avoid fragmentation" seems to contradict with the motivation of the
socket option. Shouldn't this be "avoid path MTU discovery"?

Also, it would be better to just refer a specification of the minimum
MTU (maybe RFC2460) rather than to state a specific value (i.e. 1280
bytes.)

15.  Summary of New Definitions

     <netinet/in.h>    int inet6_opt_append(void *, size_t, int,
                                            uint8_t, size_t, uint_8, void **);

I think the type of the sixth argument should be "uint8_t", not
"uint_8".

23.1.  Sending a Routing Header

   The six values in the column beneath node S are the values in the
   Routing header specified by the sending application using sendmsg()
   of setsockopt().  The function calls by the sender would look like:

       void  *extptr;
       int   extlen;
       struct msghdr  msg;
       ...

The variable "extptr" is declared but unused in the example. This
should be "optptr", or all the occurrences of "optptr" should be
replaced with "extptr".

23.2.  Receiving Routing Headers

       if (msg.msg_controllen != 0 &&
           cmsgptr->cmsg_level == IPPROTO_IPV6 &&
           cmsgptr->cmsg_type == IPV6_RTHDR) {
               struct in6_addr *in6;
               char asciiname[INET6_ADDRSTRLEN];
               struct ip6_rthdr0 *rthdr;

               rthdr = (struct ip6_rthdr0 *)optptr;
               ...

I think the type of the variable "rthdr" should be "struct ip6_rthdr
*" instead of "struct ip6_rthdr0 *" for the same reason of the first
comment on section 7.2.

24.2.  Parsing received options

       int
       print_opt(void *extbuf, size_t extlen)
       {
               ip6_dest_t *ext;
               ...
               ext = (ip6_dest_t *)extbuf;

The type "ip6_dest_t" is not standardized. Why not just use "struct
ip6_dest" here?

					JINMEI, Tatuya
					Communication Platform Lab.
					Corporate R&D Center, Toshiba Corp.
					[email-masked]

--------------------------------------------------------------------
IETF IPng Working Group Mailing List
IPng Home Page:                      http://playground.sun.com/ipng
FTP archive:                      ftp://playground.sun.com/pub/ipng
Direct all administrative requests to [email-masked]
--------------------------------------------------------------------

---

From: Erik Nordmark <[email-masked]>
Date: Wed, 5 Jan 2000 16:27:42 -0800 (PST)

Thanks for all the careful comments. I'll fix the ones I'm not explicitly
including in the reply (and most of the ones below as well - I just thought
I should respond to your comments explicitly on these ones).

> the header. As an example, here is the KAME's structure for this

I will add that unless somebody disagrees.

> 2.1.3.  IPv6 Options
> (snip)
>        /* IPv6 options */
>        structip6_opt {
>            uint8_tip6o_type;
>            uint8_tip6o_len;
>        };
> 
> There seems to be lack of white spaces in the above code.

Yes, lots of whitespace is missing in the structures.
I sent an email about this to ipng back in November when I realized the
bug.

> glad if the latter names are *added* in the specification.

I'll switch to the new ones. If implementations want to provide the old
as well as new they can do that. But we don't want to clutter up the 
specification.

>  standardized. This is just a comment.)

My take is that if we are pretty sure that things will become a standard
we can add it to the API.
Thus I added router renumbering stuff and I should add the mobile IPv6
pieces.
But I might hold off for a while on icmp name lookups and site prefixes
so we can see what will happen with those.
If somebody wants to convince me that the WG will approve of that work
I'm game to add it to the API spec.

So I'll add ND_OPT_PI_FLAG_ROUTER.
Is there something else missing from the mobile IPv6 specification?

> (it may be good to define MLD_LISTENER_QUERY, etc in this section.)

OK. I'll move the type definition down to be consistent across the section.

> #define ICMP6_ROUTER_RENUMBERING	138	/* router renumbering */

I'll add that one.

> "PCO" (Prefix Control Operations).

Ack.

> regardless of the result of overriding procedure.)

What do others think?
Should we specify this amount of detail?

> it should be allowed, but it might be useful for some purposes.)

Since PKTINFO contains two pieces of information (ifindex and source address)
and applications might only want to set one of the two the semantics of
	ipi6_ifindex = X (X != 0) and ipi6_addr is all zero (unpspecified)
must mean "the application does not want to control the source address".
Thus you can't really use this to set the source address to the unspecified
address.

> Is the option name (IPV6_PKTINFO) correct? Shouldn't it be

Yes. Good catch. I'll fix.

> way, it would be better to clearly state the fact in the draft.

I'll add that.
Using a zero length option should also work.

> specifying the option with optlen being zero.

I'll add that.

> including the header length field) of the routing header each time it

If you don't know the number of hops before starting to build the routing
header you don't know how much memory to allocate for the option/ancillary
data.
Thus I think applications like traceroute first need to parse its arguments
to get a list of hops (e.g. stored in an array) and then build the routing
header.

> (with the defined library functions only)?

The API isn't really designed to deal with anything but the recommended
way of doing extension headers i.e. at most one hbh header,
at most one destination header before a routing header,
at most one routing header, and at most one destination header
after the routing header.
For transmitting it is impossible to construct something different than
the above using the API.

While the receive side could provide more I don't see any reason to specify
that in the API.
(But if I ever felt the urge to implement something like that
having one ancillary data item per extension header would make the most sense -
and keeping the ancillary data items in the order the extension headers were
received in the packet.)

> of the segment-left field will be changed to the number of segments in

The intent was the former. I will add:
The function reverses the
order of the addresses and sets the segleft member in the new Routing 
header to the number of segments.

> is the case, which one should the kernel take?

I don't really care and I don't see a good reason for nailing down
this behavior in the specification. "Implementation defined".

> regarded as, before a routing header or after?

And the same type of answer applies.

> error? If the former is the case, which one should the kernel take?

Implementation defined.

> 0 as the second argument of the function:

The intent is that is extbuf is not NULL then extlen has to satisfy the above
requirement.
I'll clarify.

> single alignment parameter?

It is sufficient to specify all alignments according to the rules of
appendix B in the IPv6 specification. In addition on Xn+Y that spec
says "order the fields from smallest to largest".

If you have an option with alignment 4n+3 it's size must be 4m+1 to follow
the rules in appendix B. In that case you set len to 4m+1 and align to 4.
(The rules in appendix B requires an option with alignment Xn+Y to end
at a multiple of X bytes, which is why Y doesn't have to be specified.)

> simply remove the parenthesis.

While I see the point this statement in RFC 2460
      o  One desirable feature is that any multi-octet fields within the
         Option Data area of an option be aligned on their natural
         boundaries, i.e., fields of width n octets should be placed at
         an integer multiple of n octets from the start of the Hop-by-
         Hop or Destination Options header, for n = 1, 2, 4, or 8.
seems to imply that those are the only supported sizes of the
option data.

If we don't have that constraint you could interpret the above to mean that
a 5 octet value should be aligned on its natural boundary i.e. a 5 octet
alignment. While I think you could align it on a multiple of 5 from
the beginning of the option that carries that value, you can't both do this
and have it be aligned on a multiple of 5 bytes from the beginning of
the option header or from the beginning of the packet.

So if somebody is designing options with data items that are not a power
of two in size they need to decide which power of two they need for alignment.

But I guess your point is that they should be able to use inet6_opt_set_val
to set e.g. a 5 byte value. Point taken. 
I just have to think about how to describe this in a concise way.

>    When there are no more options the return value is -1.

Also -1. I'll add that.

> first comment on section 10.4.) 

I'll try to come up with concise text.

> defined in the future and unstandardized options.)

While the function doesn't know the alignment of future option content
it could verify that they have natural alignment i.e. that an N octet
field (for N = 1,2,4,8) is aligned on an N octet boundary.

> (i.e. not using cast to a specific type) for safety.

My draft implementation also uses bcopy.

> I think the type of the sixth argument should be "uint8_t", not

Actually, uint_t is the correct type.

> should be "optptr", or all the occurrences of "optptr" should be

Ack. optlen/extlen has the same issue. I'll use "ext*" since it
is the length and pointer to the extension header.

  Erik

---

From: JINMEI Tatuya / 神明達哉<[email-masked]>
Date: Fri, 07 Jan 2000 00:29:31 +0900

>>>>> On Wed, 5 Jan 2000 16:27:42 -0800 (PST), 
>>>>> Erik Nordmark <[email-masked]> said:

> I sent an email about this to ipng back in November when I realized the

I've found it in my mailbox. I missed it, sorry.

> as well as new they can do that. But we don't want to clutter up the 

Okay, I personally don't mind to nuke old ones.

> I'm game to add it to the API spec.

Okay, I can live without official definitions for name lookups and
site prefixes.

> Is there something else missing from the mobile IPv6 specification?

Sorry, I'm not an expert in mobile ip6...maybe some other people can
answer this.

> Thus you can't really use this to set the source address to the unspecified

Hmm...okay. But I'm still confused. If an application call
setsockopt(IPV6_PKTINFO) with ipi6_addr being in6addr_any and
ipi6_ifindex being zero, and then call getsockopt(IPV6_PKTINFO), what
should happen? Should an application get an in6_pktinfo structure with
all zero values, or should it get a zero-length value?

> Using a zero length option should also work.

On the second thought, I now suspect that specifying -1 can't be used
for removing the option. It should mean "the kernel must always use
the system default value regardless of values specified by weaker
options". For example, if the IPV6_HOPLIMIT option should be stronger
than IPV6_UNICAST_HOPS (we'll have to clarify such things...),
specifying -1 by IPV6_HOPLIMIT means the kernel should still use the
system default regardless of the value specified by IPV6_UNICAST_HOPS.

So I think using a zero length option should be the only way to remove
the option.

> header you don't know how much memory to allocate for the option/ancillary

Right, but an application can first allocate an appropriate amount of
space (e.g. 127 * sizeof(struct in6_addr)) and realloc when
inet6_rth_add fails. But, okay,

> to get a list of hops (e.g. stored in an array) and then build the routing

we can take this kind of approach. I don't strongly stick to the idea
of a finalization function.

> For transmitting it is impossible to construct something different than

Exactly.

> While the receive side could provide more I don't see any reason to specify

Okay, I'm convinced. I'll note that such cases are out of scope of the
API specificaiton in our documents.

> and keeping the ancillary data items in the order the extension headers were

Sounds reasonable, and in fact, that's the way of our current
implementation.

> header to the number of segments.

Okay, good.

> this behavior in the specification. "Implementation defined".

I see. I'll state our kernel's behavior (and that it's implementation
dependent) in our own document.

> And the same type of answer applies.

Okay.

> Implementation defined.

Okay.

> at a multiple of X bytes, which is why Y doesn't have to be specified.)

Hmm, I understand. Then it would be helpful to refer the appendix and
to (more) clarify the semantics of the align parameter in the function
specification. 

By the way, it seems to me that the Home Address Option of mobile ipv6
does not follow the guideline of Appendix B of RFC2460. According to
mobileip-ipv6-09 the format is:

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
                                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                                   |  Option Type  | Option Length |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                                                               |
   +                                                               +
   |                                                               |
   +                          Home Address                         +
   |                                                               |
   +                                                               +
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   Sub-Options...
   +-+-+-+-+-+-+-+-+-+-+-+-

and its alignment requirement is 8n+6.

If the length of a sub-option is smaller than 16 (and I think it is
very possible), the format would break the guideline. How do you think
of it?

> of two in size they need to decide which power of two they need for alignment.

Hmm...maybe.

> to set e.g. a 5 byte value. Point taken. 

That's my point. The constraint seems to me too restrictive. Also,
it's not an official requirement but just an appendix. If we keep the
constraint in the function specification, we may need to refer the
appendix and to state the restriction more clearly.

> I just have to think about how to describe this in a concise way.

Okay.

> field (for N = 1,2,4,8) is aligned on an N octet boundary.

Ah, that's right. Maybe this depends on how we treat the constraint of
the vallen parameter for inet6_opt_{get,set}_val.

					JINMEI, Tatuya

---

From: Erik Nordmark <[email-masked]>
Date: Wed, 5 Jan 2000 16:27:42 -0800 (PST)

I'll add that one.

Ack.

What do others think?

I'll add that.

I'll add that.

Implementation defined.

Also -1. I'll add that.

  Erik

---

From: JINMEI Tatuya / 神明達哉 <[email-masked]>
Date: Fri, 07 Jan 2000 00:29:31 +0900

Exactly.

Okay, good.

Okay.

Okay.

    0                   1                   2                   3

Hmm...maybe.

Okay.

					JINMEI, Tatuya