1321936Shselasky/*
2321936Shselasky * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3321936Shselasky * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
4321936Shselasky * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5321936Shselasky * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
6321936Shselasky *
7321936Shselasky * This software is available to you under a choice of one of two
8321936Shselasky * licenses.  You may choose to be licensed under the terms of the GNU
9321936Shselasky * General Public License (GPL) Version 2, available from the file
10321936Shselasky * COPYING in the main directory of this source tree, or the
11321936Shselasky * OpenIB.org BSD license below:
12321936Shselasky *
13321936Shselasky *     Redistribution and use in source and binary forms, with or
14321936Shselasky *     without modification, are permitted provided that the following
15321936Shselasky *     conditions are met:
16321936Shselasky *
17321936Shselasky *      - Redistributions of source code must retain the above
18321936Shselasky *        copyright notice, this list of conditions and the following
19321936Shselasky *        disclaimer.
20321936Shselasky *
21321936Shselasky *      - Redistributions in binary form must reproduce the above
22321936Shselasky *        copyright notice, this list of conditions and the following
23321936Shselasky *        disclaimer in the documentation and/or other materials
24321936Shselasky *        provided with the distribution.
25321936Shselasky *
26321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33321936Shselasky * SOFTWARE.
34321936Shselasky *
35321936Shselasky */
36321936Shselasky
37321936Shselasky/*
38321936Shselasky * Abstract:
39321936Shselasky *    Implementation of osm_sr_rcv_t.
40321936Shselasky * This object represents the ServiceRecord Receiver object.
41321936Shselasky * This object is part of the opensm family of objects.
42321936Shselasky */
43321936Shselasky
44321936Shselasky#if HAVE_CONFIG_H
45321936Shselasky#  include <config.h>
46321936Shselasky#endif				/* HAVE_CONFIG_H */
47321936Shselasky
48321936Shselasky#include <string.h>
49321936Shselasky#include <iba/ib_types.h>
50321936Shselasky#include <complib/cl_qmap.h>
51321936Shselasky#include <complib/cl_passivelock.h>
52321936Shselasky#include <complib/cl_debug.h>
53321936Shselasky#include <complib/cl_qlist.h>
54321936Shselasky#include <opensm/osm_file_ids.h>
55321936Shselasky#define FILE_ID OSM_FILE_SA_SERVICE_RECORD_C
56321936Shselasky#include <vendor/osm_vendor_api.h>
57321936Shselasky#include <opensm/osm_port.h>
58321936Shselasky#include <opensm/osm_node.h>
59321936Shselasky#include <opensm/osm_switch.h>
60321936Shselasky#include <opensm/osm_helper.h>
61321936Shselasky#include <opensm/osm_sa.h>
62321936Shselasky#include <opensm/osm_service.h>
63321936Shselasky#include <opensm/osm_pkey.h>
64321936Shselasky
65321936Shselasky#define SA_SR_RESP_SIZE SA_ITEM_RESP_SIZE(service_rec)
66321936Shselasky
67321936Shselaskytypedef struct osm_sr_match_item {
68321936Shselasky	cl_qlist_t sr_list;
69321936Shselasky	ib_service_record_t *p_service_rec;
70321936Shselasky	ib_net64_t comp_mask;
71321936Shselasky	osm_sa_t *sa;
72321936Shselasky} osm_sr_match_item_t;
73321936Shselasky
74321936Shselaskytypedef struct osm_sr_search_ctxt {
75321936Shselasky	osm_sr_match_item_t *p_sr_item;
76321936Shselasky	const osm_physp_t *p_req_physp;
77321936Shselasky} osm_sr_search_ctxt_t;
78321936Shselasky
79321936Shselaskystatic boolean_t
80321936Shselaskymatch_service_pkey_with_ports_pkey(IN osm_sa_t * sa,
81321936Shselasky				   IN const osm_madw_t * p_madw,
82321936Shselasky				   ib_service_record_t * p_service_rec,
83321936Shselasky				   ib_net64_t const comp_mask)
84321936Shselasky{
85321936Shselasky	boolean_t valid = TRUE;
86321936Shselasky	osm_physp_t *p_req_physp;
87321936Shselasky	ib_net64_t service_guid;
88321936Shselasky	osm_port_t *service_port;
89321936Shselasky
90321936Shselasky	/* update the requester physical port */
91321936Shselasky	p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
92321936Shselasky						osm_madw_get_mad_addr_ptr
93321936Shselasky						(p_madw));
94321936Shselasky	if (p_req_physp == NULL) {
95321936Shselasky		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2404: "
96321936Shselasky			"Cannot find requester physical port\n");
97321936Shselasky		valid = FALSE;
98321936Shselasky		goto Exit;
99321936Shselasky	}
100321936Shselasky	OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
101321936Shselasky		"Requester port GUID 0x%" PRIx64 "\n",
102321936Shselasky		cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
103321936Shselasky
104321936Shselasky	if ((comp_mask & IB_SR_COMPMASK_SPKEY) == IB_SR_COMPMASK_SPKEY) {
105321936Shselasky		/* We have a ServiceP_Key - check matching on requester port,
106321936Shselasky		   and ServiceGid port (if such exists) */
107321936Shselasky		/* Make sure it matches the p_req_physp */
108321936Shselasky		if (!osm_physp_has_pkey
109321936Shselasky		    (sa->p_log, p_service_rec->service_pkey, p_req_physp)) {
110321936Shselasky			valid = FALSE;
111321936Shselasky			goto Exit;
112321936Shselasky		}
113321936Shselasky
114321936Shselasky		/* If unicast, make sure it matches the port of the ServiceGid */
115321936Shselasky		if (comp_mask & IB_SR_COMPMASK_SGID &&
116321936Shselasky		    !ib_gid_is_multicast(&p_service_rec->service_gid)) {
117321936Shselasky			service_guid =
118321936Shselasky			    p_service_rec->service_gid.unicast.interface_id;
119321936Shselasky			service_port =
120321936Shselasky			    osm_get_port_by_alias_guid(sa->p_subn, service_guid);
121321936Shselasky			if (!service_port) {
122321936Shselasky				OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2405: "
123321936Shselasky					"No port object for port 0x%016" PRIx64
124321936Shselasky					"\n", cl_ntoh64(service_guid));
125321936Shselasky				valid = FALSE;
126321936Shselasky				goto Exit;
127321936Shselasky			}
128321936Shselasky			/* check on the table of the default physical port of the service port */
129321936Shselasky			if (!osm_physp_has_pkey(sa->p_log,
130321936Shselasky						p_service_rec->service_pkey,
131321936Shselasky						service_port->p_physp)) {
132321936Shselasky				valid = FALSE;
133321936Shselasky				goto Exit;
134321936Shselasky			}
135321936Shselasky		}
136321936Shselasky	}
137321936Shselasky
138321936ShselaskyExit:
139321936Shselasky	return valid;
140321936Shselasky}
141321936Shselasky
142321936Shselaskystatic boolean_t
143321936Shselaskymatch_name_to_key_association(IN osm_sa_t * sa,
144321936Shselasky			      ib_service_record_t * p_service_rec,
145321936Shselasky			      ib_net64_t comp_mask)
146321936Shselasky{
147321936Shselasky	UNUSED_PARAM(p_service_rec);
148321936Shselasky	UNUSED_PARAM(sa);
149321936Shselasky
150321936Shselasky	if ((comp_mask & (IB_SR_COMPMASK_SKEY | IB_SR_COMPMASK_SNAME)) ==
151321936Shselasky	    (IB_SR_COMPMASK_SKEY | IB_SR_COMPMASK_SNAME)) {
152321936Shselasky		/* For now, we are not maintaining the ServiceAssociation record
153321936Shselasky		 * so just return TRUE
154321936Shselasky		 */
155321936Shselasky		return TRUE;
156321936Shselasky	}
157321936Shselasky
158321936Shselasky	return TRUE;
159321936Shselasky}
160321936Shselasky
161321936Shselaskystatic boolean_t validate_sr(IN osm_sa_t * sa, IN const osm_madw_t * p_madw)
162321936Shselasky{
163321936Shselasky	boolean_t valid = TRUE;
164321936Shselasky	ib_sa_mad_t *p_sa_mad;
165321936Shselasky	ib_service_record_t *p_recvd_service_rec;
166321936Shselasky
167321936Shselasky	OSM_LOG_ENTER(sa->p_log);
168321936Shselasky
169321936Shselasky	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
170321936Shselasky	p_recvd_service_rec =
171321936Shselasky	    (ib_service_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
172321936Shselasky
173321936Shselasky	valid = match_service_pkey_with_ports_pkey(sa, p_madw,
174321936Shselasky						   p_recvd_service_rec,
175321936Shselasky						   p_sa_mad->comp_mask);
176321936Shselasky	if (!valid) {
177321936Shselasky		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
178321936Shselasky			"No Match for Service Pkey\n");
179321936Shselasky		valid = FALSE;
180321936Shselasky		goto Exit;
181321936Shselasky	}
182321936Shselasky
183321936Shselasky	valid = match_name_to_key_association(sa, p_recvd_service_rec,
184321936Shselasky					      p_sa_mad->comp_mask);
185321936Shselasky	if (!valid) {
186321936Shselasky		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
187321936Shselasky			"Service Record Name to key matching failed\n");
188321936Shselasky		valid = FALSE;
189321936Shselasky		goto Exit;
190321936Shselasky	}
191321936Shselasky
192321936ShselaskyExit:
193321936Shselasky	OSM_LOG_EXIT(sa->p_log);
194321936Shselasky	return valid;
195321936Shselasky}
196321936Shselasky
197321936Shselaskystatic void sr_rcv_respond(IN osm_sa_t * sa, IN osm_madw_t * p_madw,
198321936Shselasky			   IN cl_qlist_t * p_list)
199321936Shselasky{
200321936Shselasky	/* p923 - The ServiceKey shall be set to 0, except in the case of
201321936Shselasky	   a trusted request.
202321936Shselasky	   Note: In the mad controller we check that the SM_Key received on
203321936Shselasky	   the mad is valid. Meaning - is either zero or equal to the local
204321936Shselasky	   sm_key.
205321936Shselasky	 */
206321936Shselasky	if (!osm_madw_get_sa_mad_ptr(p_madw)->sm_key) {
207321936Shselasky		osm_sa_item_t *item;
208321936Shselasky		for (item = (osm_sa_item_t *) cl_qlist_head(p_list);
209321936Shselasky		     item != (osm_sa_item_t *) cl_qlist_end(p_list);
210321936Shselasky		     item = (osm_sa_item_t *) cl_qlist_next(&item->list_item))
211321936Shselasky			memset(item->resp.service_rec.service_key, 0,
212321936Shselasky			       sizeof(item->resp.service_rec.service_key));
213321936Shselasky	}
214321936Shselasky
215321936Shselasky	osm_sa_respond(sa, p_madw, sizeof(ib_service_record_t), p_list);
216321936Shselasky}
217321936Shselasky
218321936Shselaskystatic void get_matching_sr(IN cl_list_item_t * p_list_item, IN void *context)
219321936Shselasky{
220321936Shselasky	osm_sr_search_ctxt_t *p_ctxt = context;
221321936Shselasky	osm_svcr_t *p_svcr = (osm_svcr_t *) p_list_item;
222321936Shselasky	osm_sa_item_t *p_sr_pool_item;
223321936Shselasky	osm_sr_match_item_t *p_sr_item = p_ctxt->p_sr_item;
224321936Shselasky	ib_net64_t comp_mask = p_sr_item->comp_mask;
225321936Shselasky	const osm_physp_t *p_req_physp = p_ctxt->p_req_physp;
226321936Shselasky
227321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SID) {
228321936Shselasky		if (p_sr_item->p_service_rec->service_id !=
229321936Shselasky		    p_svcr->service_record.service_id)
230321936Shselasky			return;
231321936Shselasky	}
232321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SGID) {
233321936Shselasky		if (memcmp(&p_sr_item->p_service_rec->service_gid,
234321936Shselasky			   &p_svcr->service_record.service_gid,
235321936Shselasky			   sizeof(p_svcr->service_record.service_gid)) != 0)
236321936Shselasky			return;
237321936Shselasky	}
238321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SPKEY) {
239321936Shselasky		if (p_sr_item->p_service_rec->service_pkey !=
240321936Shselasky		    p_svcr->service_record.service_pkey)
241321936Shselasky			return;
242321936Shselasky	}
243321936Shselasky
244321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SKEY) {
245321936Shselasky		if (memcmp(p_sr_item->p_service_rec->service_key,
246321936Shselasky			   p_svcr->service_record.service_key,
247321936Shselasky			   16 * sizeof(uint8_t)))
248321936Shselasky			return;
249321936Shselasky	}
250321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SNAME) {
251321936Shselasky		if (memcmp(p_sr_item->p_service_rec->service_name,
252321936Shselasky			   p_svcr->service_record.service_name,
253321936Shselasky			   sizeof(p_svcr->service_record.service_name)) != 0)
254321936Shselasky			return;
255321936Shselasky	}
256321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_0) {
257321936Shselasky		if (p_sr_item->p_service_rec->service_data8[0] !=
258321936Shselasky		    p_svcr->service_record.service_data8[0])
259321936Shselasky			return;
260321936Shselasky	}
261321936Shselasky
262321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_1) {
263321936Shselasky		if (p_sr_item->p_service_rec->service_data8[1] !=
264321936Shselasky		    p_svcr->service_record.service_data8[1])
265321936Shselasky			return;
266321936Shselasky	}
267321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_2) {
268321936Shselasky		if (p_sr_item->p_service_rec->service_data8[2] !=
269321936Shselasky		    p_svcr->service_record.service_data8[2])
270321936Shselasky			return;
271321936Shselasky	}
272321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_3) {
273321936Shselasky		if (p_sr_item->p_service_rec->service_data8[3] !=
274321936Shselasky		    p_svcr->service_record.service_data8[3])
275321936Shselasky			return;
276321936Shselasky	}
277321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_4) {
278321936Shselasky		if (p_sr_item->p_service_rec->service_data8[4] !=
279321936Shselasky		    p_svcr->service_record.service_data8[4])
280321936Shselasky			return;
281321936Shselasky	}
282321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_5) {
283321936Shselasky		if (p_sr_item->p_service_rec->service_data8[5] !=
284321936Shselasky		    p_svcr->service_record.service_data8[5])
285321936Shselasky			return;
286321936Shselasky	}
287321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_6) {
288321936Shselasky		if (p_sr_item->p_service_rec->service_data8[6] !=
289321936Shselasky		    p_svcr->service_record.service_data8[6])
290321936Shselasky			return;
291321936Shselasky	}
292321936Shselasky
293321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_7) {
294321936Shselasky		if (p_sr_item->p_service_rec->service_data8[7] !=
295321936Shselasky		    p_svcr->service_record.service_data8[7])
296321936Shselasky			return;
297321936Shselasky	}
298321936Shselasky
299321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_8) {
300321936Shselasky		if (p_sr_item->p_service_rec->service_data8[8] !=
301321936Shselasky		    p_svcr->service_record.service_data8[8])
302321936Shselasky			return;
303321936Shselasky	}
304321936Shselasky
305321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_9) {
306321936Shselasky		if (p_sr_item->p_service_rec->service_data8[9] !=
307321936Shselasky		    p_svcr->service_record.service_data8[9])
308321936Shselasky			return;
309321936Shselasky	}
310321936Shselasky
311321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_10) {
312321936Shselasky		if (p_sr_item->p_service_rec->service_data8[10] !=
313321936Shselasky		    p_svcr->service_record.service_data8[10])
314321936Shselasky			return;
315321936Shselasky	}
316321936Shselasky
317321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_11) {
318321936Shselasky		if (p_sr_item->p_service_rec->service_data8[11] !=
319321936Shselasky		    p_svcr->service_record.service_data8[11])
320321936Shselasky			return;
321321936Shselasky	}
322321936Shselasky
323321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_12) {
324321936Shselasky		if (p_sr_item->p_service_rec->service_data8[12] !=
325321936Shselasky		    p_svcr->service_record.service_data8[12])
326321936Shselasky			return;
327321936Shselasky	}
328321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_13) {
329321936Shselasky		if (p_sr_item->p_service_rec->service_data8[13] !=
330321936Shselasky		    p_svcr->service_record.service_data8[13])
331321936Shselasky			return;
332321936Shselasky	}
333321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_14) {
334321936Shselasky		if (p_sr_item->p_service_rec->service_data8[14] !=
335321936Shselasky		    p_svcr->service_record.service_data8[14])
336321936Shselasky			return;
337321936Shselasky	}
338321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA8_15) {
339321936Shselasky		if (p_sr_item->p_service_rec->service_data8[15] !=
340321936Shselasky		    p_svcr->service_record.service_data8[15])
341321936Shselasky			return;
342321936Shselasky	}
343321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA16_0) {
344321936Shselasky		if (p_sr_item->p_service_rec->service_data16[0] !=
345321936Shselasky		    p_svcr->service_record.service_data16[0])
346321936Shselasky			return;
347321936Shselasky	}
348321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA16_1) {
349321936Shselasky		if (p_sr_item->p_service_rec->service_data16[1] !=
350321936Shselasky		    p_svcr->service_record.service_data16[1])
351321936Shselasky			return;
352321936Shselasky	}
353321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA16_2) {
354321936Shselasky		if (p_sr_item->p_service_rec->service_data16[2] !=
355321936Shselasky		    p_svcr->service_record.service_data16[2])
356321936Shselasky			return;
357321936Shselasky	}
358321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA16_3) {
359321936Shselasky		if (p_sr_item->p_service_rec->service_data16[3] !=
360321936Shselasky		    p_svcr->service_record.service_data16[3])
361321936Shselasky			return;
362321936Shselasky	}
363321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA16_4) {
364321936Shselasky		if (p_sr_item->p_service_rec->service_data16[4] !=
365321936Shselasky		    p_svcr->service_record.service_data16[4])
366321936Shselasky			return;
367321936Shselasky	}
368321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA16_5) {
369321936Shselasky		if (p_sr_item->p_service_rec->service_data16[5] !=
370321936Shselasky		    p_svcr->service_record.service_data16[5])
371321936Shselasky			return;
372321936Shselasky	}
373321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA16_6) {
374321936Shselasky		if (p_sr_item->p_service_rec->service_data16[6] !=
375321936Shselasky		    p_svcr->service_record.service_data16[6])
376321936Shselasky			return;
377321936Shselasky	}
378321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA16_7) {
379321936Shselasky		if (p_sr_item->p_service_rec->service_data16[7] !=
380321936Shselasky		    p_svcr->service_record.service_data16[7])
381321936Shselasky			return;
382321936Shselasky	}
383321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA32_0) {
384321936Shselasky		if (p_sr_item->p_service_rec->service_data32[0] !=
385321936Shselasky		    p_svcr->service_record.service_data32[0])
386321936Shselasky			return;
387321936Shselasky	}
388321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA32_1) {
389321936Shselasky		if (p_sr_item->p_service_rec->service_data32[1] !=
390321936Shselasky		    p_svcr->service_record.service_data32[1])
391321936Shselasky			return;
392321936Shselasky	}
393321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA32_2) {
394321936Shselasky		if (p_sr_item->p_service_rec->service_data32[2] !=
395321936Shselasky		    p_svcr->service_record.service_data32[2])
396321936Shselasky			return;
397321936Shselasky	}
398321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA32_3) {
399321936Shselasky		if (p_sr_item->p_service_rec->service_data32[3] !=
400321936Shselasky		    p_svcr->service_record.service_data32[3])
401321936Shselasky			return;
402321936Shselasky	}
403321936Shselasky
404321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA64_0) {
405321936Shselasky		if (p_sr_item->p_service_rec->service_data64[0] !=
406321936Shselasky		    p_svcr->service_record.service_data64[0])
407321936Shselasky			return;
408321936Shselasky	}
409321936Shselasky	if (comp_mask & IB_SR_COMPMASK_SDATA64_1) {
410321936Shselasky		if (p_sr_item->p_service_rec->service_data64[1] !=
411321936Shselasky		    p_svcr->service_record.service_data64[1])
412321936Shselasky			return;
413321936Shselasky	}
414321936Shselasky
415321936Shselasky	/* Check that the requester port has the pkey which is the service_pkey.
416321936Shselasky	   If not - then it cannot receive this ServiceRecord. */
417321936Shselasky	/* The check is relevant only if the service_pkey is valid */
418321936Shselasky	if (!ib_pkey_is_invalid(p_svcr->service_record.service_pkey)) {
419321936Shselasky		if (!osm_physp_has_pkey(p_sr_item->sa->p_log,
420321936Shselasky					p_svcr->service_record.service_pkey,
421321936Shselasky					p_req_physp)) {
422321936Shselasky			OSM_LOG(p_sr_item->sa->p_log, OSM_LOG_VERBOSE,
423321936Shselasky				"requester port doesn't have the service_pkey: 0x%X\n",
424321936Shselasky				cl_ntoh16(p_svcr->service_record.service_pkey));
425321936Shselasky			return;
426321936Shselasky		}
427321936Shselasky	}
428321936Shselasky
429321936Shselasky	p_sr_pool_item = malloc(SA_SR_RESP_SIZE);
430321936Shselasky	if (p_sr_pool_item == NULL) {
431321936Shselasky		OSM_LOG(p_sr_item->sa->p_log, OSM_LOG_ERROR, "ERR 2408: "
432321936Shselasky			"Unable to acquire Service Record from pool\n");
433321936Shselasky		goto Exit;
434321936Shselasky	}
435321936Shselasky
436321936Shselasky	p_sr_pool_item->resp.service_rec = p_svcr->service_record;
437321936Shselasky
438321936Shselasky	cl_qlist_insert_tail(&p_sr_item->sr_list, &p_sr_pool_item->list_item);
439321936Shselasky
440321936ShselaskyExit:
441321936Shselasky	return;
442321936Shselasky}
443321936Shselasky
444321936Shselaskystatic void sr_rcv_process_get_method(osm_sa_t * sa, IN osm_madw_t * p_madw)
445321936Shselasky{
446321936Shselasky	ib_sa_mad_t *p_sa_mad;
447321936Shselasky	ib_service_record_t *p_recvd_service_rec;
448321936Shselasky	osm_sr_match_item_t sr_match_item;
449321936Shselasky	osm_sr_search_ctxt_t context;
450321936Shselasky	osm_physp_t *p_req_physp;
451321936Shselasky
452321936Shselasky	OSM_LOG_ENTER(sa->p_log);
453321936Shselasky
454321936Shselasky	CL_ASSERT(p_madw);
455321936Shselasky
456321936Shselasky	/* Grab the lock */
457321936Shselasky	cl_plock_acquire(sa->p_lock);
458321936Shselasky
459321936Shselasky	/* update the requester physical port */
460321936Shselasky	p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
461321936Shselasky						osm_madw_get_mad_addr_ptr
462321936Shselasky						(p_madw));
463321936Shselasky	if (p_req_physp == NULL) {
464321936Shselasky		cl_plock_release(sa->p_lock);
465321936Shselasky		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2409: "
466321936Shselasky			"Cannot find requester physical port\n");
467321936Shselasky		goto Exit;
468321936Shselasky	}
469321936Shselasky
470321936Shselasky	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
471321936Shselasky	p_recvd_service_rec =
472321936Shselasky	    (ib_service_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
473321936Shselasky
474321936Shselasky	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
475321936Shselasky		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
476321936Shselasky			"Requester port GUID 0x%" PRIx64 "\n",
477321936Shselasky			cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
478321936Shselasky		osm_dump_service_record_v2(sa->p_log, p_recvd_service_rec,
479321936Shselasky					   FILE_ID, OSM_LOG_DEBUG);
480321936Shselasky	}
481321936Shselasky
482321936Shselasky	cl_qlist_init(&sr_match_item.sr_list);
483321936Shselasky	sr_match_item.p_service_rec = p_recvd_service_rec;
484321936Shselasky	sr_match_item.comp_mask = p_sa_mad->comp_mask;
485321936Shselasky	sr_match_item.sa = sa;
486321936Shselasky
487321936Shselasky	context.p_sr_item = &sr_match_item;
488321936Shselasky	context.p_req_physp = p_req_physp;
489321936Shselasky
490321936Shselasky	cl_qlist_apply_func(&sa->p_subn->sa_sr_list, get_matching_sr, &context);
491321936Shselasky
492321936Shselasky	cl_plock_release(sa->p_lock);
493321936Shselasky
494321936Shselasky	if (p_sa_mad->method == IB_MAD_METHOD_GET &&
495321936Shselasky	    cl_qlist_count(&sr_match_item.sr_list) == 0) {
496321936Shselasky		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
497321936Shselasky			"No records matched the Service Record query\n");
498321936Shselasky		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RECORDS);
499321936Shselasky		goto Exit;
500321936Shselasky	}
501321936Shselasky
502321936Shselasky	sr_rcv_respond(sa, p_madw, &sr_match_item.sr_list);
503321936Shselasky
504321936ShselaskyExit:
505321936Shselasky	OSM_LOG_EXIT(sa->p_log);
506321936Shselasky	return;
507321936Shselasky}
508321936Shselasky
509321936Shselaskystatic void sr_rcv_process_set_method(osm_sa_t * sa, IN osm_madw_t * p_madw)
510321936Shselasky{
511321936Shselasky	ib_sa_mad_t *p_sa_mad;
512321936Shselasky	ib_service_record_t *p_recvd_service_rec;
513321936Shselasky	ib_net64_t comp_mask;
514321936Shselasky	osm_svcr_t *p_svcr;
515321936Shselasky	osm_sa_item_t *p_sr_item;
516321936Shselasky	cl_qlist_t sr_list;
517321936Shselasky
518321936Shselasky	OSM_LOG_ENTER(sa->p_log);
519321936Shselasky
520321936Shselasky	CL_ASSERT(p_madw);
521321936Shselasky
522321936Shselasky	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
523321936Shselasky	p_recvd_service_rec =
524321936Shselasky	    (ib_service_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
525321936Shselasky
526321936Shselasky	comp_mask = p_sa_mad->comp_mask;
527321936Shselasky
528321936Shselasky	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG))
529321936Shselasky		osm_dump_service_record_v2(sa->p_log, p_recvd_service_rec,
530321936Shselasky					   FILE_ID, OSM_LOG_DEBUG);
531321936Shselasky
532321936Shselasky	if ((comp_mask & (IB_SR_COMPMASK_SID | IB_SR_COMPMASK_SGID)) !=
533321936Shselasky	    (IB_SR_COMPMASK_SID | IB_SR_COMPMASK_SGID)) {
534321936Shselasky		cl_plock_release(sa->p_lock);
535321936Shselasky		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
536321936Shselasky			"Component Mask RID check failed for METHOD_SET\n");
537321936Shselasky		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
538321936Shselasky		goto Exit;
539321936Shselasky	}
540321936Shselasky
541321936Shselasky	/* if we were not provided with a service lease make it infinite */
542321936Shselasky	if (!(comp_mask & IB_SR_COMPMASK_SLEASE)) {
543321936Shselasky		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
544321936Shselasky			"ServiceLease Component Mask not set - using infinite lease\n");
545321936Shselasky		p_recvd_service_rec->service_lease = 0xFFFFFFFF;
546321936Shselasky	}
547321936Shselasky
548321936Shselasky	/* If Record exists with matching RID */
549321936Shselasky	p_svcr = osm_svcr_get_by_rid(sa->p_subn, sa->p_log,
550321936Shselasky				     p_recvd_service_rec);
551321936Shselasky
552321936Shselasky	if (p_svcr == NULL) {
553321936Shselasky		/* Create the instance of the osm_svcr_t object */
554321936Shselasky		p_svcr = osm_svcr_new(p_recvd_service_rec);
555321936Shselasky		if (p_svcr == NULL) {
556321936Shselasky			cl_plock_release(sa->p_lock);
557321936Shselasky			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2411: "
558321936Shselasky				"Failed to create new service record\n");
559321936Shselasky
560321936Shselasky			osm_sa_send_error(sa, p_madw,
561321936Shselasky					  IB_SA_MAD_STATUS_NO_RESOURCES);
562321936Shselasky			goto Exit;
563321936Shselasky		}
564321936Shselasky
565321936Shselasky		/* Add this new osm_svcr_t object to subnet object */
566321936Shselasky		osm_svcr_insert_to_db(sa->p_subn, sa->p_log, p_svcr);
567321936Shselasky
568321936Shselasky	} else			/* Update the old instance of the osm_svcr_t object */
569321936Shselasky		osm_svcr_init(p_svcr, p_recvd_service_rec);
570321936Shselasky
571321936Shselasky	cl_plock_release(sa->p_lock);
572321936Shselasky
573321936Shselasky	if (p_recvd_service_rec->service_lease != 0xFFFFFFFF) {
574321936Shselasky#if 0
575321936Shselasky		cl_timer_trim(&sa->sr_timer,
576321936Shselasky			      p_recvd_service_rec->service_lease * 1000);
577321936Shselasky#endif
578321936Shselasky		/*  This was a bug since no check was made to see if too long */
579321936Shselasky		/*  just make sure the timer works - get a call back within a second */
580321936Shselasky		cl_timer_trim(&sa->sr_timer, 1000);
581321936Shselasky		p_svcr->modified_time = cl_get_time_stamp_sec();
582321936Shselasky	}
583321936Shselasky
584321936Shselasky	p_sr_item = malloc(SA_SR_RESP_SIZE);
585321936Shselasky	if (p_sr_item == NULL) {
586321936Shselasky		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2412: "
587321936Shselasky			"Unable to acquire Service record\n");
588321936Shselasky		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES);
589321936Shselasky		goto Exit;
590321936Shselasky	}
591321936Shselasky
592321936Shselasky	if ((comp_mask & IB_SR_COMPMASK_SPKEY) != IB_SR_COMPMASK_SPKEY)
593321936Shselasky		/* Set the Default Service P_Key in the response */
594321936Shselasky		p_recvd_service_rec->service_pkey = IB_DEFAULT_PKEY;
595321936Shselasky
596321936Shselasky	p_sr_item->resp.service_rec = *p_recvd_service_rec;
597321936Shselasky	cl_qlist_init(&sr_list);
598321936Shselasky
599321936Shselasky	cl_qlist_insert_tail(&sr_list, &p_sr_item->list_item);
600321936Shselasky
601321936Shselasky	sr_rcv_respond(sa, p_madw, &sr_list);
602321936Shselasky
603321936ShselaskyExit:
604321936Shselasky	OSM_LOG_EXIT(sa->p_log);
605321936Shselasky}
606321936Shselasky
607321936Shselaskystatic void sr_rcv_process_delete_method(osm_sa_t * sa, IN osm_madw_t * p_madw)
608321936Shselasky{
609321936Shselasky	ib_sa_mad_t *p_sa_mad;
610321936Shselasky	ib_service_record_t *p_recvd_service_rec;
611321936Shselasky	osm_svcr_t *p_svcr;
612321936Shselasky	osm_sa_item_t *p_sr_item;
613321936Shselasky	cl_qlist_t sr_list;
614321936Shselasky
615321936Shselasky	OSM_LOG_ENTER(sa->p_log);
616321936Shselasky
617321936Shselasky	CL_ASSERT(p_madw);
618321936Shselasky
619321936Shselasky	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
620321936Shselasky	p_recvd_service_rec =
621321936Shselasky	    (ib_service_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
622321936Shselasky
623321936Shselasky	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG))
624321936Shselasky		osm_dump_service_record_v2(sa->p_log, p_recvd_service_rec,
625321936Shselasky					   FILE_ID, OSM_LOG_DEBUG);
626321936Shselasky
627321936Shselasky	/* If Record exists with matching RID */
628321936Shselasky	p_svcr = osm_svcr_get_by_rid(sa->p_subn, sa->p_log,
629321936Shselasky				     p_recvd_service_rec);
630321936Shselasky
631321936Shselasky	if (p_svcr == NULL) {
632321936Shselasky		cl_plock_release(sa->p_lock);
633321936Shselasky		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
634321936Shselasky			"No records matched the RID\n");
635321936Shselasky		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RECORDS);
636321936Shselasky		goto Exit;
637321936Shselasky	}
638321936Shselasky
639321936Shselasky	osm_svcr_remove_from_db(sa->p_subn, sa->p_log, p_svcr);
640321936Shselasky	cl_plock_release(sa->p_lock);
641321936Shselasky
642321936Shselasky	p_sr_item = malloc(SA_SR_RESP_SIZE);
643321936Shselasky	if (p_sr_item == NULL) {
644321936Shselasky		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2413: "
645321936Shselasky			"Unable to acquire Service record\n");
646321936Shselasky		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES);
647321936Shselasky		osm_svcr_delete(p_svcr);
648321936Shselasky		goto Exit;
649321936Shselasky	}
650321936Shselasky
651321936Shselasky	/* provide back the copy of the record */
652321936Shselasky	p_sr_item->resp.service_rec = p_svcr->service_record;
653321936Shselasky	cl_qlist_init(&sr_list);
654321936Shselasky
655321936Shselasky	cl_qlist_insert_tail(&sr_list, &p_sr_item->list_item);
656321936Shselasky
657321936Shselasky	osm_svcr_delete(p_svcr);
658321936Shselasky
659321936Shselasky	sr_rcv_respond(sa, p_madw, &sr_list);
660321936Shselasky
661321936ShselaskyExit:
662321936Shselasky	OSM_LOG_EXIT(sa->p_log);
663321936Shselasky	return;
664321936Shselasky}
665321936Shselasky
666321936Shselaskyvoid osm_sr_rcv_process(IN void *context, IN void *data)
667321936Shselasky{
668321936Shselasky	osm_sa_t *sa = context;
669321936Shselasky	osm_madw_t *p_madw = data;
670321936Shselasky	ib_sa_mad_t *p_sa_mad;
671321936Shselasky	boolean_t valid;
672321936Shselasky
673321936Shselasky	OSM_LOG_ENTER(sa->p_log);
674321936Shselasky
675321936Shselasky	CL_ASSERT(p_madw);
676321936Shselasky
677321936Shselasky	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
678321936Shselasky
679321936Shselasky	CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_SERVICE_RECORD);
680321936Shselasky
681321936Shselasky	switch (p_sa_mad->method) {
682321936Shselasky	case IB_MAD_METHOD_SET:
683321936Shselasky		cl_plock_excl_acquire(sa->p_lock);
684321936Shselasky		valid = validate_sr(sa, p_madw);
685321936Shselasky		if (!valid) {
686321936Shselasky			cl_plock_release(sa->p_lock);
687321936Shselasky			OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
688321936Shselasky				"Component Mask check failed for set request\n");
689321936Shselasky			osm_sa_send_error(sa, p_madw,
690321936Shselasky					  IB_SA_MAD_STATUS_REQ_INVALID);
691321936Shselasky			goto Exit;
692321936Shselasky		}
693321936Shselasky		sr_rcv_process_set_method(sa, p_madw);
694321936Shselasky		break;
695321936Shselasky	case IB_MAD_METHOD_DELETE:
696321936Shselasky		cl_plock_excl_acquire(sa->p_lock);
697321936Shselasky		valid = validate_sr(sa, p_madw);
698321936Shselasky		if (!valid) {
699321936Shselasky			cl_plock_release(sa->p_lock);
700321936Shselasky			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
701321936Shselasky				"Component Mask check failed for delete request\n");
702321936Shselasky			osm_sa_send_error(sa, p_madw,
703321936Shselasky					  IB_SA_MAD_STATUS_REQ_INVALID);
704321936Shselasky			goto Exit;
705321936Shselasky		}
706321936Shselasky		sr_rcv_process_delete_method(sa, p_madw);
707321936Shselasky		break;
708321936Shselasky	case IB_MAD_METHOD_GET:
709321936Shselasky	case IB_MAD_METHOD_GETTABLE:
710321936Shselasky		sr_rcv_process_get_method(sa, p_madw);
711321936Shselasky		break;
712321936Shselasky	default:
713321936Shselasky		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
714321936Shselasky			"Unsupported Method (%s) for ServiceRecord request\n",
715321936Shselasky			ib_get_sa_method_str(p_sa_mad->method));
716321936Shselasky		osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
717321936Shselasky		break;
718321936Shselasky	}
719321936Shselasky
720321936ShselaskyExit:
721321936Shselasky	OSM_LOG_EXIT(sa->p_log);
722321936Shselasky}
723321936Shselasky
724321936Shselaskyvoid osm_sr_rcv_lease_cb(IN void *context)
725321936Shselasky{
726321936Shselasky	osm_sa_t *sa = context;
727321936Shselasky	cl_list_item_t *p_list_item;
728321936Shselasky	cl_list_item_t *p_next_list_item;
729321936Shselasky	osm_svcr_t *p_svcr;
730321936Shselasky	uint32_t curr_time;
731321936Shselasky	uint32_t elapsed_time;
732321936Shselasky	uint32_t trim_time = 20;	/*  maxiaml timer refresh is 20 seconds */
733321936Shselasky
734321936Shselasky	OSM_LOG_ENTER(sa->p_log);
735321936Shselasky
736321936Shselasky	cl_plock_excl_acquire(sa->p_lock);
737321936Shselasky
738321936Shselasky	p_list_item = cl_qlist_head(&sa->p_subn->sa_sr_list);
739321936Shselasky
740321936Shselasky	while (p_list_item != cl_qlist_end(&sa->p_subn->sa_sr_list)) {
741321936Shselasky		p_svcr = (osm_svcr_t *) p_list_item;
742321936Shselasky
743321936Shselasky		if (p_svcr->service_record.service_lease == 0xFFFFFFFF) {
744321936Shselasky			p_list_item = cl_qlist_next(p_list_item);
745321936Shselasky			continue;
746321936Shselasky		}
747321936Shselasky
748321936Shselasky		/* current time in seconds */
749321936Shselasky		curr_time = cl_get_time_stamp_sec();
750321936Shselasky		/* elapsed time from last modify */
751321936Shselasky		elapsed_time = curr_time - p_svcr->modified_time;
752321936Shselasky		/* but it can not be less then 1 */
753321936Shselasky		if (elapsed_time < 1)
754321936Shselasky			elapsed_time = 1;
755321936Shselasky
756321936Shselasky		if (elapsed_time < p_svcr->lease_period) {
757321936Shselasky			/*
758321936Shselasky			   Just update the service lease period
759321936Shselasky			   note: for simplicity we work with a uint32_t field
760321936Shselasky			   external to the network order lease_period of the MAD
761321936Shselasky			 */
762321936Shselasky			p_svcr->lease_period -= elapsed_time;
763321936Shselasky
764321936Shselasky			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
765321936Shselasky				"Remaining time for Service Name:%s is:0x%X\n",
766321936Shselasky				p_svcr->service_record.service_name,
767321936Shselasky				p_svcr->lease_period);
768321936Shselasky
769321936Shselasky			p_svcr->modified_time = curr_time;
770321936Shselasky
771321936Shselasky			/* Update the trim timer */
772321936Shselasky			if (trim_time > p_svcr->lease_period) {
773321936Shselasky				trim_time = p_svcr->lease_period;
774321936Shselasky				if (trim_time < 1)
775321936Shselasky					trim_time = 1;
776321936Shselasky			}
777321936Shselasky
778321936Shselasky			p_list_item = cl_qlist_next(p_list_item);
779321936Shselasky			continue;
780321936Shselasky
781321936Shselasky		} else {
782321936Shselasky			p_next_list_item = cl_qlist_next(p_list_item);
783321936Shselasky
784321936Shselasky			/* Remove the service Record */
785321936Shselasky			osm_svcr_remove_from_db(sa->p_subn, sa->p_log, p_svcr);
786321936Shselasky
787321936Shselasky			osm_svcr_delete(p_svcr);
788321936Shselasky
789321936Shselasky			p_list_item = p_next_list_item;
790321936Shselasky			continue;
791321936Shselasky		}
792321936Shselasky	}
793321936Shselasky
794321936Shselasky	/* Release the Lock */
795321936Shselasky	cl_plock_release(sa->p_lock);
796321936Shselasky
797321936Shselasky	if (trim_time != 0xFFFFFFFF) {
798321936Shselasky		cl_timer_trim(&sa->sr_timer, trim_time * 1000);	/* Convert to milli seconds */
799321936Shselasky	}
800321936Shselasky
801321936Shselasky	OSM_LOG_EXIT(sa->p_log);
802321936Shselasky}
803