From 8abbe3a42324264c9d5cc4e7c3d265b5be6d82d6 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 25 Aug 2009 14:03:52 -0700 Subject: [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 Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 48 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers/scsi/libfc/fc_rport.c') 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 @@ -1011,6 +1011,50 @@ static void fc_rport_enter_adisc(struct fc_rport_priv *rdata) kref_get(&rdata->kref); } +/** + * 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 @@ -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); -- cgit v1.2.3