/* * Class: net_RawIPv6Socket * Method: _bind * Signature: (I[BI)I */ JNIEXPORT jint JNICALL Java_net_RawIPv6Socket__1bind (JNIEnv *env, jobject obj, jint socket, jbyteArray address, jint scopeid) { struct sockaddr *saddr; struct sockaddr_in6 sin6; saddr = fill_sockaddr_in6(env, &sin6, address,scopeid); return bind(socket, saddr, sizeof(sin6)); }
status_t IPv6Multicast::LeaveGroup(IPv6GroupInterface* state) { MutexLocker _(sMulticastGroupsLock); sMulticastState->Remove(state); sockaddr_in6 groupAddr; return sDatalinkModule->leave_multicast(state->Interface(), sDomain, fill_sockaddr_in6(&groupAddr, state->Address())); }
status_t IPv6Multicast::JoinGroup(IPv6GroupInterface* state) { MutexLocker _(sMulticastGroupsLock); sockaddr_in6 groupAddr; status_t status = sDatalinkModule->join_multicast(state->Interface(), sDomain, fill_sockaddr_in6(&groupAddr, state->Address())); if (status != B_OK) return status; sMulticastState->Insert(state); return B_OK; }
status_t ipv6_receive_data(net_buffer* buffer) { TRACE("ReceiveData(%p [%ld bytes])", buffer, buffer->size); NetBufferHeaderReader<IPv6Header> bufferHeader(buffer); if (bufferHeader.Status() != B_OK) return bufferHeader.Status(); IPv6Header &header = bufferHeader.Data(); // dump_ipv6_header(header); if (header.ProtocolVersion() != IPV6_VERSION) return B_BAD_TYPE; uint16 packetLength = header.PayloadLength() + sizeof(ip6_hdr); if (packetLength > buffer->size) return B_BAD_DATA; // lower layers notion of Broadcast or Multicast have no relevance to us buffer->flags &= ~(MSG_BCAST | MSG_MCAST); sockaddr_in6 destination; fill_sockaddr_in6(&destination, header.Dst()); if (IN6_IS_ADDR_MULTICAST(&destination.sin6_addr)) { buffer->flags |= MSG_MCAST; } else { uint32 matchedAddressType = 0; // test if the packet is really for us if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination, &buffer->interface_address, &matchedAddressType) && !sDatalinkModule->is_local_link_address(sDomain, true, buffer->destination, &buffer->interface_address)) { char srcbuf[INET6_ADDRSTRLEN]; char dstbuf[INET6_ADDRSTRLEN]; ip6_sprintf(&header.Src(), srcbuf); ip6_sprintf(&header.Dst(), dstbuf); TRACE(" ipv6_receive_data(): packet was not for us %s -> %s", srcbuf, dstbuf); // TODO: Send ICMPv6 error: Host unreachable return B_ERROR; } // copy over special address types (MSG_BCAST or MSG_MCAST): buffer->flags |= matchedAddressType; } // set net_buffer's source/destination address fill_sockaddr_in6((struct sockaddr_in6*)buffer->source, header.Src()); memcpy(buffer->destination, &destination, sizeof(sockaddr_in6)); // get the transport protocol and transport header offset uint16 transportHeaderOffset = header.GetHeaderOffset(buffer); uint8 protocol = buffer->protocol; // remove any trailing/padding data status_t status = gBufferModule->trim(buffer, packetLength); if (status != B_OK) return status; // check for fragmentation uint16 fragmentHeaderOffset = header.GetHeaderOffset(buffer, IPPROTO_FRAGMENT); if (fragmentHeaderOffset != 0) { // this is a fragment TRACE(" ipv6_receive_data(): Found a Fragment!"); status = reassemble_fragments(header, &buffer, fragmentHeaderOffset); TRACE(" ipv6_receive_data(): -> %s", strerror(status)); if (status != B_OK) return status; if (buffer == NULL) { // buffer was put into fragment packet TRACE(" ipv6_receive_data(): Not yet assembled."); return B_OK; } } // tell the buffer to preserve removed ipv6 header - may need it later gBufferModule->store_header(buffer); // remove ipv6 headers for now gBufferModule->remove_header(buffer, transportHeaderOffset); // deliver the data to raw sockets raw_receive_data(buffer); net_protocol_module_info* module = receiving_protocol(protocol); if (module == NULL) { // no handler for this packet return EAFNOSUPPORT; } if ((buffer->flags & MSG_MCAST) != 0) { // Unfortunately historical reasons dictate that the IP multicast // model be a little different from the unicast one. We deliver // this frame directly to all sockets registered with interest // for this multicast group. return deliver_multicast(module, buffer, false); } return module->receive_data(buffer); }
/* * Class: net_RawIPv6Socket * Method: _send * Signature: (I[B[BI[BII)I */ JNIEXPORT jint JNICALL Java_net_RawIPv6Socket__1send (JNIEnv *env, jobject obj, jint socket, jbyteArray srcaddress, jbyteArray dstaddress, jint dstscopeid, jbyteArray data, jint offset, jint len, jint ttl, jint tos) { int result; jbyte *buf; struct sockaddr_in6 sin6; struct sockaddr *saddr; struct msghdr mhdr; struct iovec iovecs[1]; char msg_control_buffer6[CMSG_SPACE(sizeof(int))+CMSG_SPACE(sizeof(int))+CMSG_SPACE(sizeof(struct in6_pktinfo))]; struct cmsghdr *cmsg; int controllen; struct in6_pktinfo *pktinfo6; int *sent_ttl; int *sent_tos; saddr = fill_sockaddr_in6(env, &sin6, dstaddress, dstscopeid); buf = (*env)->GetByteArrayElements(env, data, NULL); mhdr.msg_name = saddr; mhdr.msg_namelen = sizeof(sin6); iovecs[0].iov_base= &buf[offset]; iovecs[0].iov_len = len; mhdr.msg_iov = &iovecs[0]; mhdr.msg_iovlen = 1; mhdr.msg_control = msg_control_buffer6; mhdr.msg_controllen = sizeof(msg_control_buffer6); controllen = 0; cmsg = CMSG_FIRSTHDR(&mhdr); cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; cmsg->cmsg_len = 0; pktinfo6 = (struct in6_pktinfo*) CMSG_DATA(cmsg); pktinfo6->ipi6_ifindex = 0; pktinfo6->ipi6_addr = in6addr_any;//source address not specified if (srcaddress != NULL) init_addr(env,&pktinfo6->ipi6_addr,srcaddress,sizeof(struct in6_addr)); controllen += CMSG_SPACE(sizeof(struct in6_pktinfo)); cmsg = (struct cmsghdr *)((unsigned char*)cmsg + CMSG_SPACE(sizeof(struct in6_pktinfo))); if (ttl >=0) { cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_HOPLIMIT; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); sent_ttl = (int *)CMSG_DATA(cmsg); *sent_ttl = ttl; controllen += CMSG_SPACE(sizeof(int)); cmsg = (struct cmsghdr *)((unsigned char*)cmsg + CMSG_SPACE(sizeof(int))); } if (tos >=0) { cmsg = CMSG_NXTHDR(&mhdr,cmsg); cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_TCLASS; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); sent_tos = (int *)CMSG_DATA(cmsg); *sent_tos = tos; controllen += CMSG_SPACE(sizeof(int)); cmsg = (struct cmsghdr *)((unsigned char*)cmsg + CMSG_SPACE(sizeof(int))); } mhdr.msg_controllen = controllen; result = sendmsg(socket,&mhdr,0); (*env)->ReleaseByteArrayElements(env, data, buf, JNI_ABORT); return result; }