Example #1
0
/**
 * Handle Cancel Packet
 * @param context Matching Context Pointer
 * @param sendermac Packet Sender MAC
 * @param length Packet Length
 */
void _actOnCancelPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sendermac, uint32_t length)
{
	// Find Peer
	SceNetAdhocMatchingMemberInternal * peer = _findPeer(context, sendermac);
	
	// Get Parent
	SceNetAdhocMatchingMemberInternal * parent = _findParent(context);
	
	// Get Outgoing Join Request
	SceNetAdhocMatchingMemberInternal * request = _findOutgoingRequest(context);
	
	// Get P2P Partner
	SceNetAdhocMatchingMemberInternal * p2p = _findP2P(context);
	
	// Interest Condition fulfilled
	if(peer != NULL)
	{
		// Complete Packet Header available
		if(length >= 5)
		{
			// Extract Optional Data Length
			int optlen = 0; memcpy(&optlen, context->rxbuf + 1, sizeof(optlen));
			
			// Complete Valid Packet available
			if(optlen >= 0 && length >= (5 + optlen))
			{
				// Set Default Null Data
				void * opt = NULL;
				
				// Extract Optional Data Pointer
				if(optlen > 0) opt = context->rxbuf + 5;
				
				// Child Mode
				if(context->mode == ADHOC_MATCHING_MODE_CHILD)
				{
					// Join Request denied
					if(request == peer)
					{
						// Spawn Deny Event
						_spawnLocalEvent(context, ADHOC_MATCHING_EVENT_DENY, sendermac, optlen, opt);
						
						// Delete Peer from List
						_deletePeer(context, peer);
					}
					
					// Kicked from Room
					else if(parent == peer)
					{
						// Iterate Peers
						SceNetAdhocMatchingMemberInternal * item = context->peerlist; for(; item != NULL; item = item->next)
						{
							// Established Peer
							if(item->state == ADHOC_MATCHING_PEER_CHILD || item->state == ADHOC_MATCHING_PEER_PARENT)
							{
								// Spawn Leave / Kick Event
								_spawnLocalEvent(context, ADHOC_MATCHING_EVENT_LEAVE, &item->mac, optlen, opt);
							}
						}
						
						// Delete Peer from List
						_clearPeerList(context);
					}
				}
				
				// Parent Mode
				else if(context->mode == ADHOC_MATCHING_MODE_PARENT)
				{
					// Cancel Join Request
					if(peer->state == ADHOC_MATCHING_PEER_INCOMING_REQUEST)
					{
						// Spawn Request Cancel Event
						_spawnLocalEvent(context, ADHOC_MATCHING_EVENT_CANCEL, sendermac, optlen, opt);
						
						// Delete Peer from List
						_deletePeer(context, peer);
					}
					
					// Leave Room
					else if(peer->state == ADHOC_MATCHING_PEER_CHILD)
					{
						// Spawn Leave / Kick Event
						_spawnLocalEvent(context, ADHOC_MATCHING_EVENT_LEAVE, sendermac, optlen, opt);
						
						// Delete Peer from List
						_deletePeer(context, peer);
					}
				}
				
				// P2P Mode
				else
				{
					// Join Request denied
					if(request == peer)
					{
						// Spawn Deny Event
						_spawnLocalEvent(context, ADHOC_MATCHING_EVENT_DENY, sendermac, optlen, opt);
						
						// Delete Peer from List
						_deletePeer(context, peer);
					}
					
					// Kicked from Room
					else if(p2p == peer)
					{
						// Spawn Leave / Kick Event
						_spawnLocalEvent(context, ADHOC_MATCHING_EVENT_LEAVE, sendermac, optlen, opt);
						
						// Delete Peer from List
						_deletePeer(context, peer);
					}
					
					// Cancel Join Request
					else if(peer->state == ADHOC_MATCHING_PEER_INCOMING_REQUEST)
					{
						// Spawn Request Cancel Event
						_spawnLocalEvent(context, ADHOC_MATCHING_EVENT_CANCEL, sendermac, optlen, opt);
						
						// Delete Peer from List
						_deletePeer(context, peer);
					}
				}
			}
		}
	}
}
Example #2
0
/**
 * Select / Accept Matching Target
 * @param id Matching Context ID
 * @param target Target MAC
 * @param optlen Length of Optional Data
 * @param opt Optional Data
 * @return 0 on success or... ADHOC_MATCHING_NOT_INITIALIZED, ADHOC_MATCHING_INVALID_ARG, ADHOC_MATCHING_INVALID_ID, ADHOC_MATCHING_NOT_RUNNING, ADHOC_MATCHING_UNKNOWN_TARGET, ADHOC_MATCHING_INVALID_OPTLEN, ADHOC_MATCHING_TARGET_NOT_READY, ADHOC_MATCHING_EXCEED_MAXNUM, ADHOC_MATCHING_NO_SPACE, ADHOC_MATCHING_REQUEST_IN_PROGRESS, ADHOC_MATCHING_ALREADY_ESTABLISHED
 */
