Blame opensm/osm_sa_mcmember_record.c

Packit 13e616
/*
Packit 13e616
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit 13e616
 * Copyright (c) 2002-2015 Mellanox Technologies LTD. All rights reserved.
Packit 13e616
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit 13e616
 * Copyright (c) 2008 Xsigo Systems Inc.  All rights reserved.
Packit 13e616
 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
Packit 13e616
 *
Packit 13e616
 * This software is available to you under a choice of one of two
Packit 13e616
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit 13e616
 * General Public License (GPL) Version 2, available from the file
Packit 13e616
 * COPYING in the main directory of this source tree, or the
Packit 13e616
 * OpenIB.org BSD license below:
Packit 13e616
 *
Packit 13e616
 *     Redistribution and use in source and binary forms, with or
Packit 13e616
 *     without modification, are permitted provided that the following
Packit 13e616
 *     conditions are met:
Packit 13e616
 *
Packit 13e616
 *      - Redistributions of source code must retain the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer.
Packit 13e616
 *
Packit 13e616
 *      - Redistributions in binary form must reproduce the above
Packit 13e616
 *        copyright notice, this list of conditions and the following
Packit 13e616
 *        disclaimer in the documentation and/or other materials
Packit 13e616
 *        provided with the distribution.
Packit 13e616
 *
Packit 13e616
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 13e616
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 13e616
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 13e616
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit 13e616
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit 13e616
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 13e616
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit 13e616
 * SOFTWARE.
Packit 13e616
 *
Packit 13e616
 */
Packit 13e616
Packit 13e616
/*
Packit 13e616
 * Abstract:
Packit 13e616
 *    Implementation of osm_mcmr_recv_t.
Packit 13e616
 * This object represents the MCMemberRecord Receiver object.
Packit 13e616
 * This object is part of the opensm family of objects.
Packit 13e616
 */
Packit 13e616
Packit 13e616
#if HAVE_CONFIG_H
Packit 13e616
#  include <config.h>
Packit 13e616
#endif				/* HAVE_CONFIG_H */
Packit 13e616
Packit 13e616
#include <stdlib.h>
Packit 13e616
#include <string.h>
Packit 13e616
#include <arpa/inet.h>
Packit 13e616
#include <iba/ib_types.h>
Packit 13e616
#include <complib/cl_qmap.h>
Packit 13e616
#include <complib/cl_passivelock.h>
Packit 13e616
#include <complib/cl_debug.h>
Packit 13e616
#include <complib/cl_qlist.h>
Packit 13e616
#include <opensm/osm_file_ids.h>
Packit 13e616
#define FILE_ID OSM_FILE_SA_MCMEMBER_RECORD_C
Packit 13e616
#include <vendor/osm_vendor_api.h>
Packit 13e616
#include <opensm/osm_madw.h>
Packit 13e616
#include <opensm/osm_log.h>
Packit 13e616
#include <opensm/osm_subnet.h>
Packit 13e616
#include <opensm/osm_mad_pool.h>
Packit 13e616
#include <opensm/osm_helper.h>
Packit 13e616
#include <opensm/osm_msgdef.h>
Packit 13e616
#include <opensm/osm_pkey.h>
Packit 13e616
#include <opensm/osm_inform.h>
Packit 13e616
#include <opensm/osm_sa.h>
Packit 13e616
Packit 13e616
#define SA_MCM_RESP_SIZE SA_ITEM_RESP_SIZE(mc_rec)
Packit 13e616
Packit 13e616
#define JOIN_MC_COMP_MASK (IB_MCR_COMPMASK_MGID | \
Packit 13e616
				IB_MCR_COMPMASK_PORT_GID | \
Packit 13e616
				IB_MCR_COMPMASK_JOIN_STATE)
Packit 13e616
Packit 13e616
#define REQUIRED_MC_CREATE_COMP_MASK (IB_MCR_COMPMASK_MGID | \
Packit 13e616
					IB_MCR_COMPMASK_PORT_GID | \
Packit 13e616
					IB_MCR_COMPMASK_JOIN_STATE | \
Packit 13e616
					IB_MCR_COMPMASK_QKEY | \
Packit 13e616
					IB_MCR_COMPMASK_TCLASS | \
Packit 13e616
					IB_MCR_COMPMASK_PKEY | \
Packit 13e616
					IB_MCR_COMPMASK_FLOW | \
Packit 13e616
					IB_MCR_COMPMASK_SL)
Packit 13e616
Packit 13e616
#define IPV4_BCAST_MGID_PREFIX CL_HTON64(0xff10401b00000000ULL)
Packit 13e616
#define IPV4_BCAST_MGID_INT_ID CL_HTON64(0x00000000ffffffffULL)
Packit 13e616
Packit 13e616
static int validate_other_comp_fields(osm_log_t * p_log, ib_net64_t comp_mask,
Packit 13e616
				      const ib_member_rec_t * p_mcmr,
Packit 13e616
				      osm_mgrp_t * p_mgrp,
Packit 13e616
				      osm_log_level_t log_level);
Packit 13e616
Packit 13e616
/*********************************************************************
Packit 13e616
 Copy certain fields between two mcmember records
Packit 13e616
 used during the process of join request to copy data from the mgrp
Packit 13e616
 to the port record.
Packit 13e616
**********************************************************************/
Packit 13e616
static void copy_from_create_mc_rec(IN ib_member_rec_t * dest,
Packit 13e616
				    IN const ib_member_rec_t * src)
Packit 13e616
{
Packit 13e616
	dest->qkey = src->qkey;
Packit 13e616
	dest->mlid = src->mlid;
Packit 13e616
	dest->tclass = src->tclass;
Packit 13e616
	dest->pkey = src->pkey;
Packit 13e616
	dest->sl_flow_hop = src->sl_flow_hop;
Packit 13e616
	dest->scope_state = ib_member_set_scope_state(src->scope_state >> 4,
Packit 13e616
						      dest->scope_state & 0x0F);
Packit 13e616
	dest->mtu = src->mtu;
Packit 13e616
	dest->rate = src->rate;
Packit 13e616
	dest->pkt_life = src->pkt_life;
Packit 13e616
}
Packit 13e616
Packit 13e616
/*********************************************************************
Packit 13e616
 Return mlid to the pool of free mlids.
Packit 13e616
 But this implementation is not a pool - it simply scans through
Packit 13e616
 the MGRP database for unused mlids...
Packit 13e616
*********************************************************************/
Packit 13e616
static void free_mlid(IN osm_sa_t * sa, IN uint16_t mlid)
Packit 13e616
{
Packit 13e616
	UNUSED_PARAM(sa);
Packit 13e616
	UNUSED_PARAM(mlid);
Packit 13e616
}
Packit 13e616
Packit 13e616
/*********************************************************************
Packit 13e616
 Get a new unused mlid by scanning all the used ones in the subnet.
Packit 13e616
**********************************************************************/
Packit 13e616
/* Special Case IPv6 Solicited Node Multicast (SNM) addresses */
Packit 13e616
/* 0xff1Z601bXXXX0000 : 0x00000001ffYYYYYY */
Packit 13e616
/* Where Z is the scope, XXXX is the P_Key, and
Packit 13e616
 * YYYYYY is the last 24 bits of the port guid */
