diff options
author | Joe Eykholt <jeykholt@cisco.com> | 2009-08-25 14:03:52 -0700 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-09-10 12:08:02 -0500 |
commit | 8abbe3a42324264c9d5cc4e7c3d265b5be6d82d6 (patch) | |
tree | 72fa0c25fa4337ef0be788a76fdad37615fb7f4c /drivers/scsi/libfc/fc_rport.c | |
parent | 370c3bd05cf02afabea9cd3f2de66202d6b516dc (diff) |
[SCSI] libfc: fix handling of incoming Discover Address (ADISC) requests
The local port facility has been replying to ADISC requests without
looking to see if the remote port is logged in. This is incorrect.
An ADISC request requires PLOGI first. It should be rejected if
the sending remote port is not logged in.
This is like other incoming requests that require login, all of
which should be handled in the remote port module.
Move the ADISC request handling from fc_lport.c to fc_rport.c.
Signed-off-by: Joe Eykholt <jeykholt@cisco.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/libfc/fc_rport.c')
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index c33e2585108..03ea6748e7e 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -1012,6 +1012,50 @@ static void fc_rport_enter_adisc(struct fc_rport_priv *rdata) } /** + * fc_rport_recv_adisc_req() - Handle incoming Address Discovery (ADISC) Request + * @rdata: remote port private + * @sp: current sequence in the ADISC exchange + * @in_fp: ADISC request frame + * + * Locking Note: Called with the lport and rport locks held. + */ +static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata, + struct fc_seq *sp, struct fc_frame *in_fp) +{ + struct fc_lport *lport = rdata->local_port; + struct fc_frame *fp; + struct fc_exch *ep = fc_seq_exch(sp); + struct fc_els_adisc *adisc; + struct fc_seq_els_data rjt_data; + u32 f_ctl; + + FC_RPORT_DBG(rdata, "Received ADISC request\n"); + + adisc = fc_frame_payload_get(in_fp, sizeof(*adisc)); + if (!adisc) { + rjt_data.fp = NULL; + rjt_data.reason = ELS_RJT_PROT; + rjt_data.explan = ELS_EXPL_INV_LEN; + lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + goto drop; + } + + fp = fc_frame_alloc(lport, sizeof(*adisc)); + if (!fp) + goto drop; + fc_adisc_fill(lport, fp); + adisc = fc_frame_payload_get(fp, sizeof(*adisc)); + adisc->adisc_cmd = ELS_LS_ACC; + sp = lport->tt.seq_start_next(sp); + f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; + 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); +drop: + fc_frame_free(in_fp); +} + +/** * fc_rport_recv_els_req() - handle a validated ELS request. * @lport: Fibre Channel local port * @sp: current sequence in the PLOGI exchange @@ -1062,6 +1106,9 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, case ELS_PRLO: fc_rport_recv_prlo_req(rdata, sp, fp); break; + case ELS_ADISC: + fc_rport_recv_adisc_req(rdata, sp, fp); + break; case ELS_RRQ: els_data.fp = fp; lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); @@ -1111,6 +1158,7 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, break; case ELS_PRLI: case ELS_PRLO: + case ELS_ADISC: case ELS_RRQ: case ELS_REC: fc_rport_recv_els_req(lport, sp, fp); |