int proNetAdhocMatchingSelectTarget(int id, const SceNetEtherAddr * target, int optlen, const void * opt)
{
	// Initialized Library
	if(_init == 1)
	{
		// Valid Arguments
		if(target != NULL)
		{
			// Find Matching Context for ID
			SceNetAdhocMatchingContext * context = _findMatchingContext(id);
			
			// Found Matching Context
			if(context != NULL)
			{
				// Running Context
				if(context->running)
				{
					// Search Result
					SceNetAdhocMatchingMemberInternal * peer = _findPeer(context, (SceNetEtherAddr *)target);
					
					// Found Peer in List
					if(peer != NULL)
					{
						// Valid Optional Data Length
						if((optlen == 0 && opt == NULL) || (optlen > 0 && opt != NULL))
						{
							// Host Mode
							if(context->mode == ADHOC_MATCHING_MODE_PARENT)
							{
								// Already Connected
								if(peer->state == ADHOC_MATCHING_PEER_CHILD) return ADHOC_MATCHING_ALREADY_ESTABLISHED;
								
								// Not enough space
								if(_countChildren(context) == (context->maxpeers - 1)) return ADHOC_MATCHING_EXCEED_MAXNUM;
								
								// Requesting Peer
								if(peer->state == ADHOC_MATCHING_PEER_INCOMING_REQUEST)
								{
									// Accept Peer in Group
									peer->state = ADHOC_MATCHING_PEER_CHILD;
									
									// Send Accept Confirmation to Peer
									_sendAcceptMessage(context, peer, optlen, opt);
									
									// Tell Children about new Sibling
									_sendBirthMessage(context, peer);
									
									// Return Success
									return 0;
								}
							}
							
							// Client Mode
							else if(context->mode == ADHOC_MATCHING_MODE_CHILD)
							{
								// Already connected
								if(_findParent(context) != NULL) return ADHOC_MATCHING_ALREADY_ESTABLISHED;
								
								// Outgoing Request in Progress
								if(_findOutgoingRequest(context) != NULL) return ADHOC_MATCHING_REQUEST_IN_PROGRESS;
								
								// Valid Offer
								if(peer->state == ADHOC_MATCHING_PEER_OFFER)
								{
									// Switch into Join Request Mode
									peer->state = ADHOC_MATCHING_PEER_OUTGOING_REQUEST;
									
									// Send Join Request to Peer
									_sendJoinRequest(context, peer, optlen, opt);
									
									// Return Success
									return 0;
								}
							}
							
							// P2P Mode
							else
							{
								// Already connected
								if(_findP2P(context) != NULL) return ADHOC_MATCHING_ALREADY_ESTABLISHED;
								
								// Outgoing Request in Progress
								if(_findOutgoingRequest(context) != NULL) return ADHOC_MATCHING_REQUEST_IN_PROGRESS;
								
								// Join Request Mode
								if(peer->state == ADHOC_MATCHING_PEER_OFFER)
								{
									// Switch into Join Request Mode
									peer->state = ADHOC_MATCHING_PEER_OUTGOING_REQUEST;
									
									// Send Join Request to Peer
									_sendJoinRequest(context, peer, optlen, opt);
									
									// Return Success
									return 0;
								}
								
								// Requesting Peer
								else if(peer->state == ADHOC_MATCHING_PEER_INCOMING_REQUEST)
								{
									// Accept Peer in Group
									peer->state = ADHOC_MATCHING_PEER_P2P;
									
									// Send Accept Confirmation to Peer
									_sendAcceptMessage(context, peer, optlen, opt);
									
									// Return Success
									return 0;
								}
							}
							
							// How did this happen?! It shouldn't!
							return ADHOC_MATCHING_TARGET_NOT_READY;
						}
						
						// Invalid Optional Data Length
						return ADHOC_MATCHING_INVALID_OPTLEN;
					}
					
					// Peer not found
					return ADHOC_MATCHING_UNKNOWN_TARGET;
				}
				
				// Idle Context
				return ADHOC_MATCHING_NOT_RUNNING;
			}
			
			// Invalid Matching ID
			return ADHOC_MATCHING_INVALID_ID;
		}
		
		// Invalid Arguments
		return ADHOC_MATCHING_INVALID_ARG;
	}
	
	// Uninitialized Library
	return ADHOC_MATCHING_NOT_INITIALIZED;
}
Example #3
0
/**
 * Handle Accept Packet
 * @param context Matching Context Pointer
 * @param sendermac Packet Sender MAC
 * @param length Packet Length
 */
void _actOnAcceptPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sendermac, uint32_t length)
{
	// Not a parent context
	if(context->mode != ADHOC_MATCHING_MODE_PARENT)
	{
		// Don't have a master yet
		if((context->mode == ADHOC_MATCHING_MODE_CHILD && _findParent(context) == NULL) || (context->mode == ADHOC_MATCHING_MODE_P2P && _findP2P(context) == NULL))
		{
			// Complete Packet Header available
			if(length >= 9)
			{
				// Extract Optional Data Length
				int optlen = 0; memcpy(&optlen, context->rxbuf + 1, sizeof(optlen));
				
				// Extract Sibling Count
				int siblingcount = 0; memcpy(&siblingcount, context->rxbuf + 5, sizeof(siblingcount));
				
				// Complete Valid Packet available
				if(optlen >= 0 && length >= (9 + optlen + sizeof(SceNetEtherAddr) * siblingcount))
				{
					// Set Default Null Data
					void * opt = NULL;
					
					// Extract Optional Data Pointer
					if(optlen > 0) opt = context->rxbuf + 9;
					
					// Sibling MAC Array Null Data
					SceNetEtherAddr * siblings = NULL;
					
					// Extract Optional Sibling MAC Array
					if(siblingcount > 0) siblings = (SceNetEtherAddr *)(context->rxbuf + 9 + optlen);
					
					// Find Outgoing Request
					SceNetAdhocMatchingMemberInternal * request = _findOutgoingRequest(context);
					
					// We are waiting for a answer to our request...
					if(request != NULL)
					{
						// Find Peer
						SceNetAdhocMatchingMemberInternal * peer = _findPeer(context, sendermac);
						
						// It's the answer we wanted!
						if(request == peer)
						{
							// Change Peer State
							peer->state = (context->mode == ADHOC_MATCHING_MODE_CHILD) ? (ADHOC_MATCHING_PEER_PARENT) : (ADHOC_MATCHING_PEER_P2P);
							
							// Remove Unneeded Peer Information
							_postAcceptCleanPeerList(context);
							
							// Add Sibling Peers
							if(context->mode == ADHOC_MATCHING_MODE_CHILD) _postAcceptAddSiblings(context, siblingcount, siblings);
							
							// IMPORTANT! The Event Order here is ok!
							// Internally the Event Stack appends to the front, so the order will be switched around.
							
							// Spawn Established Event
							_spawnLocalEvent(context, ADHOC_MATCHING_EVENT_ESTABLISHED, sendermac, 0, NULL);
							
							// Spawn Accept Event
							_spawnLocalEvent(context, ADHOC_MATCHING_EVENT_ACCEPT, sendermac, optlen, opt);
						}
					}
				}
			}
		}
	}
}
Example #4
0
/**
 * Handle Join Packet
 * @param context Matching Context Pointer
 * @param sendermac Packet Sender MAC
 * @param length Packet Length
 */