Packit 13e616
#define PREFIX_MASK CL_HTON64(0xff10ffff0000ffffULL)
Packit 13e616
#define PREFIX_SIGNATURE CL_HTON64(0xff10601b00000000ULL)
Packit 13e616
#define INT_ID_MASK CL_HTON64(0xfffffff1ff000000ULL)
Packit 13e616
#define INT_ID_SIGNATURE CL_HTON64(0x00000001ff000000ULL)
Packit 13e616
Packit 13e616
static int compare_ipv6_snm_mgids(const void *m1, const void *m2)
Packit 13e616
{
Packit 13e616
	return memcmp(m1, m2, sizeof(ib_gid_t) - 3);
Packit 13e616
}
Packit 13e616
Packit 13e616
static ib_net16_t find_ipv6_snm_mlid(osm_subn_t *subn, ib_gid_t *mgid)
Packit 13e616
{
Packit 13e616
	osm_mgrp_t *m = (osm_mgrp_t *)cl_fmap_match(&subn->mgrp_mgid_tbl, mgid,
Packit 13e616
						    compare_ipv6_snm_mgids);
Packit 13e616
	if (m != (osm_mgrp_t *)cl_fmap_end(&subn->mgrp_mgid_tbl))
Packit 13e616
		return m->mlid;
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static unsigned match_ipv6_snm_mgid(ib_gid_t * mgid)
Packit 13e616
{
Packit 13e616
	return ((mgid->unicast.prefix & PREFIX_MASK) == PREFIX_SIGNATURE &&
Packit 13e616
		(mgid->unicast.interface_id & INT_ID_MASK) == INT_ID_SIGNATURE);
Packit 13e616
}
Packit 13e616
Packit 13e616
static ib_net16_t get_new_mlid(osm_sa_t * sa, ib_member_rec_t * mcmr)
Packit 13e616
{
Packit 13e616
	osm_subn_t *p_subn = sa->p_subn;
Packit 13e616
	ib_net16_t requested_mlid = mcmr->mlid;
Packit 13e616
	unsigned i, max;
Packit 13e616
Packit 13e616
	if (requested_mlid && cl_ntoh16(requested_mlid) >= IB_LID_MCAST_START_HO
Packit 13e616
	    && cl_ntoh16(requested_mlid) <= p_subn->max_mcast_lid_ho
Packit 13e616
	    && !osm_get_mbox_by_mlid(p_subn, requested_mlid))
Packit 13e616
		return requested_mlid;
Packit 13e616
Packit 13e616
	if (sa->p_subn->opt.consolidate_ipv6_snm_req
Packit 13e616
	    && match_ipv6_snm_mgid(&mcmr->mgid)
Packit 13e616
	    && (requested_mlid = find_ipv6_snm_mlid(sa->p_subn, &mcmr->mgid))) {
Packit 13e616
		char str[INET6_ADDRSTRLEN];
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Special Case Solicited Node Mcast Join for MGID %s\n",
Packit 13e616
			inet_ntop(AF_INET6, mcmr->mgid.raw, str, sizeof(str)));
Packit 13e616
		return requested_mlid;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	max = p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO + 1;
Packit 13e616
	for (i = 0; i < max; i++)
Packit 13e616
		if (!sa->p_subn->mboxes[i])
Packit 13e616
			return cl_hton16(i + IB_LID_MCAST_START_HO);
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
static inline boolean_t check_join_comp_mask(ib_net64_t comp_mask)
Packit 13e616
{
Packit 13e616
	return ((comp_mask & JOIN_MC_COMP_MASK) == JOIN_MC_COMP_MASK);
Packit 13e616
}
Packit 13e616
Packit 13e616
static boolean_t check_create_comp_mask(ib_net64_t comp_mask,
Packit 13e616
					ib_member_rec_t * p_recvd_mcmember_rec)
Packit 13e616
{
Packit 13e616
	return ((comp_mask & REQUIRED_MC_CREATE_COMP_MASK) ==
Packit 13e616
		REQUIRED_MC_CREATE_COMP_MASK);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Generate the response MAD
Packit 13e616
**********************************************************************/
Packit 13e616
static void mcmr_rcv_respond(IN osm_sa_t * sa, IN osm_madw_t * p_madw,
Packit 13e616
			     IN ib_member_rec_t * p_mcmember_rec)
Packit 13e616
{
Packit 13e616
	cl_qlist_t rec_list;
Packit 13e616
	osm_sa_item_t *item;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	item = malloc(SA_MCM_RESP_SIZE);
Packit 13e616
	if (!item) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B16: "
Packit 13e616
			"rec_item alloc failed\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	item->resp.mc_rec = *p_mcmember_rec;
Packit 13e616
Packit 13e616
	/* Fill in the mtu, rate, and packet lifetime selectors */
Packit 13e616
	item->resp.mc_rec.mtu &= 0x3f;
Packit 13e616
	item->resp.mc_rec.mtu |= IB_PATH_SELECTOR_EXACTLY << 6;
Packit 13e616
	item->resp.mc_rec.rate &= 0x3f;
Packit 13e616
	item->resp.mc_rec.rate |= IB_PATH_SELECTOR_EXACTLY << 6;
Packit 13e616
	item->resp.mc_rec.pkt_life &= 0x3f;
Packit 13e616
	item->resp.mc_rec.pkt_life |= IB_PATH_SELECTOR_EXACTLY << 6;
Packit 13e616
Packit 13e616
	cl_qlist_init(&rec_list);
Packit 13e616
	cl_qlist_insert_tail(&rec_list, &item->list_item);
Packit 13e616
Packit 13e616
	osm_sa_respond(sa, p_madw, sizeof(ib_member_rec_t), &rec_list);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/*********************************************************************
Packit 13e616
 In joining an existing group, or when querying the mc groups,
Packit 13e616
 we make sure the following components provided match: MTU and RATE
Packit 13e616
 HACK: Currently we ignore the PKT_LIFETIME field.
Packit 13e616
**********************************************************************/
Packit 13e616
static boolean_t validate_more_comp_fields(osm_log_t * p_log,
Packit 13e616
					   const osm_mgrp_t * p_mgrp,
Packit 13e616
					   const ib_member_rec_t *
Packit 13e616
					   p_recvd_mcmember_rec,
Packit 13e616
					   ib_net64_t comp_mask)
Packit 13e616
{
Packit 13e616
	uint8_t mtu_sel;
Packit 13e616
	uint8_t mtu_required;
Packit 13e616
	uint8_t mtu_mgrp;
Packit 13e616
	uint8_t rate_sel;
Packit 13e616
	uint8_t rate_required;
Packit 13e616
	uint8_t rate_mgrp;
Packit 13e616
Packit 13e616
	if (comp_mask & IB_MCR_COMPMASK_MTU_SEL) {
Packit 13e616
		mtu_sel = (uint8_t) (p_recvd_mcmember_rec->mtu >> 6);
Packit 13e616
		/* Clearing last 2 bits */
Packit 13e616
		mtu_required = (uint8_t) (p_recvd_mcmember_rec->mtu & 0x3F);
Packit 13e616
		mtu_mgrp = (uint8_t) (p_mgrp->mcmember_rec.mtu & 0x3F);
Packit 13e616
		switch (mtu_sel) {
Packit 13e616
		case 0:	/* Greater than MTU specified */
Packit 13e616
			if (mtu_mgrp <= mtu_required) {
Packit 13e616
				OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Requested mcast group has MTU %x, "
Packit 13e616
					"which is not greater than %x\n",
Packit 13e616
					mtu_mgrp, mtu_required);
Packit 13e616
				return FALSE;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
		case 1:	/* Less than MTU specified */
Packit 13e616
			if (mtu_mgrp >= mtu_required) {
Packit 13e616
				OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Requested mcast group has MTU %x, "
Packit 13e616
					"which is not less than %x\n",
Packit 13e616
					mtu_mgrp, mtu_required);
Packit 13e616
				return FALSE;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
		case 2:	/* Exactly MTU specified */
Packit 13e616
			if (mtu_mgrp != mtu_required) {
Packit 13e616
				OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Requested mcast group has MTU %x, "
Packit 13e616
					"which is not equal to %x\n",
Packit 13e616
					mtu_mgrp, mtu_required);
Packit 13e616
				return FALSE;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
		default:
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* what about rate ? */
Packit 13e616
	if (comp_mask & IB_MCR_COMPMASK_RATE_SEL) {
Packit 13e616
		rate_sel = (uint8_t) (p_recvd_mcmember_rec->rate >> 6);
Packit 13e616
		/* Clearing last 2 bits */
Packit 13e616
		rate_required = (uint8_t) (p_recvd_mcmember_rec->rate & 0x3F);
Packit 13e616
		rate_mgrp = (uint8_t) (p_mgrp->mcmember_rec.rate & 0x3F);
Packit 13e616
		switch (rate_sel) {
Packit 13e616
		case 0:	/* Greater than RATE specified */
Packit 13e616
			if (ib_path_compare_rates(rate_mgrp, rate_required) <= 0) {
Packit 13e616
				OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Requested mcast group has RATE %x, "
Packit 13e616
					"which is not greater than %x\n",
Packit 13e616
					rate_mgrp, rate_required);
Packit 13e616
				return FALSE;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
		case 1:	/* Less than RATE specified */
Packit 13e616
			if (ib_path_compare_rates(rate_mgrp, rate_required) >= 0) {
Packit 13e616
				OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Requested mcast group has RATE %x, "
Packit 13e616
					"which is not less than %x\n",
Packit 13e616
					rate_mgrp, rate_required);
Packit 13e616
				return FALSE;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
		case 2:	/* Exactly RATE specified */
Packit 13e616
			if (ib_path_compare_rates(rate_mgrp, rate_required)) {
Packit 13e616
				OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Requested mcast group has RATE %x, "
Packit 13e616
					"which is not equal to %x\n",
Packit 13e616
					rate_mgrp, rate_required);
Packit 13e616
				return FALSE;
Packit 13e616
			}
Packit 13e616
			break;
Packit 13e616
		default:
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return TRUE;
Packit 13e616
}
Packit 13e616
Packit 13e616
/*********************************************************************
Packit 13e616
 In joining an existing group, we make sure the following components
Packit 13e616
 are physically realizable: MTU and RATE
Packit 13e616
**********************************************************************/
Packit 13e616
static boolean_t validate_port_caps(osm_log_t * p_log,
Packit 13e616
				    const osm_mgrp_t * p_mgrp,
Packit 13e616
				    const osm_physp_t * p_physp)
Packit 13e616
{
Packit 13e616
	const ib_port_info_t *p_pi;
Packit 13e616
	uint8_t mtu_required;
Packit 13e616
	uint8_t mtu_mgrp;
Packit 13e616
	uint8_t rate_required;
Packit 13e616
	uint8_t rate_mgrp;
Packit 13e616
	int extended;
Packit 13e616
Packit 13e616
	mtu_required = ib_port_info_get_neighbor_mtu(&p_physp->port_info);
Packit 13e616
	mtu_mgrp = (uint8_t) (p_mgrp->mcmember_rec.mtu & 0x3F);
Packit 13e616
	if (mtu_required < mtu_mgrp) {
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Port's MTU %x is less than %x\n",
Packit 13e616
			mtu_required, mtu_mgrp);
Packit 13e616
		return FALSE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_pi = &p_physp->port_info;
Packit 13e616
	extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit 13e616
	rate_required = ib_port_info_compute_rate(p_pi, extended);
Packit 13e616
	rate_mgrp = (uint8_t) (p_mgrp->mcmember_rec.rate & 0x3F);
Packit 13e616
	if (ib_path_compare_rates(rate_required, rate_mgrp) < 0) {
Packit 13e616
		OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Port's RATE %x is less than %x\n",
Packit 13e616
			rate_required, rate_mgrp);
Packit 13e616
		return FALSE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return TRUE;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 * o15-0.2.1: If SA supports UD multicast, then if SA receives a SubnAdmSet()
Packit 13e616
 * or SubnAdmDelete() method that would modify an existing
Packit 13e616
 * MCMemberRecord, SA shall not modify that MCMemberRecord and shall
Packit 13e616
 * return an error status of ERR_REQ_INVALID in response in the
Packit 13e616
 * following cases:
Packit 13e616
 * 1. Saved MCMemberRecord.ProxyJoin is not set and the request is
Packit 13e616
 * issued by a requester with a GID other than the Port-GID.
Packit 13e616
 * 2. Saved MCMemberRecord.ProxyJoin is set and the requester is not
Packit 13e616
 * part of the partition for that MCMemberRecord.
Packit 13e616
 **********************************************************************/
Packit 13e616
static boolean_t validate_modify(IN osm_sa_t * sa, IN osm_mgrp_t * p_mgrp,
Packit 13e616
				 IN osm_mad_addr_t * p_mad_addr,
Packit 13e616
				 IN ib_member_rec_t * p_recvd_mcmember_rec,
Packit 13e616
				 OUT osm_mcm_alias_guid_t ** pp_mcm_alias_guid)
Packit 13e616
{
Packit 13e616
	ib_net64_t portguid;
Packit 13e616
	ib_gid_t request_gid;
Packit 13e616
	osm_physp_t *p_request_physp;
Packit 13e616
	ib_api_status_t res;
Packit 13e616
Packit 13e616
	portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id;
Packit 13e616
Packit 13e616
	*pp_mcm_alias_guid = osm_mgrp_get_mcm_alias_guid(p_mgrp, portguid);
Packit 13e616
Packit 13e616
	/* o15-0.2.1: If this is a new port being added - nothing to check */
Packit 13e616
	if (!*pp_mcm_alias_guid) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"This is a new port in the MC group\n");
Packit 13e616
		return TRUE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* We validate the request according the the proxy_join.
Packit 13e616
	   Check if the proxy_join is set or not */
Packit 13e616
	if ((*pp_mcm_alias_guid)->proxy_join == FALSE) {
Packit 13e616
		/* The proxy_join is not set. Modifying can by done only
Packit 13e616
		   if the requester GID == PortGID */
Packit 13e616
		res = osm_get_gid_by_mad_addr(sa->p_log, sa->p_subn, p_mad_addr,
Packit 13e616
					      &request_gid);
Packit 13e616
		if (res != IB_SUCCESS) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Could not find port for requested address\n");
Packit 13e616
			return FALSE;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if ((*pp_mcm_alias_guid)->p_base_mcm_port->port->guid !=
Packit 13e616
		    request_gid.unicast.interface_id ||
Packit 13e616
		    (*pp_mcm_alias_guid)->port_gid.unicast.prefix !=
Packit 13e616
		    request_gid.unicast.prefix) {
Packit 13e616
			ib_gid_t base_port_gid;
Packit 13e616
			char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
			char gid_str2[INET6_ADDRSTRLEN];
Packit 13e616
Packit 13e616
			base_port_gid.unicast.prefix = (*pp_mcm_alias_guid)->port_gid.unicast.prefix;
Packit 13e616
			base_port_gid.unicast.interface_id = (*pp_mcm_alias_guid)->p_base_mcm_port->port->guid;
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"No ProxyJoin but different ports: stored:"
Packit 13e616
				"%s request:%s\n",
Packit 13e616
				inet_ntop(AF_INET6, base_port_gid.raw, gid_str,
Packit 13e616
					  sizeof gid_str),
Packit 13e616
				inet_ntop(AF_INET6, request_gid.raw, gid_str2,
Packit 13e616
					  sizeof gid_str2));
Packit 13e616
			return FALSE;
Packit 13e616
		}
Packit 13e616
	} else {
Packit 13e616
		/* The proxy_join is set. Modification allowed only if the
Packit 13e616
		   requester is part of the partition for this MCMemberRecord */
Packit 13e616
		p_request_physp = osm_get_physp_by_mad_addr(sa->p_log,
Packit 13e616
							    sa->p_subn,
Packit 13e616
							    p_mad_addr);
Packit 13e616
		if (p_request_physp == NULL)
Packit 13e616
			return FALSE;
Packit 13e616
Packit 13e616
		if (!osm_physp_has_pkey(sa->p_log, p_mgrp->mcmember_rec.pkey,
Packit 13e616
					p_request_physp)) {
Packit 13e616
			/* the request port is not part of the partition for this mgrp */
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Requesting port 0x%016" PRIx64 " has no PKey 0x%04x\n",
Packit 13e616
				cl_ntoh64(p_request_physp->port_guid),
Packit 13e616
				cl_ntoh16(p_mgrp->mcmember_rec.pkey));
Packit 13e616
			return FALSE;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	return TRUE;
Packit 13e616
}
Packit 13e616
Packit 13e616
/*
Packit 13e616
 * Check legality of the requested MGID DELETE
Packit 13e616
 * o15-0.1.14 = VALID DELETE:
Packit 13e616
 * To be a valid delete MAD needs to:
Packit 13e616
 * 1 the MADs PortGID and MGID components match the PortGID and
Packit 13e616
 *   MGID of a stored MCMemberRecord;
Packit 13e616
 * 2 the MADs JoinState component contains at least one bit set to 1
Packit 13e616
 *   in the same position as that stored MCMemberRecords JoinState
Packit 13e616
 *   has a bit set to 1,
Packit 13e616
 *   i.e., the logical AND of the two JoinState components
Packit 13e616
 *   is not all zeros;
Packit 13e616
 * 3 the MADs JoinState component does not have some bits set
Packit 13e616
 *   which are not set in the stored MCMemberRecords JoinState component;
Packit 13e616
 * 4 either the stored MCMemberRecord:ProxyJoin is reset (0), and the
Packit 13e616
 *   MADs source is the stored PortGID;
Packit 13e616
 *   OR
Packit 13e616
 *   the stored MCMemberRecord:ProxyJoin is set (1), (see o15-
Packit 13e616
 *   0.1.2:); and the MADs source is a member of the partition indicated
Packit 13e616
 *   by the stored MCMemberRecord:P_Key.
Packit 13e616
 */
Packit 13e616
static boolean_t validate_delete(IN osm_sa_t * sa, IN osm_mgrp_t * p_mgrp,
Packit 13e616
				 IN osm_mad_addr_t * p_mad_addr,
Packit 13e616
				 IN ib_member_rec_t * p_recvd_mcmember_rec,
Packit 13e616
				 OUT osm_mcm_alias_guid_t ** pp_mcm_alias_guid)
Packit 13e616
{
Packit 13e616
	ib_net64_t portguid;
Packit 13e616
Packit 13e616
	portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id;
Packit 13e616
Packit 13e616
	*pp_mcm_alias_guid = osm_mgrp_get_mcm_alias_guid(p_mgrp, portguid);
Packit 13e616
Packit 13e616
	/* 1 */
Packit 13e616
	if (!*pp_mcm_alias_guid) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Failed to find the port in the MC group\n");
Packit 13e616
		return FALSE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* 2 */
Packit 13e616
	if (!(p_recvd_mcmember_rec->scope_state & 0x0F &
Packit 13e616
	      (*pp_mcm_alias_guid)->scope_state)) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Could not find any matching bits in the stored "
Packit 13e616
			"and requested JoinStates\n");
Packit 13e616
		return FALSE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* 3 */
Packit 13e616
	if (((p_recvd_mcmember_rec->scope_state & 0x0F) |
Packit 13e616
	     (0x0F & (*pp_mcm_alias_guid)->scope_state)) !=
Packit 13e616
	    (0x0F & (*pp_mcm_alias_guid)->scope_state)) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Some bits in the request JoinState (0x%X) are not "
Packit 13e616
			"set in the stored port (0x%X)\n",
Packit 13e616
			(p_recvd_mcmember_rec->scope_state & 0x0F),
Packit 13e616
			(0x0F & (*pp_mcm_alias_guid)->scope_state));
Packit 13e616
		return FALSE;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* 4 */
Packit 13e616
	/* Validate according the the proxy_join (o15-0.1.2) */
Packit 13e616
	if (validate_modify(sa, p_mgrp, p_mad_addr, p_recvd_mcmember_rec,
Packit 13e616
			    pp_mcm_alias_guid) == FALSE) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"proxy_join validation failure\n");
Packit 13e616
		return FALSE;
Packit 13e616
	}
Packit 13e616
	return TRUE;
Packit 13e616
}
Packit 13e616
Packit 13e616
/*
Packit 13e616
 * Check legality of the requested MGID (note this does not hold for SA
Packit 13e616
 * created MGIDs)
Packit 13e616
 *
Packit 13e616
 * Implementing o15-0.1.5:
Packit 13e616
 * A multicast GID is considered to be invalid if:
Packit 13e616
 * 1. It does not comply with the rules as specified in 4.1.1 "GID Usage and
Packit 13e616
 *    Properties" on page 145:
Packit 13e616
 *
Packit 13e616
 * 14) The multicast GID format is (bytes are comma sep):
Packit 13e616
 *     0xff,<Fl><Sc>,<Si>,<Si>,

,

,

,

,

,

,

,

,<Id>,<Id>,<Id>,<Id>

Packit 13e616
 *     Fl  4bit = Flags (b)
Packit 13e616
 *     Sc  4bit = Scope (c)
Packit 13e616
 *     Si 16bit = Signature (2)
Packit 13e616
 *     P  64bit = GID Prefix (should be a subnet unique ID - normally Subnet Prefix)
Packit 13e616
 *     Id 32bit = Unique ID in the Subnet (might be MLID or P_Key ?)
Packit 13e616
 *
Packit 13e616
 *  a) 8-bits of 11111111 at the start of the GID identifies this as being a
Packit 13e616
 *     multicast GID.
Packit 13e616
 *  b) Flags is a set of four 1-bit flags: 000T with three flags reserved
Packit 13e616
 *     and defined as zero (0). The T flag is defined as follows:
Packit 13e616
 *     i) T = 0 indicates this is a permanently assigned (i.e. wellknown)
Packit 13e616
 *        multicast GID. See RFC 2373 and RFC 2375 as reference
Packit 13e616
 *        for these permanently assigned GIDs.
Packit 13e616
 *     ii) T = 1 indicates this is a non-permanently assigned (i.e. transient)
Packit 13e616
 *        multicast GID.
Packit 13e616
 *  c) Scope is a 4-bit multicast scope value used to limit the scope of
Packit 13e616
 *     the multicast group. The following table defines scope value and
Packit 13e616
 *     interpretation.
Packit 13e616
 *
Packit 13e616
 *     Multicast Address Scope Values:
Packit 13e616
 *     0x2 Link-local
Packit 13e616
 *     0x5 Site-local
Packit 13e616
 *     0x8 Organization-local
Packit 13e616
 *     0xE Global
Packit 13e616
 *
Packit 13e616
 * 2. It contains the SA-specific signature of 0xA01B and has the link-local
Packit 13e616
 *    scope bits set. (EZ: the idea here is that SA created MGIDs are the
Packit 13e616
 *    only source for this signature with link-local scope)
Packit 13e616
 */
Packit 13e616
static boolean_t validate_requested_mgid(IN osm_sa_t * sa,
Packit 13e616
					 IN const ib_member_rec_t * p_mcm_rec)
Packit 13e616
{
Packit 13e616
	uint16_t signature;
Packit 13e616
	boolean_t valid = TRUE;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	/* 14-a: mcast GID must start with 0xFF */
Packit 13e616
	if (p_mcm_rec->mgid.multicast.header[0] != 0xFF) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B01: "
Packit 13e616
			"Invalid prefix 0x%02X in requested MGID, "
Packit 13e616
			"must be 0xFF\n",
Packit 13e616
			cl_ntoh16(p_mcm_rec->mgid.multicast.header[0]));
Packit 13e616
		valid = FALSE;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* the MGID signature can mark IPoIB or SA assigned MGIDs */
Packit 13e616
	memcpy(&signature, &(p_mcm_rec->mgid.multicast.raw_group_id),
Packit 13e616
	       sizeof(signature));
Packit 13e616
	signature = cl_ntoh16(signature);
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "MGID Signed as 0x%04X\n", signature);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * We skip any checks for MGIDs that follow IPoIB
Packit 13e616
	 * GID structure as defined by the IETF ipoib-link-multicast.
Packit 13e616
	 *
Packit 13e616
	 * For IPv4 over IB, the signature will be "0x401B".
Packit 13e616
	 *
Packit 13e616
	 * |   8    |  4 |  4 |     16 bits     | 16 bits | 48 bits  | 32 bits |
Packit 13e616
	 * +--------+----+----+-----------------+---------+----------+---------+
Packit 13e616
	 * |11111111|0001|scop|<IPoIB signature>|< P_Key >|00.......0|<all 1's>|
Packit 13e616
	 * +--------+----+----+-----------------+---------+----------+---------+
Packit 13e616
	 *
Packit 13e616
	 * For IPv6 over IB, the signature will be "0x601B".
Packit 13e616
	 *
Packit 13e616
	 * |   8    |  4 |  4 |     16 bits     | 16 bits |       80 bits      |
Packit 13e616
	 * +--------+----+----+-----------------+---------+--------------------+
Packit 13e616
	 * |11111111|0001|scop|<IPoIB signature>|< P_Key >|000.............0001|
Packit 13e616
	 * +--------+----+----+-----------------+---------+--------------------+
Packit 13e616
	 *
Packit 13e616
	 */
Packit 13e616
	if (signature == 0x401B || signature == 0x601B) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Skipping MGID Validation for IPoIB Signed (0x%04X) MGIDs\n",
Packit 13e616
			signature);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* 14-b: the 3 upper bits in the "flags" should be zero: */
Packit 13e616
	if (p_mcm_rec->mgid.multicast.header[1] & 0xE0) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B28: "
Packit 13e616
			"Requested MGID invalid, uses Reserved Flags: flags=0x%X\n",
Packit 13e616
			(p_mcm_rec->mgid.multicast.header[1] & 0xE0) >> 4);
Packit 13e616
		valid = FALSE;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* 2 - now what if the link local format 0xA01B is used -
Packit 13e616
	   the scope should not be link local */
Packit 13e616
	if (signature == 0xA01B &&
Packit 13e616
	    (p_mcm_rec->mgid.multicast.header[1] & 0x0F) ==
Packit 13e616
	    IB_MC_SCOPE_LINK_LOCAL) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B24: "
Packit 13e616
			"Requested MGID invalid, "
Packit 13e616
			"uses 0xA01B signature but with link-local scope\n");
Packit 13e616
		valid = FALSE;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * For SA assigned MGIDs (signature 0xA01B):
Packit 13e616
	 * There is no real way to make sure the GID Prefix is really unique.
Packit 13e616
	 * If we could enforce using the Subnet Prefix for that purpose it would
Packit 13e616
	 * have been nice. But the spec does not require it.
Packit 13e616
	 */
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return valid;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Check if the requested new MC group parameters are realizable.
Packit 13e616
 Also set the default MTU and Rate if not provided by the user.
Packit 13e616
**********************************************************************/
Packit 13e616
static boolean_t mgrp_request_is_realizable(IN osm_sa_t * sa,
Packit 13e616
					    IN ib_net64_t comp_mask,
Packit 13e616
					    IN ib_member_rec_t * p_mcm_rec,
Packit 13e616
					    IN const osm_physp_t * p_physp)
Packit 13e616
{
Packit 13e616
	uint8_t mtu_sel = 2;	/* exactly */
Packit 13e616
	uint8_t mtu_required, mtu, port_mtu;
Packit 13e616
	uint8_t rate_sel = 2;	/* exactly */
Packit 13e616
	uint8_t rate_required, rate, port_rate, new_rate;
Packit 13e616
	const ib_port_info_t *p_pi;
Packit 13e616
	osm_log_t *p_log = sa->p_log;
Packit 13e616
	int extended;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * End of o15-0.2.3 specifies:
Packit 13e616
	 * ....
Packit 13e616
	 * The entity may also supply the other components such as HopLimit,
Packit 13e616
	 * MTU, etc. during group creation time. If these components are not
Packit 13e616
	 * provided during group creation time, SA will provide them for the
Packit 13e616
	 * group. The values chosen are vendor-dependent and beyond the scope
Packit 13e616
	 * of the specification.
Packit 13e616
	 *
Packit 13e616
	 * so we might also need to assign RATE/MTU if they are not comp
Packit 13e616
	 * masked in.
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	p_pi = &p_physp->port_info;
Packit 13e616
	port_mtu = p_physp ? ib_port_info_get_neighbor_mtu(p_pi) : 0;
Packit 13e616
	if (!(comp_mask & IB_MCR_COMPMASK_MTU) ||
Packit 13e616
	    !(comp_mask & IB_MCR_COMPMASK_MTU_SEL) ||
Packit 13e616
	    (mtu_sel = (p_mcm_rec->mtu >> 6)) == 3)
Packit 13e616
		mtu = port_mtu ? port_mtu : sa->p_subn->min_ca_mtu;
Packit 13e616
	else {
Packit 13e616
		mtu_required = (uint8_t) (p_mcm_rec->mtu & 0x3F);
Packit 13e616
		mtu = mtu_required;
Packit 13e616
		switch (mtu_sel) {
Packit 13e616
		case 0:	/* Greater than MTU specified */
Packit 13e616
			if (port_mtu && mtu_required >= port_mtu) {
Packit 13e616
				OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Requested MTU %x >= the port\'s mtu:%x\n",
Packit 13e616
					mtu_required, port_mtu);
Packit 13e616
				return FALSE;
Packit 13e616
			}
Packit 13e616
			/* we provide the largest MTU possible if we can */
Packit 13e616
			if (port_mtu)
Packit 13e616
				mtu = port_mtu;
Packit 13e616
			else if (mtu_required < sa->p_subn->min_ca_mtu)
Packit 13e616
				mtu = sa->p_subn->min_ca_mtu;
Packit 13e616
			else
Packit 13e616
				mtu++;
Packit 13e616
			break;
Packit 13e616
		case 1:	/* Less than MTU specified */
Packit 13e616
			/* use the smaller of the two:
Packit 13e616
			   a. one lower then the required
Packit 13e616
			   b. the mtu of the requesting port (if exists) */
Packit 13e616
			if (port_mtu && mtu_required > port_mtu)
Packit 13e616
				mtu = port_mtu;
Packit 13e616
			else
Packit 13e616
				mtu--;
Packit 13e616
			break;
Packit 13e616
		case 2:	/* Exactly MTU specified */
Packit 13e616
		default:
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
		/* make sure it still is in the range */
Packit 13e616
		if (mtu < IB_MIN_MTU || mtu > IB_MAX_MTU) {
Packit 13e616
			OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"Calculated MTU %x is out of range\n", mtu);
Packit 13e616
			return FALSE;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	p_mcm_rec->mtu = (mtu_sel << 6) | mtu;
Packit 13e616
Packit 13e616
	if (p_physp) {
Packit 13e616
		extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
Packit 13e616
		port_rate = ib_port_info_compute_rate(p_pi, extended);
Packit 13e616
	} else
Packit 13e616
		port_rate = 0;
Packit 13e616
Packit 13e616
	if (!(comp_mask & IB_MCR_COMPMASK_RATE)
Packit 13e616
	    || !(comp_mask & IB_MCR_COMPMASK_RATE_SEL)
Packit 13e616
	    || (rate_sel = (p_mcm_rec->rate >> 6)) == 3)
Packit 13e616
		rate = port_rate ? port_rate : sa->p_subn->min_ca_rate;
Packit 13e616
	else {
Packit 13e616
		rate_required = (uint8_t) (p_mcm_rec->rate & 0x3F);
Packit 13e616
		rate = rate_required;
Packit 13e616
		switch (rate_sel) {
Packit 13e616
		case 0:	/* Greater than RATE specified */
Packit 13e616
			if (ib_path_compare_rates(rate_required, port_rate) >= 0) {
Packit 13e616
				OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
					"Requested RATE %x >= the port\'s rate:%x\n",
Packit 13e616
					rate_required, port_rate);
Packit 13e616
				return FALSE;
Packit 13e616
			}
Packit 13e616
			/* we provide the largest RATE possible if we can */
Packit 13e616
			if (port_rate)
Packit 13e616
				rate = port_rate;
Packit 13e616
			else if (ib_path_compare_rates(rate_required,
Packit 13e616
						       sa->p_subn->min_ca_rate) < 0)
Packit 13e616
				rate = sa->p_subn->min_ca_rate;
Packit 13e616
			else
Packit 13e616
				rate = ib_path_rate_get_next(rate);
Packit 13e616
			break;
Packit 13e616
		case 1:	/* Less than RATE specified */
Packit 13e616
			/* use the smaller of the two:
Packit 13e616
			   a. one lower then the required
Packit 13e616
			   b. the rate of the requesting port (if exists) */
Packit 13e616
			if (ib_path_compare_rates(rate_required, port_rate) > 0)
Packit 13e616
				rate = port_rate;
Packit 13e616
			else
Packit 13e616
				rate = ib_path_rate_get_prev(rate);
Packit 13e616
			break;
Packit 13e616
		case 2:	/* Exactly RATE specified */
Packit 13e616
		default:
Packit 13e616
			break;
Packit 13e616
		}
Packit 13e616
		/* make sure it still is in the range */
Packit 13e616
		if (rate < IB_MIN_RATE || rate > IB_MAX_RATE) {
Packit 13e616
			OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"Calculated RATE %x is out of range\n", rate);
Packit 13e616
			return FALSE;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	if (sa->p_subn->opt.use_original_extended_sa_rates_only) {
Packit 13e616
		new_rate = ib_path_rate_max_12xedr(rate);
Packit 13e616
		if (new_rate != rate) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
				"Rate decreased from %u to %u\n",
Packit 13e616
				rate, new_rate);
Packit 13e616
			rate = new_rate;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
	p_mcm_rec->rate = (rate_sel << 6) | rate;
Packit 13e616
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return TRUE;
Packit 13e616
}
Packit 13e616
Packit 13e616
static unsigned build_new_mgid(osm_sa_t * sa, ib_net64_t comp_mask,
Packit 13e616
			       ib_member_rec_t * mcmr)
Packit 13e616
{
Packit 13e616
	static uint32_t uniq_count;
Packit 13e616
	ib_gid_t *mgid = &mcmr->mgid;
Packit 13e616
	uint8_t scope;
Packit 13e616
	unsigned i;
Packit 13e616
Packit 13e616
	/* use the given scope state only if requested! */
Packit 13e616
	if (comp_mask & IB_MCR_COMPMASK_SCOPE)
Packit 13e616
		ib_member_get_scope_state(mcmr->scope_state, &scope, NULL);
Packit 13e616
	else
Packit 13e616
	/* to guarantee no collision with other subnets use local scope! */
Packit 13e616
		scope = IB_MC_SCOPE_LINK_LOCAL;
Packit 13e616
Packit 13e616
	mgid->raw[0] = 0xff;
Packit 13e616
	mgid->raw[1] = 0x10 | scope;
Packit 13e616
	mgid->raw[2] = 0xa0;
Packit 13e616
	mgid->raw[3] = 0x1b;
Packit 13e616
Packit 13e616
	memcpy(&mgid->raw[4], &sa->p_subn->opt.subnet_prefix, sizeof(uint64_t));
Packit 13e616
Packit 13e616
	for (i = 0; i < 1000; i++) {
Packit 13e616
		memcpy(&mgid->raw[10], &uniq_count, 4);
Packit 13e616
		uniq_count++;
Packit 13e616
		if (!osm_get_mgrp_by_mgid(sa->p_subn, mgid))
Packit 13e616
			return 1;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	return 0;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Call this function to create a new mgrp.
Packit 13e616
**********************************************************************/
Packit 13e616
static ib_api_status_t mcmr_rcv_create_new_mgrp(IN osm_sa_t * sa,
Packit 13e616
						IN ib_net64_t comp_mask,
Packit 13e616
						IN const ib_member_rec_t * p_recvd_mcmember_rec,
Packit 13e616
						IN const osm_physp_t * p_physp,
Packit 13e616
						OUT osm_mgrp_t ** pp_mgrp)
Packit 13e616
{
Packit 13e616
	ib_net16_t mlid;
Packit 13e616
	uint16_t signature;
Packit 13e616
	ib_api_status_t status = IB_SUCCESS;
Packit 13e616
	osm_mgrp_t *bcast_mgrp;
Packit 13e616
	ib_gid_t bcast_mgid;
Packit 13e616
	ib_member_rec_t mcm_rec = *p_recvd_mcmember_rec;	/* copy for modifications */
Packit 13e616
	char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	/* we need to create the new MGID if it was not defined */
Packit 13e616
	if (!ib_gid_is_notzero(&p_recvd_mcmember_rec->mgid)) {
Packit 13e616
		/* create a new MGID */
Packit 13e616
		if (!build_new_mgid(sa, comp_mask, &mcm_rec)) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B23: "
Packit 13e616
				"cannot allocate unique MGID value\n");
Packit 13e616
			status = IB_SA_MAD_STATUS_NO_RESOURCES;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Allocated new MGID:%s\n",
Packit 13e616
			inet_ntop(AF_INET6, mcm_rec.mgid.raw, gid_str,
Packit 13e616
				  sizeof gid_str));
Packit 13e616
	} else if (sa->p_subn->opt.ipoib_mcgroup_creation_validation) {
Packit 13e616
		/* a specific MGID was requested so validate the resulting MGID */
Packit 13e616
		if (validate_requested_mgid(sa, &mcm_rec)) {
Packit 13e616
			memcpy(&signature, &(mcm_rec.mgid.multicast.raw_group_id),
Packit 13e616
			       sizeof(signature));
Packit 13e616
			signature = cl_ntoh16(signature);
Packit 13e616
			/* Check for IPoIB signature in MGID */
Packit 13e616
			if (signature == 0x401B || signature == 0x601B) {
Packit 13e616
				/* Derive IPoIB broadcast MGID */
Packit 13e616
				bcast_mgid.unicast.prefix = IPV4_BCAST_MGID_PREFIX;
Packit 13e616
				bcast_mgid.unicast.interface_id = IPV4_BCAST_MGID_INT_ID;
Packit 13e616
				/* Set scope in IPoIB broadcast MGID */
Packit 13e616
				bcast_mgid.multicast.header[1] =
Packit 13e616
					(bcast_mgid.multicast.header[1] & 0xF0) |
Packit 13e616
					(mcm_rec.mgid.multicast.header[1] & 0x0F);
Packit 13e616
				/* Set P_Key in IPoIB broadcast MGID */
Packit 13e616
				bcast_mgid.multicast.raw_group_id[2] =
Packit 13e616
					mcm_rec.mgid.multicast.raw_group_id[2];
Packit 13e616
				bcast_mgid.multicast.raw_group_id[3] =
Packit 13e616
					mcm_rec.mgid.multicast.raw_group_id[3];
Packit 13e616
				/* Check MC group for the IPoIB broadcast group */
Packit 13e616
				if (signature != 0x401B ||
Packit 13e616
				    memcmp(&bcast_mgid, &(mcm_rec.mgid), sizeof(ib_gid_t))) {
Packit 13e616
					bcast_mgrp = osm_get_mgrp_by_mgid(sa->p_subn,
Packit 13e616
									  &bcast_mgid);
Packit 13e616
					if (!bcast_mgrp) {
Packit 13e616
						OSM_LOG(sa->p_log, OSM_LOG_ERROR,
Packit 13e616
							"ERR 1B1B: Broadcast group %s not found, sending IB_SA_MAD_STATUS_REQ_INVALID\n",
Packit 13e616
							inet_ntop(AF_INET6, bcast_mgid.raw, gid_str, sizeof gid_str));
Packit 13e616
						status = IB_SA_MAD_STATUS_REQ_INVALID;
Packit 13e616
						goto Exit;
Packit 13e616
					}
Packit 13e616
					if (!validate_other_comp_fields(sa->p_log, comp_mask, p_recvd_mcmember_rec, bcast_mgrp, OSM_LOG_ERROR)) {
Packit 13e616
						OSM_LOG(sa->p_log, OSM_LOG_ERROR,
Packit 13e616
							"ERR 1B1C: validate_other_comp_fields failed for MGID: %s, sending IB_SA_MAD_STATUS_REQ_INVALID\n",
Packit 13e616
							inet_ntop(AF_INET6, &p_recvd_mcmember_rec->mgid, gid_str, sizeof gid_str));
Packit 13e616
						status = IB_SA_MAD_STATUS_REQ_INVALID;
Packit 13e616
						goto Exit;
Packit 13e616
					}
Packit 13e616
				}
Packit 13e616
			}
Packit 13e616
		} else {
Packit 13e616
			status = IB_SA_MAD_STATUS_REQ_INVALID;
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* check the requested parameters are realizable */
Packit 13e616
	if (mgrp_request_is_realizable(sa, comp_mask, &mcm_rec, p_physp) ==
Packit 13e616
	    FALSE) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B26: "
Packit 13e616
			"Requested MGRP parameters are not realizable\n");
Packit 13e616
		status = IB_SA_MAD_STATUS_REQ_INVALID;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	mlid = get_new_mlid(sa, &mcm_rec);
Packit 13e616
	if (mlid == 0) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B19: "
Packit 13e616
			"get_new_mlid failed request mlid 0x%04x\n",
Packit 13e616
			cl_ntoh16(mcm_rec.mlid));
Packit 13e616
		status = IB_SA_MAD_STATUS_NO_RESOURCES;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Obtained new mlid 0x%X\n",
Packit 13e616
		cl_ntoh16(mlid));
Packit 13e616
Packit 13e616
	mcm_rec.mlid = mlid;
Packit 13e616
	/* create a new MC Group */
Packit 13e616
	*pp_mgrp = osm_mgrp_new(sa->p_subn, mlid, &mcm_rec);
Packit 13e616
	if (*pp_mgrp == NULL) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B08: "
Packit 13e616
			"osm_mgrp_new failed\n");
