Commit a2f6a024 authored by Joe Eykholt's avatar Joe Eykholt Committed by James Bottomley

[SCSI] libfc: recode incoming PRLI handling

Reduce indentation in fc_rport_recv_prli_req() using gotos.
Also add payload length checks.
Signed-off-by: default avatarJoe Eykholt <jeykholt@cisco.com>
Signed-off-by: default avatarRobert Love <robert.w.love@intel.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent fc193172
...@@ -1442,136 +1442,115 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, ...@@ -1442,136 +1442,115 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
struct fc_els_spp *spp; /* response spp */ struct fc_els_spp *spp; /* response spp */
unsigned int len; unsigned int len;
unsigned int plen; unsigned int plen;
enum fc_els_rjt_reason reason = ELS_RJT_UNAB;
enum fc_els_rjt_explan explan = ELS_EXPL_NONE;
enum fc_els_spp_resp resp; enum fc_els_spp_resp resp;
struct fc_seq_els_data rjt_data; struct fc_seq_els_data rjt_data;
u32 f_ctl; u32 f_ctl;
u32 fcp_parm; u32 fcp_parm;
u32 roles = FC_RPORT_ROLE_UNKNOWN; u32 roles = FC_RPORT_ROLE_UNKNOWN;
rjt_data.fp = NULL;
rjt_data.fp = NULL;
fh = fc_frame_header_get(rx_fp); fh = fc_frame_header_get(rx_fp);
FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n", FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
fc_rport_state(rdata)); fc_rport_state(rdata));
switch (rdata->rp_state) {
case RPORT_ST_PRLI:
case RPORT_ST_RTV:
case RPORT_ST_READY:
case RPORT_ST_ADISC:
reason = ELS_RJT_NONE;
break;
default:
fc_frame_free(rx_fp);
return;
break;
}
len = fr_len(rx_fp) - sizeof(*fh); len = fr_len(rx_fp) - sizeof(*fh);
pp = fc_frame_payload_get(rx_fp, sizeof(*pp)); pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
if (pp == NULL) { if (!pp)
reason = ELS_RJT_PROT; goto reject_len;
explan = ELS_EXPL_INV_LEN; plen = ntohs(pp->prli.prli_len);
} else { if ((plen % 4) != 0 || plen > len || plen < 16)
plen = ntohs(pp->prli.prli_len); goto reject_len;
if ((plen % 4) != 0 || plen > len) { if (plen < len)
reason = ELS_RJT_PROT; len = plen;
explan = ELS_EXPL_INV_LEN; plen = pp->prli.prli_spp_len;
} else if (plen < len) { if ((plen % 4) != 0 || plen < sizeof(*spp) ||
len = plen; plen > len || len < sizeof(*pp) || plen < 12)
} goto reject_len;
plen = pp->prli.prli_spp_len; rspp = &pp->spp;
if ((plen % 4) != 0 || plen < sizeof(*spp) ||
plen > len || len < sizeof(*pp)) { fp = fc_frame_alloc(lport, len);
reason = ELS_RJT_PROT; if (!fp) {
explan = ELS_EXPL_INV_LEN; rjt_data.reason = ELS_RJT_UNAB;
} rjt_data.explan = ELS_EXPL_INSUF_RES;
rspp = &pp->spp; goto reject;
} }
if (reason != ELS_RJT_NONE || sp = lport->tt.seq_start_next(sp);
(fp = fc_frame_alloc(lport, len)) == NULL) { WARN_ON(!sp);
rjt_data.reason = reason; pp = fc_frame_payload_get(fp, len);
rjt_data.explan = explan; WARN_ON(!pp);
lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); memset(pp, 0, len);
} else { pp->prli.prli_cmd = ELS_LS_ACC;
sp = lport->tt.seq_start_next(sp); pp->prli.prli_spp_len = plen;
WARN_ON(!sp); pp->prli.prli_len = htons(len);
pp = fc_frame_payload_get(fp, len); len -= sizeof(struct fc_els_prli);
WARN_ON(!pp);
memset(pp, 0, len);
pp->prli.prli_cmd = ELS_LS_ACC;
pp->prli.prli_spp_len = plen;
pp->prli.prli_len = htons(len);
len -= sizeof(struct fc_els_prli);
/* reinitialize remote port roles */
rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
/*
* Go through all the service parameter pages and build
* response. If plen indicates longer SPP than standard,
* use that. The entire response has been pre-cleared above.
*/
spp = &pp->spp;
while (len >= plen) {
spp->spp_type = rspp->spp_type;
spp->spp_type_ext = rspp->spp_type_ext;
spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
resp = FC_SPP_RESP_ACK;
if (rspp->spp_flags & FC_SPP_RPA_VAL)
resp = FC_SPP_RESP_NO_PA;
switch (rspp->spp_type) {
case 0: /* common to all FC-4 types */
break;
case FC_TYPE_FCP:
fcp_parm = ntohl(rspp->spp_params);
if (fcp_parm & FCP_SPPF_RETRY)
rdata->flags |= FC_RP_FLAGS_RETRY;
rdata->supported_classes = FC_COS_CLASS3;
if (fcp_parm & FCP_SPPF_INIT_FCN)
roles |= FC_RPORT_ROLE_FCP_INITIATOR;
if (fcp_parm & FCP_SPPF_TARG_FCN)
roles |= FC_RPORT_ROLE_FCP_TARGET;
rdata->ids.roles = roles;
spp->spp_params =
htonl(lport->service_params);
break;
default:
resp = FC_SPP_RESP_INVL;
break;
}
spp->spp_flags |= resp;
len -= plen;
rspp = (struct fc_els_spp *)((char *)rspp + plen);
spp = (struct fc_els_spp *)((char *)spp + plen);
}
/* /* reinitialize remote port roles */
* Send LS_ACC. If this fails, the originator should retry. rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
*/
f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
ep = fc_seq_exch(sp);
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
FC_TYPE_ELS, f_ctl, 0);
lport->tt.seq_send(lport, sp, fp);
/* /*
* Get lock and re-check state. * Go through all the service parameter pages and build
*/ * response. If plen indicates longer SPP than standard,
switch (rdata->rp_state) { * use that. The entire response has been pre-cleared above.
case RPORT_ST_PRLI: */
fc_rport_enter_ready(rdata); spp = &pp->spp;
while (len >= plen) {
spp->spp_type = rspp->spp_type;
spp->spp_type_ext = rspp->spp_type_ext;
spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
resp = FC_SPP_RESP_ACK;
switch (rspp->spp_type) {
case 0: /* common to all FC-4 types */
break; break;
case RPORT_ST_READY: case FC_TYPE_FCP:
case RPORT_ST_ADISC: fcp_parm = ntohl(rspp->spp_params);
if (fcp_parm & FCP_SPPF_RETRY)
rdata->flags |= FC_RP_FLAGS_RETRY;
rdata->supported_classes = FC_COS_CLASS3;
if (fcp_parm & FCP_SPPF_INIT_FCN)
roles |= FC_RPORT_ROLE_FCP_INITIATOR;
if (fcp_parm & FCP_SPPF_TARG_FCN)
roles |= FC_RPORT_ROLE_FCP_TARGET;
rdata->ids.roles = roles;
spp->spp_params = htonl(lport->service_params);
break; break;
default: default:
resp = FC_SPP_RESP_INVL;
break; break;
} }
spp->spp_flags |= resp;
len -= plen;
rspp = (struct fc_els_spp *)((char *)rspp + plen);
spp = (struct fc_els_spp *)((char *)spp + plen);
}
/*
* Send LS_ACC. If this fails, the originator should retry.
*/
f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
ep = fc_seq_exch(sp);
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
FC_TYPE_ELS, f_ctl, 0);
lport->tt.seq_send(lport, sp, fp);
switch (rdata->rp_state) {
case RPORT_ST_PRLI:
fc_rport_enter_ready(rdata);
break;
default:
break;
} }
goto drop;
reject_len:
rjt_data.reason = ELS_RJT_PROT;
rjt_data.explan = ELS_EXPL_INV_LEN;
reject:
lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
drop:
fc_frame_free(rx_fp); fc_frame_free(rx_fp);
} }
......
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