void _actOnJoinPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sendermac, uint32_t length)
{
	// Not a child mode context
	if(context->mode != ADHOC_MATCHING_MODE_CHILD)
	{
		// We still got a unoccupied slot in our room (Parent / P2P)
		if((context->mode == ADHOC_MATCHING_MODE_PARENT && _countChildren(context) < (context->maxpeers - 1)) || (context->mode == ADHOC_MATCHING_MODE_P2P && _findP2P(context) == NULL))
		{
			// Complete Packet Header available
			if(length >= 5)
			{
				// Extract Optional Data Length
				int optlen = 0; memcpy(&optlen, context->rxbuf + 1, sizeof(optlen));
				
				// Complete Valid Packet available
				if(optlen >= 0 && length >= (5 + optlen))
				{
					// Set Default Null Data
					void * opt = NULL;
					
					// Extract Optional Data Pointer
					if(optlen > 0) opt = context->rxbuf + 5;
					
					// Find Peer
					SceNetAdhocMatchingMemberInternal * peer = _findPeer(context, sendermac);
					
					// If we got the peer in the table already and are a parent, there is nothing left to be done.
					// This is because the only way a parent can know of a child is via a join request...
					// If we thus know of a possible child, then we already had a previous join request thus no need for double tapping.
					if(peer != NULL && context->mode == ADHOC_MATCHING_MODE_PARENT) return;
					
					// New Peer
					if(peer == NULL)
					{
						// Allocate Memory
						peer = (SceNetAdhocMatchingMemberInternal *)_malloc(sizeof(SceNetAdhocMatchingMemberInternal));
						
						// Allocated Memory
						if(peer != NULL)
						{
							// Clear Memory
							memset(peer, 0, sizeof(SceNetAdhocMatchingMemberInternal));
							
							// Copy Sender MAC
							peer->mac = *sendermac;
							
							// Set Peer State
							peer->state = ADHOC_MATCHING_PEER_INCOMING_REQUEST;
							
							// Initialize Ping Timer
							peer->lastping = sceKernelGetSystemTimeWide();
							
							// Link Peer into List
							peer->next = context->peerlist;
							context->peerlist = peer;
							
							// Spawn Request Event
							_spawnLocalEvent(context, ADHOC_MATCHING_EVENT_REQUEST, sendermac, optlen, opt);
							
							// Return Success
							return;
						}
					}
					
					// Existing Peer (this case is only reachable for P2P mode)
					else
					{
						// Set Peer State
						peer->state = ADHOC_MATCHING_PEER_INCOMING_REQUEST;
						
						// Spawn Request Event
						_spawnLocalEvent(context, ADHOC_MATCHING_EVENT_REQUEST, sendermac, optlen, opt);
						
						// Return Success
						return;
					}
				}
			}
		}
		
		// Auto-Reject Player
		_sendCancelPacket(context, sendermac, 0, NULL);
	}
}
Example #5
0
/**
 * Handle Hello Packet
 * @param context Matching Context Pointer
 * @param sendermac Packet Sender MAC
 * @param length Packet Length
 */
void _actOnHelloPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sendermac, uint32_t length)
{
	// Interested in Hello Data
	if((context->mode == ADHOC_MATCHING_MODE_CHILD && _findParent(context) == NULL) || (context->mode == ADHOC_MATCHING_MODE_P2P && _findP2P(context) == NULL))
	{
		// Complete Packet Header available
		if(length >= 5)
		{
			// Extract Optional Data Length
			int optlen = 0; memcpy(&optlen, context->rxbuf + 1, sizeof(optlen));
			
			// Complete Valid Packet available
			if(optlen >= 0 && length >= (5 + optlen))
			{
				// Set Default Null Data
				void * opt = NULL;
				
				// Extract Optional Data Pointer
				if(optlen > 0) opt = context->rxbuf + 5;
				
				// Find Peer
				SceNetAdhocMatchingMemberInternal * peer = _findPeer(context, sendermac);
				
				// Peer not found
				if(peer == NULL)
				{
					// Allocate Memory
					peer = (SceNetAdhocMatchingMemberInternal *)_malloc(sizeof(SceNetAdhocMatchingMemberInternal));
					
					// Allocated Memory
					if(peer != NULL)
					{
						// Clear Memory
						memset(peer, 0, sizeof(SceNetAdhocMatchingMemberInternal));
						
						// Copy Sender MAC
						peer->mac = *sendermac;
						
						// Set Peer State
						peer->state = ADHOC_MATCHING_PEER_OFFER;
						
						// Initialize Ping Timer
						peer->lastping = sceKernelGetSystemTimeWide();
						
						// Link Peer into List
						peer->next = context->peerlist;
						context->peerlist = peer;
					}
				}
				
				// Peer available now
				if(peer != NULL)
				{
					// Spawn Hello Event
					_spawnLocalEvent(context, ADHOC_MATCHING_EVENT_HELLO, sendermac, optlen, opt);
				}
			}
		}
	}
}
Example #6
0
/**
 * Matching IO Handler Thread
 * @param args sizeof(SceNetAdhocMatchingContext *)
 * @param argp SceNetAdhocMatchingContext *
 * @return Exit Point is never reached...
 */