Packit 13e616
		free_mlid(sa, mlid);
Packit 13e616
		status = IB_SA_MAD_STATUS_NO_RESOURCES;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* the mcmember_record should have mtu_sel, rate_sel, and pkt_lifetime_sel = 2 */
Packit 13e616
	(*pp_mgrp)->mcmember_rec.mtu &= 0x3f;
Packit 13e616
	(*pp_mgrp)->mcmember_rec.mtu |= IB_PATH_SELECTOR_EXACTLY << 6;
Packit 13e616
	(*pp_mgrp)->mcmember_rec.rate &= 0x3f;
Packit 13e616
	(*pp_mgrp)->mcmember_rec.rate |= IB_PATH_SELECTOR_EXACTLY << 6;
Packit 13e616
	(*pp_mgrp)->mcmember_rec.pkt_life &= 0x3f;
Packit 13e616
	(*pp_mgrp)->mcmember_rec.pkt_life |= IB_PATH_SELECTOR_EXACTLY << 6;
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Call this function to find or create a new mgrp.
Packit 13e616
**********************************************************************/
Packit 13e616
osm_mgrp_t *osm_mcmr_rcv_find_or_create_new_mgrp(IN osm_sa_t * sa,
Packit 13e616
						 IN ib_net64_t comp_mask,
Packit 13e616
						 IN ib_member_rec_t *
Packit 13e616
						 p_recvd_mcmember_rec)
Packit 13e616
{
Packit 13e616
	osm_mgrp_t *mgrp;
Packit 13e616
Packit 13e616
	if ((mgrp = osm_get_mgrp_by_mgid(sa->p_subn,
Packit 13e616
					 &p_recvd_mcmember_rec->mgid)))
Packit 13e616
		return mgrp;
Packit 13e616
	if (mcmr_rcv_create_new_mgrp(sa, comp_mask, p_recvd_mcmember_rec, NULL,
Packit 13e616
				     &mgrp) == IB_SUCCESS)
Packit 13e616
		return mgrp;
Packit 13e616
	return NULL;
Packit 13e616
}
Packit 13e616
Packit 13e616
/*********************************************************************
Packit 13e616
Process a request for leaving the group
Packit 13e616
**********************************************************************/
Packit 13e616
static void mcmr_rcv_leave_mgrp(IN osm_sa_t * sa, IN osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	osm_mgrp_t *p_mgrp;
Packit 13e616
	ib_sa_mad_t *p_sa_mad;
Packit 13e616
	ib_member_rec_t *p_recvd_mcmember_rec;
Packit 13e616
	ib_member_rec_t mcmember_rec;
Packit 13e616
	osm_mcm_alias_guid_t *p_mcm_alias_guid;
Packit Service cd4207
	ib_net64_t prefix;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
Packit 13e616
	p_recvd_mcmember_rec =
Packit 13e616
	    (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
Packit 13e616
Packit Service cd4207
	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
Packit Service cd4207
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Dump of record\n");
Packit Service cd4207
		osm_dump_mc_record_v2(sa->p_log, p_recvd_mcmember_rec, FILE_ID, OSM_LOG_DEBUG);
Packit Service cd4207
	}
Packit Service cd4207
Packit Service cd4207
	/* Use ports actual subnet prefix */
Packit Service cd4207
	prefix = p_recvd_mcmember_rec->port_gid.unicast.prefix;
Packit Service cd4207
	if (prefix == IB_DEFAULT_SUBNET_PREFIX)
Packit Service cd4207
		p_recvd_mcmember_rec->port_gid.unicast.prefix = sa->p_subn->opt.subnet_prefix;
Packit Service cd4207
Packit 13e616
	mcmember_rec = *p_recvd_mcmember_rec;
Packit 13e616
Packit 13e616
	/* Validate the subnet prefix in the PortGID */
Packit 13e616
	if (p_recvd_mcmember_rec->port_gid.unicast.prefix !=
Packit 13e616
	    sa->p_subn->opt.subnet_prefix) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR,
Packit 13e616
			"ERR 1B41: PortGID subnet prefix 0x%" PRIx64
Packit 13e616
			" does not match configured prefix 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(p_recvd_mcmember_rec->port_gid.unicast.prefix),
Packit 13e616
			cl_ntoh64(sa->p_subn->opt.subnet_prefix));
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INVALID_GID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	CL_PLOCK_EXCL_ACQUIRE(sa->p_lock);
Packit 13e616
Packit 13e616
	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
Packit 13e616
		osm_physp_t *p_req_physp;
Packit 13e616
Packit 13e616
		p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
Packit 13e616
							osm_madw_get_mad_addr_ptr(p_madw));
Packit 13e616
		if (p_req_physp == NULL) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B02: "
Packit 13e616
				"Cannot find requester physical port\n");
Packit 13e616
		} else {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Requester port GUID 0x%" PRIx64 "\n",
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_mgrp = osm_get_mgrp_by_mgid(sa->p_subn, &p_recvd_mcmember_rec->mgid);
Packit 13e616
	if (!p_mgrp) {
Packit 13e616
		char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
		CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Failed since multicast group %s not present\n",
Packit 13e616
			inet_ntop(AF_INET6, p_recvd_mcmember_rec->mgid.raw,
Packit 13e616
				  gid_str, sizeof gid_str));
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* check validity of the delete request o15-0.1.14 */
Packit 13e616
	if (!validate_delete(sa, p_mgrp, osm_madw_get_mad_addr_ptr(p_madw),
Packit 13e616
			     p_recvd_mcmember_rec, &p_mcm_alias_guid)) {
Packit 13e616
		char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
		char gid_str2[INET6_ADDRSTRLEN];
Packit 13e616
		CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B25: "
Packit 13e616
			"Received an invalid delete request for "
Packit 13e616
			"MGID: %s for PortGID: %s\n",
Packit 13e616
			inet_ntop(AF_INET6, p_recvd_mcmember_rec->mgid.raw,
Packit 13e616
				  gid_str, sizeof gid_str),
Packit 13e616
			inet_ntop(AF_INET6, p_recvd_mcmember_rec->port_gid.raw,
Packit 13e616
				  gid_str2, sizeof gid_str2));
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* remove port and/or update join state */
Packit 13e616
	osm_mgrp_remove_port(sa->p_subn, sa->p_log, p_mgrp, p_mcm_alias_guid,
Packit 13e616
			     &mcmember_rec);
Packit 13e616
	CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
Packit Service cd4207
	/* Return response with same subnet prefix of the request */
Packit Service cd4207
	mcmember_rec.port_gid.unicast.prefix = prefix;
Packit 13e616
	mcmr_rcv_respond(sa, p_madw, &mcmember_rec);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static int validate_other_comp_fields(osm_log_t * p_log, ib_net64_t comp_mask,
Packit 13e616
				      const ib_member_rec_t * p_mcmr,
Packit 13e616
				      osm_mgrp_t * p_mgrp,
Packit 13e616
				      osm_log_level_t log_level)
Packit 13e616
{
Packit 13e616
	int ret = 0;
Packit 13e616
Packit 13e616
	if ((IB_MCR_COMPMASK_QKEY & comp_mask) &&
Packit 13e616
	    p_mcmr->qkey != p_mgrp->mcmember_rec.qkey) {
Packit 13e616
		OSM_LOG(p_log, log_level, "ERR 1B30: "
Packit 13e616
			"Q_Key mismatch: query 0x%x group 0x%x\n",
Packit 13e616
			cl_ntoh32(p_mcmr->qkey),
Packit 13e616
			cl_ntoh32(p_mgrp->mcmember_rec.qkey));
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (IB_MCR_COMPMASK_PKEY & comp_mask) {
Packit 13e616
		if (!(ib_pkey_is_full_member(p_mcmr->pkey) ||
Packit 13e616
		      ib_pkey_is_full_member(p_mgrp->mcmember_rec.pkey))) {
Packit 13e616
			OSM_LOG(p_log, log_level, "ERR 1B31: "
Packit 13e616
				"Both limited P_Keys: query 0x%x group 0x%x\n",
Packit 13e616
				cl_ntoh16(p_mcmr->pkey),
Packit 13e616
				cl_ntoh16(p_mgrp->mcmember_rec.pkey));
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
		if (ib_pkey_get_base(p_mcmr->pkey) !=
Packit 13e616
		    ib_pkey_get_base(p_mgrp->mcmember_rec.pkey)) {
Packit 13e616
			OSM_LOG(p_log, log_level, "ERR 1B32: "
Packit 13e616
				"P_Key base mismatch: query 0x%x group 0x%x\n",
Packit 13e616
				cl_ntoh16(p_mcmr->pkey),
Packit 13e616
				cl_ntoh16(p_mgrp->mcmember_rec.pkey));
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if ((IB_MCR_COMPMASK_TCLASS & comp_mask) &&
Packit 13e616
	    p_mcmr->tclass != p_mgrp->mcmember_rec.tclass) {
Packit 13e616
		OSM_LOG(p_log, log_level, "ERR 1B33: "
Packit 13e616
			"TClass mismatch: query %d group %d\n",
Packit 13e616
			p_mcmr->tclass, p_mgrp->mcmember_rec.tclass);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* check SL, Flow, and Hop limit */
Packit 13e616
	{
Packit 13e616
		uint32_t mgrp_flow, query_flow;
Packit 13e616
		uint8_t mgrp_sl, query_sl;
Packit 13e616
		uint8_t mgrp_hop, query_hop;
Packit 13e616
Packit 13e616
		ib_member_get_sl_flow_hop(p_mcmr->sl_flow_hop,
Packit 13e616
					  &query_sl, &query_flow, &query_hop);
Packit 13e616
Packit 13e616
		ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
Packit 13e616
					  &mgrp_sl, &mgrp_flow, &mgrp_hop);
Packit 13e616
Packit 13e616
		if ((IB_MCR_COMPMASK_SL & comp_mask) && query_sl != mgrp_sl) {
Packit 13e616
			OSM_LOG(p_log, log_level, "ERR 1B34: "
Packit 13e616
				"SL mismatch: query %d group %d\n",
Packit 13e616
				query_sl, mgrp_sl);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if ((IB_MCR_COMPMASK_FLOW & comp_mask) &&
Packit 13e616
		    query_flow != mgrp_flow) {
Packit 13e616
			OSM_LOG(p_log, log_level, "ERR 1B35: "
Packit 13e616
				"FlowLabel mismatch: query 0x%x group 0x%x\n",
Packit 13e616
				query_flow, mgrp_flow);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		if ((IB_MCR_COMPMASK_HOP & comp_mask) && query_hop != mgrp_hop) {
Packit 13e616
			OSM_LOG(p_log, log_level, "ERR 1B36: "
Packit 13e616
				"Hop mismatch: query %d group %d\n",
Packit 13e616
				query_hop, mgrp_hop);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	ret = 1;
Packit 13e616
Exit:
Packit 13e616
	return ret;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Handle a join (or create) request
Packit 13e616
**********************************************************************/
Packit 13e616
static void mcmr_rcv_join_mgrp(IN osm_sa_t * sa, IN osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	osm_mgrp_t *p_mgrp = NULL;
Packit 13e616
	ib_api_status_t status;
Packit 13e616
	ib_sa_mad_t *p_sa_mad;
Packit 13e616
	ib_member_rec_t *p_recvd_mcmember_rec;
Packit 13e616
	ib_member_rec_t mcmember_rec;
Packit 13e616
	osm_mcm_port_t *p_mcmr_port;
Packit 13e616
	osm_mcm_alias_guid_t *p_mcm_alias_guid;
Packit 13e616
	ib_net64_t portguid;
Packit 13e616
	osm_port_t *p_port;
Packit 13e616
	osm_physp_t *p_physp;
Packit 13e616
	osm_physp_t *p_request_physp;
Packit 13e616
	uint8_t is_new_group;	/* TRUE = there is a need to create a group */
Packit 13e616
	uint8_t join_state;
Packit 13e616
	boolean_t proxy;
Packit Service cd4207
	ib_net64_t prefix;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
Packit 13e616
	p_recvd_mcmember_rec = ib_sa_mad_get_payload_ptr(p_sa_mad);
Packit 13e616
Packit Service cd4207
	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
Packit Service cd4207
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Dump of incoming record\n");
Packit Service cd4207
		osm_dump_mc_record_v2(sa->p_log, p_recvd_mcmember_rec, FILE_ID, OSM_LOG_DEBUG);
Packit Service cd4207
	}
Packit Service cd4207
Packit 13e616
	portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id;
Packit 13e616
Packit Service cd4207
	/* Use ports actual subnet prefix */
Packit Service cd4207
	prefix = p_recvd_mcmember_rec->port_gid.unicast.prefix;
Packit Service cd4207
	if (prefix == IB_DEFAULT_SUBNET_PREFIX)
Packit Service cd4207
		p_recvd_mcmember_rec->port_gid.unicast.prefix = sa->p_subn->opt.subnet_prefix;
Packit Service cd4207
Packit 13e616
	mcmember_rec = *p_recvd_mcmember_rec;
Packit 13e616
Packit 13e616
	/* Validate the subnet prefix in the PortGID */
Packit 13e616
	if (p_recvd_mcmember_rec->port_gid.unicast.prefix !=
Packit 13e616
	    sa->p_subn->opt.subnet_prefix) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR,
Packit 13e616
			"ERR 1B40: PortGID subnet prefix 0x%" PRIx64
Packit 13e616
			" does not match configured prefix 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(p_recvd_mcmember_rec->port_gid.unicast.prefix),
Packit 13e616
			cl_ntoh64(sa->p_subn->opt.subnet_prefix));
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INVALID_GID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	CL_PLOCK_EXCL_ACQUIRE(sa->p_lock);
Packit 13e616
Packit 13e616
	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
Packit 13e616
		osm_physp_t *p_req_physp;
Packit 13e616
Packit 13e616
		p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
Packit 13e616
							osm_madw_get_mad_addr_ptr(p_madw));
Packit 13e616
		if (p_req_physp == NULL) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B03: "
Packit 13e616
				"Cannot find requester physical port\n");
Packit 13e616
		} else {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
				"Requester port GUID 0x%" PRIx64 "\n",
Packit 13e616
				cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* make sure the requested port guid is known to the SM */
Packit 13e616
	p_port = osm_get_port_by_alias_guid(sa->p_subn, portguid);
Packit 13e616
	if (!p_port) {
Packit 13e616
		CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Unknown port GUID 0x%016" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(portguid));
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	p_physp = p_port->p_physp;
Packit 13e616
	/* Check that the p_physp and the requester physp are in the same
Packit 13e616
	   partition. */
Packit 13e616
	p_request_physp =
Packit 13e616
	    osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
Packit 13e616
				      osm_madw_get_mad_addr_ptr(p_madw));
Packit 13e616
	if (p_request_physp == NULL) {
Packit 13e616
		CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	proxy = (p_physp != p_request_physp);
Packit 13e616
Packit 13e616
	if (proxy && !osm_physp_share_pkey(sa->p_log, p_physp, p_request_physp,
Packit 13e616
					   sa->p_subn->opt.allow_both_pkeys)) {
Packit 13e616
		CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Port and requester don't share PKey\n");
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if ((p_sa_mad->comp_mask & IB_MCR_COMPMASK_PKEY) &&
Packit 13e616
	    ib_pkey_is_invalid(p_recvd_mcmember_rec->pkey)) {
Packit 13e616
		CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
Packit 13e616
			"Invalid PKey supplied in request\n");
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	ib_member_get_scope_state(p_recvd_mcmember_rec->scope_state, NULL,
Packit 13e616
				  &join_state);
Packit 13e616
Packit 13e616
	/* do we need to create a new group? */
Packit 13e616
	p_mgrp = osm_get_mgrp_by_mgid(sa->p_subn, &p_recvd_mcmember_rec->mgid);
Packit 13e616
	if (!p_mgrp) {
Packit 13e616
		/* check for JoinState.FullMember = 1 o15.0.1.9 */
Packit 13e616
		if (!(join_state & (IB_JOIN_STATE_FULL | IB_JOIN_STATE_SEND_ONLY_FULL))) {
Packit 13e616
			char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
			CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B10: "
Packit 13e616
				"Failed to create multicast group "
Packit 13e616
				"because Join State != FullMember | SendOnlyFullMember"
Packit 13e616
				" - required for create, "
Packit 13e616
				"MGID: %s from port 0x%016" PRIx64 " (%s)\n",
Packit 13e616
				inet_ntop(AF_INET6,
Packit 13e616
					  p_recvd_mcmember_rec->mgid.raw,
Packit 13e616
					  gid_str, sizeof gid_str),
Packit 13e616
				cl_ntoh64(portguid),
Packit 13e616
				p_port->p_node->print_desc);
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/* check the comp_mask */
Packit 13e616
		if (!check_create_comp_mask(p_sa_mad->comp_mask,
Packit 13e616
					    p_recvd_mcmember_rec)) {
Packit 13e616
			char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
			CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B11: "
Packit 13e616
				"Port 0x%016" PRIx64 " (%s) failed to join "
Packit 13e616
				"non-existing multicast group with MGID %s, "
Packit 13e616
				"insufficient components specified for "
Packit 13e616
				"implicit create (comp_mask 0x%" PRIx64 ")\n",
Packit 13e616
				cl_ntoh64(portguid), p_port->p_node->print_desc,
Packit 13e616
				inet_ntop(AF_INET6,
Packit 13e616
					  p_recvd_mcmember_rec->mgid.raw,
Packit 13e616
					  gid_str, sizeof gid_str),
Packit 13e616
				cl_ntoh64(p_sa_mad->comp_mask));
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_INSUF_COMPS);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		status = mcmr_rcv_create_new_mgrp(sa, p_sa_mad->comp_mask,
Packit 13e616
						  p_recvd_mcmember_rec,
Packit 13e616
						  p_physp, &p_mgrp);
Packit 13e616
		if (status != IB_SUCCESS) {
Packit 13e616
			CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
			osm_sa_send_error(sa, p_madw, status);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
		/* copy the MGID to the result */
Packit 13e616
		mcmember_rec.mgid = p_mgrp->mcmember_rec.mgid;
Packit 13e616
		is_new_group = 1;
Packit 13e616
	} else {
Packit 13e616
		/* no need for a new group */
Packit 13e616
		is_new_group = 0;
Packit 13e616
		if (sa->p_subn->opt.mcgroup_join_validation &&
Packit 13e616
		    !validate_other_comp_fields(sa->p_log, p_sa_mad->comp_mask,
Packit 13e616
						p_recvd_mcmember_rec, p_mgrp,
Packit 13e616
						OSM_LOG_ERROR)) {
Packit 13e616
			char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
			CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B1A: "
Packit 13e616
				"validate_other_comp_fields failed for "
Packit 13e616
				"MGID: %s port 0x%016" PRIx64
Packit 13e616
				" (%s), sending IB_SA_MAD_STATUS_REQ_INVALID\n",
Packit 13e616
				inet_ntop(AF_INET6,
Packit 13e616
					  p_mgrp->mcmember_rec.mgid.raw,
Packit 13e616
					  gid_str, sizeof gid_str),
Packit 13e616
				cl_ntoh64(portguid),
Packit 13e616
				p_port->p_node->print_desc);
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	CL_ASSERT(p_mgrp);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * o15-0.2.4: If SA supports UD multicast, then SA shall cause an
Packit 13e616
	 * endport to join an existing multicast group if:
Packit 13e616
	 * 1. It receives a SubnAdmSet() method for a MCMemberRecord, and
Packit 13e616
	 *    - WE KNOW THAT ALREADY
Packit 13e616
	 * 2. The MGID is specified and matches an existing multicast
Packit 13e616
	 *    group, and
Packit 13e616
	 *    - WE KNOW THAT ALREADY
Packit 13e616
	 * 3. The MCMemberRecord:JoinState is not all 0s, and
Packit 13e616
	 * 4. PortGID is specified and
Packit 13e616
	 *    - WE KNOW THAT ALREADY (as it matched a real one)
Packit 13e616
	 * 5. All other components match that existing group, either by
Packit 13e616
	 *    being wildcarded or by having values identical to those specified
Packit 13e616
	 *    by the component mask and in use by the group with the exception
Packit 13e616
	 *    of components such as ProxyJoin and Reserved, which are ignored
Packit 13e616
	 *    by SA.
Packit 13e616
	 *
Packit 13e616
	 * We need to check #3 and #5 here:
Packit 13e616
	 */
Packit 13e616
	if (!validate_more_comp_fields(sa->p_log, p_mgrp, p_recvd_mcmember_rec,
Packit 13e616
				       p_sa_mad->comp_mask)
Packit 13e616
	    || !validate_port_caps(sa->p_log, p_mgrp, p_physp)
Packit 13e616
	    || !(join_state != 0)) {
Packit 13e616
		char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
		memset(gid_str, 0, sizeof(gid_str));
Packit 13e616
Packit 13e616
		/* get the gid_str before the cleanup, the cleanup can free the pointer */
Packit 13e616
		inet_ntop(AF_INET6, p_mgrp->mcmember_rec.mgid.raw, gid_str,
Packit 13e616
			  sizeof gid_str);
Packit 13e616
Packit 13e616
		/* since we might have created the new group we need to cleanup */
Packit 13e616
		if (is_new_group)
Packit 13e616
			osm_mgrp_cleanup(sa->p_subn, p_mgrp);
Packit 13e616
		CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B12: "
Packit 13e616
			"validate_more_comp_fields, validate_port_caps, "
Packit 13e616
			"or JoinState = 0 failed for MGID: %s port 0x%016" PRIx64
Packit 13e616
			" (%s), sending IB_SA_MAD_STATUS_REQ_INVALID\n",
Packit 13e616
			gid_str, cl_ntoh64(portguid), p_port->p_node->print_desc);
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* verify that the joining port is in the partition of the group */
Packit 13e616
	if (!osm_physp_has_pkey(sa->p_log, p_mgrp->mcmember_rec.pkey, p_physp)) {
Packit 13e616
		char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
		memset(gid_str, 0, sizeof(gid_str));
Packit 13e616
		inet_ntop(AF_INET6, p_mgrp->mcmember_rec.mgid.raw, gid_str,
Packit 13e616
			  sizeof(gid_str));
Packit 13e616
Packit 13e616
		if (is_new_group)
Packit 13e616
			osm_mgrp_cleanup(sa->p_subn, p_mgrp);
Packit 13e616
		CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B14: "
Packit 13e616
			"Cannot join port 0x%016" PRIx64 " to MGID %s - "
Packit 13e616
			"Port is not in partition of this MC group\n",
Packit 13e616
			cl_ntoh64(portguid), gid_str);
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	 * o15-0.2.1 requires validation of the requesting port
Packit 13e616
	 * in the case of modification:
Packit 13e616
	 */
Packit 13e616
	if (!is_new_group &&
Packit 13e616
	    !validate_modify(sa, p_mgrp, osm_madw_get_mad_addr_ptr(p_madw),
Packit 13e616
			     p_recvd_mcmember_rec, &p_mcm_alias_guid)) {
Packit 13e616
		char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
		CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B13: "
Packit 13e616
			"validate_modify failed from port 0x%016" PRIx64
Packit 13e616
			" (%s) for MGID: %s, sending IB_SA_MAD_STATUS_REQ_INVALID\n",
Packit 13e616
			cl_ntoh64(portguid), p_port->p_node->print_desc,
Packit 13e616
			inet_ntop(AF_INET6,
Packit 13e616
				  p_mgrp->mcmember_rec.mgid.raw,
Packit 13e616
				  gid_str, sizeof(gid_str)));
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* copy qkey mlid tclass pkey sl_flow_hop mtu rate pkt_life */
Packit 13e616
	copy_from_create_mc_rec(&mcmember_rec, &p_mgrp->mcmember_rec);
Packit 13e616
Packit 13e616
	/* create or update existing port (join-state will be updated) */
Packit 13e616
	p_mcmr_port = osm_mgrp_add_port(sa->p_subn, sa->p_log, p_mgrp, p_port,
Packit 13e616
					&mcmember_rec, proxy);
Packit 13e616
	if (!p_mcmr_port) {
Packit 13e616
		/* we fail to add the port so we might need to delete the group */
Packit 13e616
		if (is_new_group)
Packit 13e616
			osm_mgrp_cleanup(sa->p_subn, p_mgrp);
Packit 13e616
		CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B06: "
Packit 13e616
			"osm_mgrp_add_port failed\n");
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES);
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	/* Release the lock as we don't need it. */
Packit 13e616
	CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
Packit Service cd4207
	/* Return response with same subnet prefix of the request */
Packit Service cd4207
	mcmember_rec.port_gid.unicast.prefix = prefix;
Packit Service cd4207
Packit 13e616
	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG))
Packit 13e616
		osm_dump_mc_record_v2(sa->p_log, &mcmember_rec, FILE_ID, OSM_LOG_DEBUG);
Packit 13e616
Packit 13e616
	mcmr_rcv_respond(sa, p_madw, &mcmember_rec);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Add a patched multicast group to the results list
Packit 13e616
**********************************************************************/
Packit 13e616
static ib_api_status_t mcmr_rcv_new_mcmr(IN osm_sa_t * sa,
Packit 13e616
					 IN const ib_member_rec_t * p_rcvd_rec,
Packit 13e616
					 IN cl_qlist_t * p_list)
Packit 13e616
{
Packit 13e616
	osm_sa_item_t *p_rec_item;
Packit 13e616
	ib_api_status_t status = IB_SUCCESS;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	p_rec_item = malloc(SA_MCM_RESP_SIZE);
Packit 13e616
	if (p_rec_item == NULL) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B15: "
Packit 13e616
			"rec_item alloc failed\n");
Packit 13e616
		status = IB_INSUFFICIENT_RESOURCES;
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	memset(p_rec_item, 0, sizeof(cl_list_item_t));
Packit 13e616
Packit 13e616
	/* HACK: Untrusted requesters should result with 0 Join
Packit 13e616
	   State, Port Guid, and Proxy */
Packit 13e616
	p_rec_item->resp.mc_rec = *p_rcvd_rec;
Packit 13e616
	cl_qlist_insert_tail(p_list, &p_rec_item->list_item);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return status;
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Match the given mgrp to the requested mcmr
Packit 13e616
**********************************************************************/
Packit 13e616
static void mcmr_by_comp_mask(osm_sa_t * sa, const ib_member_rec_t * p_rcvd_rec,
Packit 13e616
			      ib_net64_t comp_mask, osm_mgrp_t * p_mgrp,
Packit 13e616
			      const osm_physp_t * p_req_physp,
Packit 13e616
			      boolean_t trusted_req, cl_qlist_t * list)
Packit 13e616
{
Packit 13e616
	/* since we might change scope_state */
Packit 13e616
	ib_member_rec_t match_rec;
Packit 13e616
	osm_mcm_alias_guid_t *p_mcm_alias_guid;
Packit 13e616
	ib_net64_t portguid = p_rcvd_rec->port_gid.unicast.interface_id;
Packit 13e616
	/* will be used for group or port info */
Packit 13e616
	uint8_t scope_state;
Packit 13e616
	uint8_t scope_state_mask = 0;
Packit 13e616
	cl_map_item_t *p_item;
Packit 13e616
	ib_gid_t port_gid;
Packit 13e616
	boolean_t proxy_join = FALSE;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
		"Checking mlid:0x%X\n", cl_ntoh16(p_mgrp->mlid));
Packit 13e616
Packit 13e616
	memset(&port_gid, 0, sizeof(port_gid));
Packit 13e616
Packit 13e616
	/* first try to eliminate the group by MGID, MLID, or P_Key */
Packit 13e616
	if ((IB_MCR_COMPMASK_MGID & comp_mask) &&
Packit 13e616
	    memcmp(&p_rcvd_rec->mgid, &p_mgrp->mcmember_rec.mgid,
Packit 13e616
		   sizeof(ib_gid_t)))
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	if ((IB_MCR_COMPMASK_MLID & comp_mask) &&
Packit 13e616
	    memcmp(&p_rcvd_rec->mlid, &p_mgrp->mcmember_rec.mlid,
Packit 13e616
		   sizeof(uint16_t)))
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/* if the requester physical port doesn't have the pkey that is defined
Packit 13e616
	   for the group - exit. */
Packit 13e616
	if (!osm_physp_has_pkey(sa->p_log, p_mgrp->mcmember_rec.pkey,
Packit 13e616
				p_req_physp))
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/* now do the rest of the match */
Packit 13e616
	if (!validate_other_comp_fields(sa->p_log, comp_mask, p_rcvd_rec, p_mgrp,
Packit 13e616
					OSM_LOG_NONE))
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	if ((IB_MCR_COMPMASK_PROXY & comp_mask) &&
Packit 13e616
	    p_rcvd_rec->proxy_join != p_mgrp->mcmember_rec.proxy_join)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/* need to validate mtu, rate, and pkt_lifetime fields */
Packit 13e616
	if (validate_more_comp_fields(sa->p_log, p_mgrp, p_rcvd_rec,
Packit 13e616
				      comp_mask) == FALSE)
Packit 13e616
		goto Exit;
Packit 13e616
Packit 13e616
	/* Port specific fields */
Packit 13e616
	/* so did we get the PortGUID mask */
Packit 13e616
	if (IB_MCR_COMPMASK_PORT_GID & comp_mask) {
Packit 13e616
		/* try to find this port */
Packit 13e616
		p_mcm_alias_guid = osm_mgrp_get_mcm_alias_guid(p_mgrp, portguid);
Packit 13e616
		if (!p_mcm_alias_guid) /* port not in group */
Packit 13e616
			goto Exit;
Packit 13e616
		scope_state = p_mcm_alias_guid->scope_state;
Packit 13e616
		memcpy(&port_gid, &(p_mcm_alias_guid->port_gid),
Packit 13e616
		       sizeof(ib_gid_t));
Packit 13e616
		proxy_join = p_mcm_alias_guid->proxy_join;
Packit 13e616
	} else /* point to the group information */
Packit 13e616
		scope_state = p_mgrp->mcmember_rec.scope_state;
Packit 13e616
Packit 13e616
	if (IB_MCR_COMPMASK_SCOPE & comp_mask)
Packit 13e616
		scope_state_mask = 0xF0;
Packit 13e616
Packit 13e616
	if (IB_MCR_COMPMASK_JOIN_STATE & comp_mask)
Packit 13e616
		scope_state_mask = scope_state_mask | 0x0F;
Packit 13e616
Packit 13e616
	/* Many MC records returned */
Packit 13e616
	if (trusted_req == TRUE && !(IB_MCR_COMPMASK_PORT_GID & comp_mask)) {
Packit 13e616
		char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Trusted req is TRUE and no specific port defined\n");
Packit 13e616
Packit 13e616
		/* return all the ports that match in this MC group */
Packit 13e616
		p_item = cl_qmap_head(&(p_mgrp->mcm_alias_port_tbl));
Packit 13e616
		while (p_item != cl_qmap_end(&(p_mgrp->mcm_alias_port_tbl))) {
Packit 13e616
			p_mcm_alias_guid = (osm_mcm_alias_guid_t *) p_item;
Packit 13e616
Packit 13e616
			if ((scope_state_mask & p_rcvd_rec->scope_state) ==
Packit 13e616
			    (scope_state_mask & p_mcm_alias_guid->scope_state)) {
Packit 13e616
				/* add to the list */
Packit 13e616
				match_rec = p_mgrp->mcmember_rec;
Packit 13e616
				match_rec.scope_state = p_mcm_alias_guid->scope_state;
Packit 13e616
				memcpy(&match_rec.port_gid,
Packit 13e616
				       &p_mcm_alias_guid->port_gid,
Packit 13e616
				       sizeof(ib_gid_t));
Packit 13e616
				OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
					"Record of port_gid: %s"
Packit 13e616
					" in multicast_lid: 0x%X is returned\n",
Packit 13e616
					inet_ntop(AF_INET6,
Packit 13e616
						  match_rec.port_gid.raw,
Packit 13e616
						  gid_str, sizeof gid_str),
Packit 13e616
					cl_ntoh16(p_mgrp->mlid));
Packit 13e616
Packit 13e616
				match_rec.proxy_join =
Packit 13e616
				    (uint8_t) (p_mcm_alias_guid->proxy_join);
Packit 13e616
Packit 13e616
				mcmr_rcv_new_mcmr(sa, &match_rec, list);
Packit 13e616
			}
Packit 13e616
			p_item = cl_qmap_next(p_item);
Packit 13e616
		}
Packit 13e616
	} else { /* One MC record returned */
Packit 13e616
		if ((scope_state_mask & p_rcvd_rec->scope_state) !=
Packit 13e616
		    (scope_state_mask & scope_state))
Packit 13e616
			goto Exit;
Packit 13e616
Packit 13e616
		/* add to the list */
Packit 13e616
		match_rec = p_mgrp->mcmember_rec;
Packit 13e616
		match_rec.scope_state = scope_state;
Packit 13e616
		memcpy(&(match_rec.port_gid), &port_gid, sizeof(ib_gid_t));
Packit 13e616
		match_rec.proxy_join = (uint8_t) proxy_join;
Packit 13e616
Packit 13e616
		mcmr_rcv_new_mcmr(sa, &match_rec, list);
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
/**********************************************************************
Packit 13e616
 Handle a query request
Packit 13e616
**********************************************************************/
Packit 13e616
static void mcmr_query_mgrp(IN osm_sa_t * sa, IN osm_madw_t * p_madw)
Packit 13e616
{
Packit 13e616
	const ib_sa_mad_t *p_rcvd_mad;
Packit 13e616
	const ib_member_rec_t *p_rcvd_rec;
Packit 13e616
	cl_qlist_t rec_list;
Packit 13e616
	ib_net64_t comp_mask;
Packit 13e616
	osm_physp_t *p_req_physp;
Packit 13e616
	boolean_t trusted_req;
Packit 13e616
	osm_mgrp_t *p_mgrp;
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw);
Packit 13e616
	p_rcvd_rec = (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad);
Packit 13e616
	comp_mask = p_rcvd_mad->comp_mask;
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   if sm_key is not zero and does not match we never get here
Packit 13e616
	   see main SA receiver
Packit 13e616
	 */
Packit 13e616
	trusted_req = (p_rcvd_mad->sm_key != 0);
Packit 13e616
Packit 13e616
	CL_PLOCK_ACQUIRE(sa->p_lock);
Packit 13e616
Packit 13e616
	/* update the requester physical port */
Packit 13e616
	p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
Packit 13e616
						osm_madw_get_mad_addr_ptr
Packit 13e616
						(p_madw));
Packit 13e616
	if (p_req_physp == NULL) {
Packit 13e616
		CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B04: "
Packit 13e616
			"Cannot find requester physical port\n");
Packit 13e616
		goto Exit;
Packit 13e616
	}
Packit 13e616
Packit 13e616
	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
Packit 13e616
			"Requester port GUID 0x%" PRIx64 "\n",
Packit 13e616
			cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Dump of record\n");
Packit 13e616
		osm_dump_mc_record(sa->p_log, p_rcvd_rec, OSM_LOG_DEBUG);
Packit 13e616
	}
Packit 13e616
Packit 13e616
	cl_qlist_init(&rec_list);
Packit 13e616
Packit 13e616
	/* simply go over all MCGs and match */
Packit 13e616
	for (p_mgrp = (osm_mgrp_t *) cl_fmap_head(&sa->p_subn->mgrp_mgid_tbl);
Packit 13e616
	     p_mgrp != (osm_mgrp_t *) cl_fmap_end(&sa->p_subn->mgrp_mgid_tbl);
Packit 13e616
	     p_mgrp = (osm_mgrp_t *) cl_fmap_next(&p_mgrp->map_item))
Packit 13e616
		mcmr_by_comp_mask(sa, p_rcvd_rec, comp_mask, p_mgrp,
Packit 13e616
				  p_req_physp, trusted_req, &rec_list);
Packit 13e616
Packit 13e616
	CL_PLOCK_RELEASE(sa->p_lock);
Packit 13e616
Packit 13e616
	/*
Packit 13e616
	   p923 - The PortGID, JoinState and ProxyJoin shall be zero,
Packit 13e616
	   except in the case of a trusted request.
Packit 13e616
	   Note: In the mad controller we check that the SM_Key received on
Packit 13e616
	   the mad is valid. Meaning - is either zero or equal to the local
Packit 13e616
	   sm_key.
Packit 13e616
	 */
Packit 13e616
Packit 13e616
	if (!p_rcvd_mad->sm_key) {
Packit 13e616
		osm_sa_item_t *item;
Packit 13e616
		for (item = (osm_sa_item_t *) cl_qlist_head(&rec_list);
Packit 13e616
		     item != (osm_sa_item_t *) cl_qlist_end(&rec_list);
Packit 13e616
		     item =
Packit 13e616
		     (osm_sa_item_t *) cl_qlist_next(&item->list_item)) {
Packit 13e616
			memset(&item->resp.mc_rec.port_gid, 0, sizeof(ib_gid_t));
Packit 13e616
			ib_member_set_join_state(&item->resp.mc_rec, 0);
Packit 13e616
			item->resp.mc_rec.proxy_join = 0;
Packit 13e616
		}
Packit 13e616
	}
Packit 13e616
Packit 13e616
	osm_sa_respond(sa, p_madw, sizeof(ib_member_rec_t), &rec_list);
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
}
Packit 13e616
Packit 13e616
static uint8_t rate_is_valid(IN const ib_sa_mad_t *p_sa_mad,
Packit 13e616
			     IN const ib_member_rec_t *p_recvd_mcmember_rec)
Packit 13e616
{
Packit 13e616
	uint8_t rate;
Packit 13e616
Packit 13e616
	/* Validate rate if supplied */
Packit 13e616
	if ((p_sa_mad->comp_mask & IB_MCR_COMPMASK_RATE_SEL) &&
Packit 13e616
	    (p_sa_mad->comp_mask & IB_MCR_COMPMASK_RATE)) {
Packit 13e616
		rate = (uint8_t) (p_recvd_mcmember_rec->rate & 0x3F);
Packit 13e616
		return ib_rate_is_valid(rate);
Packit 13e616
	}
Packit 13e616
	return 1;
Packit 13e616
}
Packit 13e616
Packit 13e616
static int mtu_is_valid(IN const ib_sa_mad_t *p_sa_mad,
Packit 13e616
			IN const ib_member_rec_t *p_recvd_mcmember_rec)
Packit 13e616
{
Packit 13e616
	uint8_t mtu;
Packit 13e616
Packit 13e616
	/* Validate MTU if supplied */
Packit 13e616
	if ((p_sa_mad->comp_mask & IB_MCR_COMPMASK_MTU_SEL) &&
Packit 13e616
	    (p_sa_mad->comp_mask & IB_MCR_COMPMASK_MTU)) {
Packit 13e616
		mtu = (uint8_t) (p_recvd_mcmember_rec->mtu & 0x3F);
Packit 13e616
		return ib_mtu_is_valid(mtu);
Packit 13e616
	}
Packit 13e616
	return 1;
Packit 13e616
}
Packit 13e616
Packit 13e616
void osm_mcmr_rcv_process(IN void *context, IN void *data)
Packit 13e616
{
Packit 13e616
	osm_sa_t *sa = context;
Packit 13e616
	osm_madw_t *p_madw = data;
Packit 13e616
	ib_sa_mad_t *p_sa_mad;
Packit 13e616
	ib_member_rec_t *p_recvd_mcmember_rec;
Packit 13e616
Packit 13e616
	CL_ASSERT(sa);
Packit 13e616
Packit 13e616
	OSM_LOG_ENTER(sa->p_log);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_madw);
Packit 13e616
Packit 13e616
	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
Packit 13e616
	p_recvd_mcmember_rec =
Packit 13e616
	    (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
Packit 13e616
Packit 13e616
	CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_MCMEMBER_RECORD);
Packit 13e616
Packit 13e616
	switch (p_sa_mad->method) {
Packit 13e616
	case IB_MAD_METHOD_SET:
Packit 13e616
		if (!check_join_comp_mask(p_sa_mad->comp_mask)) {
Packit 13e616
			char gid_str[INET6_ADDRSTRLEN];
Packit 13e616
			char gid_str2[INET6_ADDRSTRLEN];
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B18: "
Packit 13e616
				"component mask = 0x%016" PRIx64 ", "
Packit 13e616
				"expected comp mask = 0x%016" PRIx64 ", "
Packit 13e616
				"MGID: %s for PortGID: %s\n",
Packit 13e616
				cl_ntoh64(p_sa_mad->comp_mask),
Packit 13e616
				CL_NTOH64(JOIN_MC_COMP_MASK),
Packit 13e616
				inet_ntop(AF_INET6,
Packit 13e616
					  p_recvd_mcmember_rec->mgid.raw,
Packit 13e616
					  gid_str, sizeof gid_str),
Packit 13e616
				inet_ntop(AF_INET6,
Packit 13e616
					  p_recvd_mcmember_rec->port_gid.raw,
Packit 13e616
					  gid_str2, sizeof gid_str2));
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_INSUF_COMPS);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
		if (!rate_is_valid(p_sa_mad, p_recvd_mcmember_rec) ||
Packit 13e616
		    !mtu_is_valid(p_sa_mad, p_recvd_mcmember_rec)) {
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		 * Join or Create Multicast Group
Packit 13e616
		 */
Packit 13e616
		mcmr_rcv_join_mgrp(sa, p_madw);
Packit 13e616
		break;
Packit 13e616
	case IB_MAD_METHOD_DELETE:
Packit 13e616
		if (!check_join_comp_mask(p_sa_mad->comp_mask)) {
Packit 13e616
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B20: "
Packit 13e616
				"component mask = 0x%016" PRIx64 ", "
Packit 13e616
				"expected comp mask = 0x%016" PRIx64 "\n",
Packit 13e616
				cl_ntoh64(p_sa_mad->comp_mask),
Packit 13e616
				CL_NTOH64(JOIN_MC_COMP_MASK));
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_INSUF_COMPS);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
		if (!rate_is_valid(p_sa_mad, p_recvd_mcmember_rec) ||
Packit 13e616
		    !mtu_is_valid(p_sa_mad, p_recvd_mcmember_rec)) {
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		 * Leave Multicast Group
Packit 13e616
		 */
Packit 13e616
		mcmr_rcv_leave_mgrp(sa, p_madw);
Packit 13e616
		break;
Packit 13e616
	case IB_MAD_METHOD_GET:
Packit 13e616
	case IB_MAD_METHOD_GETTABLE:
Packit 13e616
		if (!rate_is_valid(p_sa_mad, p_recvd_mcmember_rec) ||
Packit 13e616
		    !mtu_is_valid(p_sa_mad, p_recvd_mcmember_rec)) {
Packit 13e616
			osm_sa_send_error(sa, p_madw,
Packit 13e616
					  IB_SA_MAD_STATUS_REQ_INVALID);
Packit 13e616
			goto Exit;
Packit 13e616
		}
Packit 13e616
Packit 13e616
		/*
Packit 13e616
		 * Querying a Multicast Group
Packit 13e616
		 */
Packit 13e616
		mcmr_query_mgrp(sa, p_madw);
Packit 13e616
		break;
Packit 13e616
	default:
Packit 13e616
		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B21: "
Packit 13e616
			"Unsupported Method (%s) for MCMemberRecord request\n",
Packit 13e616
			ib_get_sa_method_str(p_sa_mad->method));
Packit 13e616
		osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
Packit 13e616
		break;
Packit 13e616
	}
Packit 13e616
Packit 13e616
Exit:
Packit 13e616
	OSM_LOG_EXIT(sa->p_log);
Packit 13e616
	return;
Packit 13e616
}