diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-10-19 13:25:44 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-10-19 13:25:44 -0400 |
commit | c7b70a641df26002e8f26e2b8122fcb6a1d815a1 (patch) | |
tree | a67b6e7500320cd5499b5af928d94c56ec0a473f | |
parent | b2a205ff49b9c55d4bdda1bdb10ad19ebd646221 (diff) | |
parent | 9ae24af3669111d418242caec8dd4ebd9ba26860 (diff) |
Merge tag 'usb-4.19-final' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
I wrote:
"USB fixes for 4.19-final
Here are a small number of last-minute USB driver fixes
Included here are:
- spectre fix for usb storage gadgets
- xhci fixes
- cdc-acm fixes
- usbip fixes for reported problems
All of these have been in linux-next with no reported issues."
* tag 'usb-4.19-final' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
usb: gadget: storage: Fix Spectre v1 vulnerability
USB: fix the usbfs flag sanitization for control transfers
usb: xhci: pci: Enable Intel USB role mux on Apollo Lake platforms
usb: roles: intel_xhci: Fix Unbalanced pm_runtime_enable
cdc-acm: correct counting of UART states in serial state notification
cdc-acm: do not reset notification buffer index upon urb unlinking
cdc-acm: fix race between reset and control messaging
usb: usbip: Fix BUG: KASAN: slab-out-of-bounds in vhci_hub_control()
selftests: usbip: add wait after attach and before checking port status
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 16 | ||||
-rw-r--r-- | drivers/usb/core/devio.c | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_mass_storage.c | 3 | ||||
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 6 | ||||
-rw-r--r-- | drivers/usb/roles/intel-xhci-usb-role-switch.c | 2 | ||||
-rw-r--r-- | drivers/usb/usbip/vhci_hcd.c | 57 | ||||
-rwxr-xr-x | tools/testing/selftests/drivers/usb/usbip/usbip_test.sh | 4 |
7 files changed, 65 insertions, 27 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index bc03b0a690b4..9ede35cecb12 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -310,17 +310,17 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) | |||
310 | 310 | ||
311 | if (difference & ACM_CTRL_DSR) | 311 | if (difference & ACM_CTRL_DSR) |
312 | acm->iocount.dsr++; | 312 | acm->iocount.dsr++; |
313 | if (difference & ACM_CTRL_BRK) | ||
314 | acm->iocount.brk++; | ||
315 | if (difference & ACM_CTRL_RI) | ||
316 | acm->iocount.rng++; | ||
317 | if (difference & ACM_CTRL_DCD) | 313 | if (difference & ACM_CTRL_DCD) |
318 | acm->iocount.dcd++; | 314 | acm->iocount.dcd++; |
319 | if (difference & ACM_CTRL_FRAMING) | 315 | if (newctrl & ACM_CTRL_BRK) |
316 | acm->iocount.brk++; | ||
317 | if (newctrl & ACM_CTRL_RI) | ||
318 | acm->iocount.rng++; | ||
319 | if (newctrl & ACM_CTRL_FRAMING) | ||
320 | acm->iocount.frame++; | 320 | acm->iocount.frame++; |
321 | if (difference & ACM_CTRL_PARITY) | 321 | if (newctrl & ACM_CTRL_PARITY) |
322 | acm->iocount.parity++; | 322 | acm->iocount.parity++; |
323 | if (difference & ACM_CTRL_OVERRUN) | 323 | if (newctrl & ACM_CTRL_OVERRUN) |
324 | acm->iocount.overrun++; | 324 | acm->iocount.overrun++; |
325 | spin_unlock_irqrestore(&acm->read_lock, flags); | 325 | spin_unlock_irqrestore(&acm->read_lock, flags); |
326 | 326 | ||
@@ -355,7 +355,6 @@ static void acm_ctrl_irq(struct urb *urb) | |||
355 | case -ENOENT: | 355 | case -ENOENT: |
356 | case -ESHUTDOWN: | 356 | case -ESHUTDOWN: |
357 | /* this urb is terminated, clean up */ | 357 | /* this urb is terminated, clean up */ |
358 | acm->nb_index = 0; | ||
359 | dev_dbg(&acm->control->dev, | 358 | dev_dbg(&acm->control->dev, |
360 | "%s - urb shutting down with status: %d\n", | 359 | "%s - urb shutting down with status: %d\n", |
361 | __func__, status); | 360 | __func__, status); |
@@ -1642,6 +1641,7 @@ static int acm_pre_reset(struct usb_interface *intf) | |||
1642 | struct acm *acm = usb_get_intfdata(intf); | 1641 | struct acm *acm = usb_get_intfdata(intf); |
1643 | 1642 | ||
1644 | clear_bit(EVENT_RX_STALL, &acm->flags); | 1643 | clear_bit(EVENT_RX_STALL, &acm->flags); |
1644 | acm->nb_index = 0; /* pending control transfers are lost */ | ||
1645 | 1645 | ||
1646 | return 0; | 1646 | return 0; |
1647 | } | 1647 | } |
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 244417d0dfd1..ffccd40ea67d 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
@@ -1474,8 +1474,6 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb | |||
1474 | u = 0; | 1474 | u = 0; |
1475 | switch (uurb->type) { | 1475 | switch (uurb->type) { |
1476 | case USBDEVFS_URB_TYPE_CONTROL: | 1476 | case USBDEVFS_URB_TYPE_CONTROL: |
1477 | if (is_in) | ||
1478 | allow_short = true; | ||
1479 | if (!usb_endpoint_xfer_control(&ep->desc)) | 1477 | if (!usb_endpoint_xfer_control(&ep->desc)) |
1480 | return -EINVAL; | 1478 | return -EINVAL; |
1481 | /* min 8 byte setup packet */ | 1479 | /* min 8 byte setup packet */ |
@@ -1505,6 +1503,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb | |||
1505 | is_in = 0; | 1503 | is_in = 0; |
1506 | uurb->endpoint &= ~USB_DIR_IN; | 1504 | uurb->endpoint &= ~USB_DIR_IN; |
1507 | } | 1505 | } |
1506 | if (is_in) | ||
1507 | allow_short = true; | ||
1508 | snoop(&ps->dev->dev, "control urb: bRequestType=%02x " | 1508 | snoop(&ps->dev->dev, "control urb: bRequestType=%02x " |
1509 | "bRequest=%02x wValue=%04x " | 1509 | "bRequest=%02x wValue=%04x " |
1510 | "wIndex=%04x wLength=%04x\n", | 1510 | "wIndex=%04x wLength=%04x\n", |
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index ca8a4b53c59f..1074cb82ec17 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c | |||
@@ -221,6 +221,8 @@ | |||
221 | #include <linux/usb/gadget.h> | 221 | #include <linux/usb/gadget.h> |
222 | #include <linux/usb/composite.h> | 222 | #include <linux/usb/composite.h> |
223 | 223 | ||
224 | #include <linux/nospec.h> | ||
225 | |||
224 | #include "configfs.h" | 226 | #include "configfs.h" |
225 | 227 | ||
226 | 228 | ||
@@ -3152,6 +3154,7 @@ static struct config_group *fsg_lun_make(struct config_group *group, | |||
3152 | fsg_opts = to_fsg_opts(&group->cg_item); | 3154 | fsg_opts = to_fsg_opts(&group->cg_item); |
3153 | if (num >= FSG_MAX_LUNS) | 3155 | if (num >= FSG_MAX_LUNS) |
3154 | return ERR_PTR(-ERANGE); | 3156 | return ERR_PTR(-ERANGE); |
3157 | num = array_index_nospec(num, FSG_MAX_LUNS); | ||
3155 | 3158 | ||
3156 | mutex_lock(&fsg_opts->lock); | 3159 | mutex_lock(&fsg_opts->lock); |
3157 | if (fsg_opts->refcnt || fsg_opts->common->luns[num]) { | 3160 | if (fsg_opts->refcnt || fsg_opts->common->luns[num]) { |
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 722860eb5a91..51dd8e00c4f8 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c | |||
@@ -179,10 +179,12 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) | |||
179 | xhci->quirks |= XHCI_PME_STUCK_QUIRK; | 179 | xhci->quirks |= XHCI_PME_STUCK_QUIRK; |
180 | } | 180 | } |
181 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && | 181 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && |
182 | pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { | 182 | pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) |
183 | xhci->quirks |= XHCI_SSIC_PORT_UNUSED; | 183 | xhci->quirks |= XHCI_SSIC_PORT_UNUSED; |
184 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && | ||
185 | (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || | ||
186 | pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI)) | ||
184 | xhci->quirks |= XHCI_INTEL_USB_ROLE_SW; | 187 | xhci->quirks |= XHCI_INTEL_USB_ROLE_SW; |
185 | } | ||
186 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && | 188 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && |
187 | (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || | 189 | (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || |
188 | pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || | 190 | pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || |
diff --git a/drivers/usb/roles/intel-xhci-usb-role-switch.c b/drivers/usb/roles/intel-xhci-usb-role-switch.c index 1fb3dd0f1dfa..277de96181f9 100644 --- a/drivers/usb/roles/intel-xhci-usb-role-switch.c +++ b/drivers/usb/roles/intel-xhci-usb-role-switch.c | |||
@@ -161,6 +161,8 @@ static int intel_xhci_usb_remove(struct platform_device *pdev) | |||
161 | { | 161 | { |
162 | struct intel_xhci_usb_data *data = platform_get_drvdata(pdev); | 162 | struct intel_xhci_usb_data *data = platform_get_drvdata(pdev); |
163 | 163 | ||
164 | pm_runtime_disable(&pdev->dev); | ||
165 | |||
164 | usb_role_switch_unregister(data->role_sw); | 166 | usb_role_switch_unregister(data->role_sw); |
165 | return 0; | 167 | return 0; |
166 | } | 168 | } |
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index d11f3f8dad40..1e592ec94ba4 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c | |||
@@ -318,8 +318,9 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
318 | struct vhci_hcd *vhci_hcd; | 318 | struct vhci_hcd *vhci_hcd; |
319 | struct vhci *vhci; | 319 | struct vhci *vhci; |
320 | int retval = 0; | 320 | int retval = 0; |
321 | int rhport; | 321 | int rhport = -1; |
322 | unsigned long flags; | 322 | unsigned long flags; |
323 | bool invalid_rhport = false; | ||
323 | 324 | ||
324 | u32 prev_port_status[VHCI_HC_PORTS]; | 325 | u32 prev_port_status[VHCI_HC_PORTS]; |
325 | 326 | ||
@@ -334,9 +335,19 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
334 | usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue, | 335 | usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue, |
335 | wIndex); | 336 | wIndex); |
336 | 337 | ||
337 | if (wIndex > VHCI_HC_PORTS) | 338 | /* |
338 | pr_err("invalid port number %d\n", wIndex); | 339 | * wIndex can be 0 for some request types (typeReq). rhport is |
339 | rhport = wIndex - 1; | 340 | * in valid range when wIndex >= 1 and < VHCI_HC_PORTS. |
341 | * | ||
342 | * Reference port_status[] only with valid rhport when | ||
343 | * invalid_rhport is false. | ||
344 | */ | ||
345 | if (wIndex < 1 || wIndex > VHCI_HC_PORTS) { | ||
346 | invalid_rhport = true; | ||
347 | if (wIndex > VHCI_HC_PORTS) | ||
348 | pr_err("invalid port number %d\n", wIndex); | ||
349 | } else | ||
350 | rhport = wIndex - 1; | ||
340 | 351 | ||
341 | vhci_hcd = hcd_to_vhci_hcd(hcd); | 352 | vhci_hcd = hcd_to_vhci_hcd(hcd); |
342 | vhci = vhci_hcd->vhci; | 353 | vhci = vhci_hcd->vhci; |
@@ -345,8 +356,9 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
345 | 356 | ||
346 | /* store old status and compare now and old later */ | 357 | /* store old status and compare now and old later */ |
347 | if (usbip_dbg_flag_vhci_rh) { | 358 | if (usbip_dbg_flag_vhci_rh) { |
348 | memcpy(prev_port_status, vhci_hcd->port_status, | 359 | if (!invalid_rhport) |
349 | sizeof(prev_port_status)); | 360 | memcpy(prev_port_status, vhci_hcd->port_status, |
361 | sizeof(prev_port_status)); | ||
350 | } | 362 | } |
351 | 363 | ||
352 | switch (typeReq) { | 364 | switch (typeReq) { |
@@ -354,8 +366,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
354 | usbip_dbg_vhci_rh(" ClearHubFeature\n"); | 366 | usbip_dbg_vhci_rh(" ClearHubFeature\n"); |
355 | break; | 367 | break; |
356 | case ClearPortFeature: | 368 | case ClearPortFeature: |
357 | if (rhport < 0) | 369 | if (invalid_rhport) { |
370 | pr_err("invalid port number %d\n", wIndex); | ||
358 | goto error; | 371 | goto error; |
372 | } | ||
359 | switch (wValue) { | 373 | switch (wValue) { |
360 | case USB_PORT_FEAT_SUSPEND: | 374 | case USB_PORT_FEAT_SUSPEND: |
361 | if (hcd->speed == HCD_USB3) { | 375 | if (hcd->speed == HCD_USB3) { |
@@ -415,9 +429,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
415 | break; | 429 | break; |
416 | case GetPortStatus: | 430 | case GetPortStatus: |
417 | usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex); | 431 | usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex); |
418 | if (wIndex < 1) { | 432 | if (invalid_rhport) { |
419 | pr_err("invalid port number %d\n", wIndex); | 433 | pr_err("invalid port number %d\n", wIndex); |
420 | retval = -EPIPE; | 434 | retval = -EPIPE; |
435 | goto error; | ||
421 | } | 436 | } |
422 | 437 | ||
423 | /* we do not care about resume. */ | 438 | /* we do not care about resume. */ |
@@ -513,16 +528,20 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
513 | goto error; | 528 | goto error; |
514 | } | 529 | } |
515 | 530 | ||
516 | if (rhport < 0) | 531 | if (invalid_rhport) { |
532 | pr_err("invalid port number %d\n", wIndex); | ||
517 | goto error; | 533 | goto error; |
534 | } | ||
518 | 535 | ||
519 | vhci_hcd->port_status[rhport] |= USB_PORT_STAT_SUSPEND; | 536 | vhci_hcd->port_status[rhport] |= USB_PORT_STAT_SUSPEND; |
520 | break; | 537 | break; |
521 | case USB_PORT_FEAT_POWER: | 538 | case USB_PORT_FEAT_POWER: |
522 | usbip_dbg_vhci_rh( | 539 | usbip_dbg_vhci_rh( |
523 | " SetPortFeature: USB_PORT_FEAT_POWER\n"); | 540 | " SetPortFeature: USB_PORT_FEAT_POWER\n"); |
524 | if (rhport < 0) | 541 | if (invalid_rhport) { |
542 | pr_err("invalid port number %d\n", wIndex); | ||
525 | goto error; | 543 | goto error; |
544 | } | ||
526 | if (hcd->speed == HCD_USB3) | 545 | if (hcd->speed == HCD_USB3) |
527 | vhci_hcd->port_status[rhport] |= USB_SS_PORT_STAT_POWER; | 546 | vhci_hcd->port_status[rhport] |= USB_SS_PORT_STAT_POWER; |
528 | else | 547 | else |
@@ -531,8 +550,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
531 | case USB_PORT_FEAT_BH_PORT_RESET: | 550 | case USB_PORT_FEAT_BH_PORT_RESET: |
532 | usbip_dbg_vhci_rh( | 551 | usbip_dbg_vhci_rh( |
533 | " SetPortFeature: USB_PORT_FEAT_BH_PORT_RESET\n"); | 552 | " SetPortFeature: USB_PORT_FEAT_BH_PORT_RESET\n"); |
534 | if (rhport < 0) | 553 | if (invalid_rhport) { |
554 | pr_err("invalid port number %d\n", wIndex); | ||
535 | goto error; | 555 | goto error; |
556 | } | ||
536 | /* Applicable only for USB3.0 hub */ | 557 | /* Applicable only for USB3.0 hub */ |
537 | if (hcd->speed != HCD_USB3) { | 558 | if (hcd->speed != HCD_USB3) { |
538 | pr_err("USB_PORT_FEAT_BH_PORT_RESET req not " | 559 | pr_err("USB_PORT_FEAT_BH_PORT_RESET req not " |
@@ -543,8 +564,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
543 | case USB_PORT_FEAT_RESET: | 564 | case USB_PORT_FEAT_RESET: |
544 | usbip_dbg_vhci_rh( | 565 | usbip_dbg_vhci_rh( |
545 | " SetPortFeature: USB_PORT_FEAT_RESET\n"); | 566 | " SetPortFeature: USB_PORT_FEAT_RESET\n"); |
546 | if (rhport < 0) | 567 | if (invalid_rhport) { |
568 | pr_err("invalid port number %d\n", wIndex); | ||
547 | goto error; | 569 | goto error; |
570 | } | ||
548 | /* if it's already enabled, disable */ | 571 | /* if it's already enabled, disable */ |
549 | if (hcd->speed == HCD_USB3) { | 572 | if (hcd->speed == HCD_USB3) { |
550 | vhci_hcd->port_status[rhport] = 0; | 573 | vhci_hcd->port_status[rhport] = 0; |
@@ -565,8 +588,10 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
565 | default: | 588 | default: |
566 | usbip_dbg_vhci_rh(" SetPortFeature: default %d\n", | 589 | usbip_dbg_vhci_rh(" SetPortFeature: default %d\n", |
567 | wValue); | 590 | wValue); |
568 | if (rhport < 0) | 591 | if (invalid_rhport) { |
592 | pr_err("invalid port number %d\n", wIndex); | ||
569 | goto error; | 593 | goto error; |
594 | } | ||
570 | if (hcd->speed == HCD_USB3) { | 595 | if (hcd->speed == HCD_USB3) { |
571 | if ((vhci_hcd->port_status[rhport] & | 596 | if ((vhci_hcd->port_status[rhport] & |
572 | USB_SS_PORT_STAT_POWER) != 0) { | 597 | USB_SS_PORT_STAT_POWER) != 0) { |
@@ -608,7 +633,7 @@ error: | |||
608 | if (usbip_dbg_flag_vhci_rh) { | 633 | if (usbip_dbg_flag_vhci_rh) { |
609 | pr_debug("port %d\n", rhport); | 634 | pr_debug("port %d\n", rhport); |
610 | /* Only dump valid port status */ | 635 | /* Only dump valid port status */ |
611 | if (rhport >= 0) { | 636 | if (!invalid_rhport) { |
612 | dump_port_status_diff(prev_port_status[rhport], | 637 | dump_port_status_diff(prev_port_status[rhport], |
613 | vhci_hcd->port_status[rhport], | 638 | vhci_hcd->port_status[rhport], |
614 | hcd->speed == HCD_USB3); | 639 | hcd->speed == HCD_USB3); |
@@ -618,8 +643,10 @@ error: | |||
618 | 643 | ||
619 | spin_unlock_irqrestore(&vhci->lock, flags); | 644 | spin_unlock_irqrestore(&vhci->lock, flags); |
620 | 645 | ||
621 | if ((vhci_hcd->port_status[rhport] & PORT_C_MASK) != 0) | 646 | if (!invalid_rhport && |
647 | (vhci_hcd->port_status[rhport] & PORT_C_MASK) != 0) { | ||
622 | usb_hcd_poll_rh_status(hcd); | 648 | usb_hcd_poll_rh_status(hcd); |
649 | } | ||
623 | 650 | ||
624 | return retval; | 651 | return retval; |
625 | } | 652 | } |
diff --git a/tools/testing/selftests/drivers/usb/usbip/usbip_test.sh b/tools/testing/selftests/drivers/usb/usbip/usbip_test.sh index a72df93cf1f8..128f0ab24307 100755 --- a/tools/testing/selftests/drivers/usb/usbip/usbip_test.sh +++ b/tools/testing/selftests/drivers/usb/usbip/usbip_test.sh | |||
@@ -141,6 +141,10 @@ echo "Import devices from localhost - should work" | |||
141 | src/usbip attach -r localhost -b $busid; | 141 | src/usbip attach -r localhost -b $busid; |
142 | echo "==============================================================" | 142 | echo "==============================================================" |
143 | 143 | ||
144 | # Wait for sysfs file to be updated. Without this sleep, usbip port | ||
145 | # shows no imported devices. | ||
146 | sleep 3; | ||
147 | |||
144 | echo "List imported devices - expect to see imported devices"; | 148 | echo "List imported devices - expect to see imported devices"; |
145 | src/usbip port; | 149 | src/usbip port; |
146 | echo "==============================================================" | 150 | echo "==============================================================" |