int _matchingInputThread(uint32_t args, void * argp)
{
	// Cast Context
	SceNetAdhocMatchingContext * context = *(SceNetAdhocMatchingContext **)argp;
	
	// Last Ping
	uint64_t lastping = 0;
	
	// Last Hello
	uint64_t lasthello = 0;
	
	// Run while needed...
	while(context->input_thid > 0)
	{
		// Hello Message Sending Context with unoccupied Slots
		if((context->mode == ADHOC_MATCHING_MODE_PARENT && _countChildren(context) < (context->maxpeers - 1)) || (context->mode == ADHOC_MATCHING_MODE_P2P && _findP2P(context) == NULL))
		{
			// Hello Message Broadcast necessary because of Hello Interval
			if((sceKernelGetSystemTimeWide() - lasthello) >= context->hello_int)
			{
				// Broadcast Hello Message
				_broadcastHelloMessage(context);
				
				// Update Hello Timer
				lasthello = sceKernelGetSystemTimeWide();
			}
		}
		
		// Ping Required
		if((sceKernelGetSystemTimeWide() - lastping) >= context->keepalive_int)
		{
			// Broadcast Ping Message
			_broadcastPingMessage(context);
			
			// Update Ping Timer
			lastping = sceKernelGetSystemTimeWide();
		}
		
		// Messages on Stack ready for processing
		if(context->input_stack != NULL && context->input_stack_lock == 0)
		{
			// Claim Stack
			context->input_stack_lock = 1;
			
			// Iterate Message List
			ThreadMessage * msg = context->input_stack; for(; msg != NULL; msg = msg->next)
			{
				// Default Optional Data
				void * opt = NULL;
				
				// Grab Optional Data
				if(msg->optlen > 0) opt = ((void *)msg) + sizeof(ThreadMessage);
				
				// Send Accept Packet
				if(msg->opcode == ADHOC_MATCHING_PACKET_ACCEPT) _sendAcceptPacket(context, &msg->mac, msg->optlen, opt);
				
				// Send Join Packet
				else if(msg->opcode == ADHOC_MATCHING_PACKET_JOIN) _sendJoinPacket(context, &msg->mac, msg->optlen, opt);
				
				// Send Cancel Packet
				else if(msg->opcode == ADHOC_MATCHING_PACKET_CANCEL) _sendCancelPacket(context, &msg->mac, msg->optlen, opt);
				
				// Send Bulk Data Packet
				else if(msg->opcode == ADHOC_MATCHING_PACKET_BULK) _sendBulkDataPacket(context, &msg->mac, msg->optlen, opt);
				
				// Send Birth Packet
				else if(msg->opcode == ADHOC_MATCHING_PACKET_BIRTH) _sendBirthPacket(context, &msg->mac);
				
				// Cancel Bulk Data Transfer (does nothing as of now as we fire and forget anyway)
				// else if(msg->opcode == ADHOC_MATCHING_PACKET_BULK_ABORT) blabla;
			}
			
			// Clear IO Message Stack
			_clearStack(context, ADHOC_MATCHING_INPUT_STACK);
			
			// Free Stack
			context->input_stack_lock = 0;
		}
		
		// Receive PDP Datagram
		SceNetEtherAddr sendermac;
		uint16_t senderport;
		int rxbuflen = context->rxbuflen;
		int recvresult = sceNetAdhocPdpRecv(context->socket, &sendermac, &senderport, context->rxbuf, &rxbuflen, 0, ADHOC_F_NONBLOCK);
		
		// Received Data from a Sender that interests us
		if(recvresult == 0 && rxbuflen > 0 && context->port == senderport)
		{
			// Log Receive Success
			printk("Received %d Bytes (Opcode: %d)\n", rxbuflen, context->rxbuf[0]);
			
			// Ping Packet
			if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_PING) _actOnPingPacket(context, &sendermac);
			
			// Hello Packet
			else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_HELLO) _actOnHelloPacket(context, &sendermac, rxbuflen);
			
			// Join Packet
			else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_JOIN) _actOnJoinPacket(context, &sendermac, rxbuflen);
			
			// Accept Packet
			else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_ACCEPT) _actOnAcceptPacket(context, &sendermac, rxbuflen);
			
			// Cancel Packet
			else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_CANCEL) _actOnCancelPacket(context, &sendermac, rxbuflen);
			
			// Bulk Data Packet
			else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_BULK) _actOnBulkDataPacket(context, &sendermac, rxbuflen);
			
			// Birth Packet
			else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_BIRTH) _actOnBirthPacket(context, &sendermac, rxbuflen);
			
			// Death Packet
			else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_DEATH) _actOnDeathPacket(context, &sendermac, rxbuflen);
			
			// Bye Packet
			else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_BYE) _actOnByePacket(context, &sendermac);
			
			// Ignore Incoming Trash Data
		}
		
		// Handle Peer Timeouts
		_handleTimeout(context);
		
		// Share CPU Time
		sceKernelDelayThread(10000);
	}
	
	// Send Bye Messages
	_sendByePacket(context);
	
	// Free Peer List Buffer
	_clearPeerList(context);
	
	// Delete Pointer Reference (and notify caller about finished cleanup)
	context->input_thid = 0;
	
	// Terminate Thread
	sceKernelExitDeleteThread(0);
	
	// Return Zero to shut up Compiler (never reached anyway)
	return 0;
}
Example #7
0
/**
 * Get Member List
 * @return 0 on success or... ADHOC_MATCHING_NOT_INITIALIZED, ADHOC_MATCHING_INVALID_ARG, ADHOC_MATCHING_INVALID_ID, ADHOC_MATCHING_NOT_RUNNING
 */
int proNetAdhocMatchingGetMembers(int id, int * buflen, SceNetAdhocMatchingMember * buf)
{
	// Initialized Library
	if(_init == 1)
	{
		// Find Matching Context
		SceNetAdhocMatchingContext * context = _findMatchingContext(id);
		
		// Found Context
		if(context != NULL)
		{
			// Running Context
			if(context->running)
			{
				// Length Buffer available
				if(buflen != NULL)
				{
					// Number of Connected Peers
					uint32_t peercount = _countConnectedPeers(context);
					
					// Calculate Connected Peer Bytesize
					int available = sizeof(SceNetAdhocMatchingMember) * peercount;
					
					// Length Returner Mode
					if(buf == NULL)
					{
						// Get Connected Peer Count
						*buflen = available;
					}
					
					// Normal Mode
					else
					{
						// Fix Negative Length
						if((*buflen) < 0) *buflen = 0;
						
						// Fix Oversize Request
						if((*buflen) > available) *buflen = available;
						
						// Clear Memory
						memset(buf, 0, *buflen);
						
						// Calculate Requested Peer Count
						int requestedpeers = (*buflen) / sizeof(SceNetAdhocMatchingMember);
						
						// Filled Request Counter
						int filledpeers = 0;
						
						// Add Self-Peer
						if(requestedpeers > 0)
						{
							// Add Local MAC
							buf[filledpeers++].addr = context->mac;
							
							// Room for more than local peer
							if(requestedpeers > 1)
							{
								// P2P Mode
								if(context->mode == ADHOC_MATCHING_MODE_P2P)
								{
									// Find P2P Brother
									SceNetAdhocMatchingMemberInternal * p2p = _findP2P(context);
									
									// P2P Brother found
									if(p2p != NULL)
									{
										// Add P2P Brother MAC
										buf[filledpeers++].addr = p2p->mac;
									}
								}
								
								// Parent or Child Mode
								else
								{
									// Iterate Peer List
									SceNetAdhocMatchingMemberInternal * peer = context->peerlist; for(; peer != NULL && filledpeers < requestedpeers; peer = peer->next)
									{
										// Parent Mode
										if(context->mode == ADHOC_MATCHING_MODE_PARENT)
										{
											// Interested in Children (Michael Jackson Style)
											if(peer->state == ADHOC_MATCHING_PEER_CHILD)
											{
												// Add Child MAC
												buf[filledpeers++].addr = peer->mac;
											}
										}
										
										// Children Mode
										else
										{
											// Interested in Parent & Siblings
											if(peer->state == ADHOC_MATCHING_PEER_CHILD || peer->state == ADHOC_MATCHING_PEER_PARENT)
											{
												// Add Peer MAC
												buf[filledpeers++].addr = peer->mac;
											}
										}
									}
								}
								
								// Link Result List
								int i = 0; for(; i < filledpeers - 1; i++)
								{
									// Link Next Element
									buf[i].next = &buf[i + 1];
								}
							}
						}
						
						// Fix Buffer Size
						*buflen = sizeof(SceNetAdhocMatchingMember) * filledpeers;
					}
					
					// Return Success
					return 0;
				}
				
				// Invalid Arguments
				return ADHOC_MATCHING_INVALID_ARG;
			}
			
			// Context not running
			return ADHOC_MATCHING_NOT_RUNNING;
		}
		
		// Invalid Matching ID
		return ADHOC_MATCHING_INVALID_ID;
	}
	
	// Uninitialized Library
	return ADHOC_MATCHING_NOT_INITIALIZED;
}