Commit 8c3dca34 authored by Ursula Braun's avatar Ursula Braun Committed by David S. Miller

net/smc: build and send V2 CLC proposal

The new format of an SMCD V2 CLC proposal is introduced, and
building and checking of SMCD V2 CLC proposals is adapted
accordingly.
Signed-off-by: default avatarUrsula Braun <ubraun@linux.ibm.com>
Signed-off-by: default avatarKarsten Graul <kgraul@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d70bf4f7
...@@ -1301,7 +1301,7 @@ static void smc_find_ism_device_serv(struct smc_sock *new_smc, ...@@ -1301,7 +1301,7 @@ static void smc_find_ism_device_serv(struct smc_sock *new_smc,
if (!smcd_indicated(pclc->hdr.typev1)) if (!smcd_indicated(pclc->hdr.typev1))
goto not_found; goto not_found;
ini->is_smcd = true; /* prepare ISM check */ ini->is_smcd = true; /* prepare ISM check */
ini->ism_peer_gid[0] = pclc_smcd->gid; ini->ism_peer_gid[0] = ntohll(pclc_smcd->ism.gid);
if (smc_find_ism_device(new_smc, ini)) if (smc_find_ism_device(new_smc, ini))
goto not_found; goto not_found;
if (!smc_listen_ism_init(new_smc, ini)) if (!smc_listen_ism_init(new_smc, ini))
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#define SMC_V1 1 /* SMC version V1 */ #define SMC_V1 1 /* SMC version V1 */
#define SMC_V2 2 /* SMC version V2 */ #define SMC_V2 2 /* SMC version V2 */
#define SMC_RELEASE 0
#define SMCPROTO_SMC 0 /* SMC protocol, IPv4 */ #define SMCPROTO_SMC 0 /* SMC protocol, IPv4 */
#define SMCPROTO_SMC6 1 /* SMC protocol, IPv6 */ #define SMCPROTO_SMC6 1 /* SMC protocol, IPv6 */
...@@ -28,6 +29,8 @@ ...@@ -28,6 +29,8 @@
* devices * devices
*/ */
#define SMC_MAX_EID_LEN 32
extern struct proto smc_proto; extern struct proto smc_proto;
extern struct proto smc_proto6; extern struct proto smc_proto6;
...@@ -251,6 +254,9 @@ extern struct workqueue_struct *smc_close_wq; /* wq for close work */ ...@@ -251,6 +254,9 @@ extern struct workqueue_struct *smc_close_wq; /* wq for close work */
extern u8 local_systemid[SMC_SYSTEMID_LEN]; /* unique system identifier */ extern u8 local_systemid[SMC_SYSTEMID_LEN]; /* unique system identifier */
#define ntohll(x) be64_to_cpu(x)
#define htonll(x) cpu_to_be64(x)
/* convert an u32 value into network byte order, store it into a 3 byte field */ /* convert an u32 value into network byte order, store it into a 3 byte field */
static inline void hton24(u8 *net, u32 host) static inline void hton24(u8 *net, u32 host)
{ {
......
...@@ -34,12 +34,52 @@ static const char SMC_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xd9'}; ...@@ -34,12 +34,52 @@ static const char SMC_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xd9'};
/* eye catcher "SMCD" EBCDIC for CLC messages */ /* eye catcher "SMCD" EBCDIC for CLC messages */
static const char SMCD_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xc4'}; static const char SMCD_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xc4'};
/* check arriving CLC proposal */
static bool smc_clc_msg_prop_valid(struct smc_clc_msg_proposal *pclc)
{
struct smc_clc_msg_proposal_prefix *pclc_prfx;
struct smc_clc_smcd_v2_extension *smcd_v2_ext;
struct smc_clc_msg_hdr *hdr = &pclc->hdr;
struct smc_clc_v2_extension *v2_ext;
v2_ext = smc_get_clc_v2_ext(pclc);
pclc_prfx = smc_clc_proposal_get_prefix(pclc);
if (hdr->version == SMC_V1) {
if (hdr->typev1 == SMC_TYPE_N)
return false;
if (ntohs(hdr->length) !=
sizeof(*pclc) + ntohs(pclc->iparea_offset) +
sizeof(*pclc_prfx) +
pclc_prfx->ipv6_prefixes_cnt *
sizeof(struct smc_clc_ipv6_prefix) +
sizeof(struct smc_clc_msg_trail))
return false;
} else {
if (ntohs(hdr->length) !=
sizeof(*pclc) +
sizeof(struct smc_clc_msg_smcd) +
(hdr->typev1 != SMC_TYPE_N ?
sizeof(*pclc_prfx) +
pclc_prfx->ipv6_prefixes_cnt *
sizeof(struct smc_clc_ipv6_prefix) : 0) +
(hdr->typev2 != SMC_TYPE_N ?
sizeof(*v2_ext) +
v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN : 0) +
(smcd_indicated(hdr->typev2) ?
sizeof(*smcd_v2_ext) + v2_ext->hdr.ism_gid_cnt *
sizeof(struct smc_clc_smcd_gid_chid) :
0) +
sizeof(struct smc_clc_msg_trail))
return false;
}
return true;
}
/* check if received message has a correct header length and contains valid /* check if received message has a correct header length and contains valid
* heading and trailing eyecatchers * heading and trailing eyecatchers
*/ */
static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl) static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl)
{ {
struct smc_clc_msg_proposal_prefix *pclc_prfx;
struct smc_clc_msg_accept_confirm *clc; struct smc_clc_msg_accept_confirm *clc;
struct smc_clc_msg_proposal *pclc; struct smc_clc_msg_proposal *pclc;
struct smc_clc_msg_decline *dclc; struct smc_clc_msg_decline *dclc;
...@@ -51,13 +91,7 @@ static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl) ...@@ -51,13 +91,7 @@ static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl)
switch (clcm->type) { switch (clcm->type) {
case SMC_CLC_PROPOSAL: case SMC_CLC_PROPOSAL:
pclc = (struct smc_clc_msg_proposal *)clcm; pclc = (struct smc_clc_msg_proposal *)clcm;
pclc_prfx = smc_clc_proposal_get_prefix(pclc); if (!smc_clc_msg_prop_valid(pclc))
if (ntohs(pclc->hdr.length) <
sizeof(*pclc) + ntohs(pclc->iparea_offset) +
sizeof(*pclc_prfx) +
pclc_prfx->ipv6_prefixes_cnt *
sizeof(struct smc_clc_ipv6_prefix) +
sizeof(*trl))
return false; return false;
trl = (struct smc_clc_msg_trail *) trl = (struct smc_clc_msg_trail *)
((u8 *)pclc + ntohs(pclc->hdr.length) - sizeof(*trl)); ((u8 *)pclc + ntohs(pclc->hdr.length) - sizeof(*trl));
...@@ -327,9 +361,6 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen, ...@@ -327,9 +361,6 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
goto out; goto out;
} }
if (clcm->type == SMC_CLC_PROPOSAL && clcm->typev1 == SMC_TYPE_N)
reason_code = SMC_CLC_DECL_VERSMISMAT; /* just V2 offered */
/* receive the complete CLC message */ /* receive the complete CLC message */
memset(&msg, 0, sizeof(struct msghdr)); memset(&msg, 0, sizeof(struct msghdr));
if (datlen > buflen) { if (datlen > buflen) {
...@@ -412,15 +443,18 @@ int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info) ...@@ -412,15 +443,18 @@ int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info)
/* send CLC PROPOSAL message across internal TCP socket */ /* send CLC PROPOSAL message across internal TCP socket */
int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
{ {
struct smc_clc_smcd_v2_extension *smcd_v2_ext;
struct smc_clc_msg_proposal_prefix *pclc_prfx; struct smc_clc_msg_proposal_prefix *pclc_prfx;
struct smc_clc_msg_proposal *pclc_base; struct smc_clc_msg_proposal *pclc_base;
struct smc_clc_smcd_gid_chid *gidchids;
struct smc_clc_msg_proposal_area *pclc; struct smc_clc_msg_proposal_area *pclc;
struct smc_clc_ipv6_prefix *ipv6_prfx; struct smc_clc_ipv6_prefix *ipv6_prfx;
struct smc_clc_v2_extension *v2_ext;
struct smc_clc_msg_smcd *pclc_smcd; struct smc_clc_msg_smcd *pclc_smcd;
struct smc_clc_msg_trail *trl; struct smc_clc_msg_trail *trl;
int len, i, plen, rc; int len, i, plen, rc;
int reason_code = 0; int reason_code = 0;
struct kvec vec[5]; struct kvec vec[8];
struct msghdr msg; struct msghdr msg;
pclc = kzalloc(sizeof(*pclc), GFP_KERNEL); pclc = kzalloc(sizeof(*pclc), GFP_KERNEL);
...@@ -431,24 +465,37 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -431,24 +465,37 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
pclc_smcd = &pclc->pclc_smcd; pclc_smcd = &pclc->pclc_smcd;
pclc_prfx = &pclc->pclc_prfx; pclc_prfx = &pclc->pclc_prfx;
ipv6_prfx = pclc->pclc_prfx_ipv6; ipv6_prfx = pclc->pclc_prfx_ipv6;
v2_ext = &pclc->pclc_v2_ext;
smcd_v2_ext = &pclc->pclc_smcd_v2_ext;
gidchids = pclc->pclc_gidchids;
trl = &pclc->pclc_trl; trl = &pclc->pclc_trl;
pclc_base->hdr.version = SMC_V2;
pclc_base->hdr.typev1 = ini->smc_type_v1;
pclc_base->hdr.typev2 = ini->smc_type_v2;
plen = sizeof(*pclc_base) + sizeof(*pclc_smcd) + sizeof(*trl);
/* retrieve ip prefixes for CLC proposal msg */ /* retrieve ip prefixes for CLC proposal msg */
if (ini->smc_type_v1 != SMC_TYPE_N) {
rc = smc_clc_prfx_set(smc->clcsock, pclc_prfx, ipv6_prfx); rc = smc_clc_prfx_set(smc->clcsock, pclc_prfx, ipv6_prfx);
if (rc) { if (rc) {
if (ini->smc_type_v2 == SMC_TYPE_N) {
kfree(pclc); kfree(pclc);
return SMC_CLC_DECL_CNFERR; /* configuration error */ return SMC_CLC_DECL_CNFERR;
}
pclc_base->hdr.typev1 = SMC_TYPE_N;
} else {
pclc_base->iparea_offset = htons(sizeof(*pclc_smcd));
plen += sizeof(*pclc_prfx) +
pclc_prfx->ipv6_prefixes_cnt *
sizeof(ipv6_prfx[0]);
}
} }
/* send SMC Proposal CLC message */ /* build SMC Proposal CLC message */
plen = sizeof(*pclc_base) + sizeof(*pclc_prfx) +
(pclc_prfx->ipv6_prefixes_cnt * sizeof(ipv6_prfx[0])) +
sizeof(*trl);
memcpy(pclc_base->hdr.eyecatcher, SMC_EYECATCHER, memcpy(pclc_base->hdr.eyecatcher, SMC_EYECATCHER,
sizeof(SMC_EYECATCHER)); sizeof(SMC_EYECATCHER));
pclc_base->hdr.type = SMC_CLC_PROPOSAL; pclc_base->hdr.type = SMC_CLC_PROPOSAL;
pclc_base->hdr.version = SMC_V1; /* SMC version */
pclc_base->hdr.typev1 = ini->smc_type_v1;
if (smcr_indicated(ini->smc_type_v1)) { if (smcr_indicated(ini->smc_type_v1)) {
/* add SMC-R specifics */ /* add SMC-R specifics */
memcpy(pclc_base->lcl.id_for_peer, local_systemid, memcpy(pclc_base->lcl.id_for_peer, local_systemid,
...@@ -456,25 +503,65 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -456,25 +503,65 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
memcpy(pclc_base->lcl.gid, ini->ib_gid, SMC_GID_SIZE); memcpy(pclc_base->lcl.gid, ini->ib_gid, SMC_GID_SIZE);
memcpy(pclc_base->lcl.mac, &ini->ib_dev->mac[ini->ib_port - 1], memcpy(pclc_base->lcl.mac, &ini->ib_dev->mac[ini->ib_port - 1],
ETH_ALEN); ETH_ALEN);
pclc_base->iparea_offset = htons(0);
} }
if (smcd_indicated(ini->smc_type_v1)) { if (smcd_indicated(ini->smc_type_v1)) {
/* add SMC-D specifics */ /* add SMC-D specifics */
plen += sizeof(*pclc_smcd); if (ini->ism_dev[0]) {
pclc_base->iparea_offset = htons(sizeof(*pclc_smcd)); pclc_smcd->ism.gid = htonll(ini->ism_dev[0]->local_gid);
pclc_smcd->gid = ini->ism_dev[0]->local_gid; pclc_smcd->ism.chid =
htons(smc_ism_get_chid(ini->ism_dev[0]));
} }
pclc_base->hdr.length = htons(plen); }
if (ini->smc_type_v2 == SMC_TYPE_N) {
pclc_smcd->v2_ext_offset = 0;
} else {
u16 v2_ext_offset;
u8 *eid = NULL;
v2_ext_offset = sizeof(*pclc_smcd) -
offsetofend(struct smc_clc_msg_smcd, v2_ext_offset);
if (ini->smc_type_v1 != SMC_TYPE_N)
v2_ext_offset += sizeof(*pclc_prfx) +
pclc_prfx->ipv6_prefixes_cnt *
sizeof(ipv6_prfx[0]);
pclc_smcd->v2_ext_offset = htons(v2_ext_offset);
v2_ext->hdr.eid_cnt = 0;
v2_ext->hdr.ism_gid_cnt = ini->ism_offered_cnt;
v2_ext->hdr.flag.release = SMC_RELEASE;
v2_ext->hdr.flag.seid = 1;
v2_ext->hdr.smcd_v2_ext_offset = htons(sizeof(*v2_ext) -
offsetofend(struct smc_clnt_opts_area_hdr,
smcd_v2_ext_offset) +
v2_ext->hdr.eid_cnt * SMC_MAX_EID_LEN);
if (ini->ism_dev[0])
smc_ism_get_system_eid(ini->ism_dev[0], &eid);
else
smc_ism_get_system_eid(ini->ism_dev[1], &eid);
if (eid)
memcpy(smcd_v2_ext->system_eid, eid, SMC_MAX_EID_LEN);
plen += sizeof(*v2_ext) + sizeof(*smcd_v2_ext);
if (ini->ism_offered_cnt) {
for (i = 1; i <= ini->ism_offered_cnt; i++) {
gidchids[i - 1].gid =
htonll(ini->ism_dev[i]->local_gid);
gidchids[i - 1].chid =
htons(smc_ism_get_chid(ini->ism_dev[i]));
}
plen += ini->ism_offered_cnt *
sizeof(struct smc_clc_smcd_gid_chid);
}
}
pclc_base->hdr.length = htons(plen);
memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)); memcpy(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
/* send SMC Proposal CLC message */
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
i = 0; i = 0;
vec[i].iov_base = pclc_base; vec[i].iov_base = pclc_base;
vec[i++].iov_len = sizeof(*pclc_base); vec[i++].iov_len = sizeof(*pclc_base);
if (smcd_indicated(ini->smc_type_v1)) {
vec[i].iov_base = pclc_smcd; vec[i].iov_base = pclc_smcd;
vec[i++].iov_len = sizeof(*pclc_smcd); vec[i++].iov_len = sizeof(*pclc_smcd);
} if (ini->smc_type_v1 != SMC_TYPE_N) {
vec[i].iov_base = pclc_prfx; vec[i].iov_base = pclc_prfx;
vec[i++].iov_len = sizeof(*pclc_prfx); vec[i++].iov_len = sizeof(*pclc_prfx);
if (pclc_prfx->ipv6_prefixes_cnt > 0) { if (pclc_prfx->ipv6_prefixes_cnt > 0) {
...@@ -482,6 +569,18 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -482,6 +569,18 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
vec[i++].iov_len = pclc_prfx->ipv6_prefixes_cnt * vec[i++].iov_len = pclc_prfx->ipv6_prefixes_cnt *
sizeof(ipv6_prfx[0]); sizeof(ipv6_prfx[0]);
} }
}
if (ini->smc_type_v2 != SMC_TYPE_N) {
vec[i].iov_base = v2_ext;
vec[i++].iov_len = sizeof(*v2_ext);
vec[i].iov_base = smcd_v2_ext;
vec[i++].iov_len = sizeof(*smcd_v2_ext);
if (ini->ism_offered_cnt) {
vec[i].iov_base = gidchids;
vec[i++].iov_len = ini->ism_offered_cnt *
sizeof(struct smc_clc_smcd_gid_chid);
}
}
vec[i].iov_base = trl; vec[i].iov_base = trl;
vec[i++].iov_len = sizeof(*trl); vec[i++].iov_len = sizeof(*trl);
/* due to the few bytes needed for clc-handshake this cannot block */ /* due to the few bytes needed for clc-handshake this cannot block */
......
...@@ -81,8 +81,6 @@ struct smc_clc_msg_local { /* header2 of clc messages */ ...@@ -81,8 +81,6 @@ struct smc_clc_msg_local { /* header2 of clc messages */
u8 mac[6]; /* mac of ib_device port */ u8 mac[6]; /* mac of ib_device port */
}; };
#define SMC_CLC_MAX_V6_PREFIX 8
/* Struct would be 4 byte aligned, but it is used in an array that is sent /* Struct would be 4 byte aligned, but it is used in an array that is sent
* to peers and must conform to RFC7609, hence we need to use packed here. * to peers and must conform to RFC7609, hence we need to use packed here.
*/ */
...@@ -91,6 +89,44 @@ struct smc_clc_ipv6_prefix { ...@@ -91,6 +89,44 @@ struct smc_clc_ipv6_prefix {
u8 prefix_len; u8 prefix_len;
} __packed; /* format defined in RFC7609 */ } __packed; /* format defined in RFC7609 */
#if defined(__BIG_ENDIAN_BITFIELD)
struct smc_clc_v2_flag {
u8 release : 4,
rsvd : 3,
seid : 1;
};
#elif defined(__LITTLE_ENDIAN_BITFIELD)
struct smc_clc_v2_flag {
u8 seid : 1,
rsvd : 3,
release : 4;
};
#endif
struct smc_clnt_opts_area_hdr {
u8 eid_cnt; /* number of user defined EIDs */
u8 ism_gid_cnt; /* number of ISMv2 GIDs */
u8 reserved1;
struct smc_clc_v2_flag flag;
u8 reserved2[2];
__be16 smcd_v2_ext_offset; /* SMC-Dv2 Extension Offset */
};
struct smc_clc_smcd_gid_chid {
__be64 gid; /* ISM GID */
__be16 chid; /* ISMv2 CHID */
} __packed; /* format defined in
* IBM Shared Memory Communications Version 2
* (https://www.ibm.com/support/pages/node/6326337)
*/
struct smc_clc_v2_extension {
struct smc_clnt_opts_area_hdr hdr;
u8 roce[16]; /* RoCEv2 GID */
u8 reserved[16];
u8 user_eids[0][SMC_MAX_EID_LEN];
};
struct smc_clc_msg_proposal_prefix { /* prefix part of clc proposal message*/ struct smc_clc_msg_proposal_prefix { /* prefix part of clc proposal message*/
__be32 outgoing_subnet; /* subnet mask */ __be32 outgoing_subnet; /* subnet mask */
u8 prefix_len; /* number of significant bits in mask */ u8 prefix_len; /* number of significant bits in mask */
...@@ -99,8 +135,15 @@ struct smc_clc_msg_proposal_prefix { /* prefix part of clc proposal message*/ ...@@ -99,8 +135,15 @@ struct smc_clc_msg_proposal_prefix { /* prefix part of clc proposal message*/
} __aligned(4); } __aligned(4);
struct smc_clc_msg_smcd { /* SMC-D GID information */ struct smc_clc_msg_smcd { /* SMC-D GID information */
u64 gid; /* ISM GID of requestor */ struct smc_clc_smcd_gid_chid ism; /* ISM native GID+CHID of requestor */
u8 res[32]; __be16 v2_ext_offset; /* SMC Version 2 Extension Offset */
u8 reserved[28];
};
struct smc_clc_smcd_v2_extension {
u8 system_eid[SMC_MAX_EID_LEN];
u8 reserved[16];
struct smc_clc_smcd_gid_chid gidchid[0];
}; };
struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */ struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */
...@@ -109,11 +152,16 @@ struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */ ...@@ -109,11 +152,16 @@ struct smc_clc_msg_proposal { /* clc proposal message sent by Linux */
__be16 iparea_offset; /* offset to IP address information area */ __be16 iparea_offset; /* offset to IP address information area */
} __aligned(4); } __aligned(4);
#define SMC_CLC_MAX_V6_PREFIX 8
struct smc_clc_msg_proposal_area { struct smc_clc_msg_proposal_area {
struct smc_clc_msg_proposal pclc_base; struct smc_clc_msg_proposal pclc_base;
struct smc_clc_msg_smcd pclc_smcd; struct smc_clc_msg_smcd pclc_smcd;
struct smc_clc_msg_proposal_prefix pclc_prfx; struct smc_clc_msg_proposal_prefix pclc_prfx;
struct smc_clc_ipv6_prefix pclc_prfx_ipv6[SMC_CLC_MAX_V6_PREFIX]; struct smc_clc_ipv6_prefix pclc_prfx_ipv6[SMC_CLC_MAX_V6_PREFIX];
struct smc_clc_v2_extension pclc_v2_ext;
struct smc_clc_smcd_v2_extension pclc_smcd_v2_ext;
struct smc_clc_smcd_gid_chid pclc_gidchids[SMC_MAX_ISM_DEVS];
struct smc_clc_msg_trail pclc_trl; struct smc_clc_msg_trail pclc_trl;
}; };
...@@ -190,13 +238,28 @@ static inline bool smcd_indicated(int smc_type) ...@@ -190,13 +238,28 @@ static inline bool smcd_indicated(int smc_type)
static inline struct smc_clc_msg_smcd * static inline struct smc_clc_msg_smcd *
smc_get_clc_msg_smcd(struct smc_clc_msg_proposal *prop) smc_get_clc_msg_smcd(struct smc_clc_msg_proposal *prop)
{ {
if (smcd_indicated(prop->hdr.type) && if (smcd_indicated(prop->hdr.typev1) &&
ntohs(prop->iparea_offset) != sizeof(struct smc_clc_msg_smcd)) ntohs(prop->iparea_offset) != sizeof(struct smc_clc_msg_smcd))
return NULL; return NULL;
return (struct smc_clc_msg_smcd *)(prop + 1); return (struct smc_clc_msg_smcd *)(prop + 1);
} }
static inline struct smc_clc_v2_extension *
smc_get_clc_v2_ext(struct smc_clc_msg_proposal *prop)
{
struct smc_clc_msg_smcd *prop_smcd = smc_get_clc_msg_smcd(prop);
if (!prop_smcd || !ntohs(prop_smcd->v2_ext_offset))
return NULL;
return (struct smc_clc_v2_extension *)
((u8 *)prop_smcd +
offsetof(struct smc_clc_msg_smcd, v2_ext_offset) +
sizeof(prop_smcd->v2_ext_offset) +
ntohs(prop_smcd->v2_ext_offset));
}
struct smcd_dev; struct smcd_dev;
struct smc_init_info; struct smc_init_info;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment