* the cdevsw write interface - an atomic write is a packet - or else! */
| 1838 | * the cdevsw write interface - an atomic write is a packet - or else! |
| 1839 | */ |
| 1840 | static int |
| 1841 | tunwrite(struct cdev *dev, struct uio *uio, int flag) |
| 1842 | { |
| 1843 | struct virtio_net_hdr_mrg_rxbuf vhdr; |
| 1844 | struct tuntap_softc *tp; |
| 1845 | struct ifnet *ifp; |
| 1846 | struct mbuf *m; |
| 1847 | uint32_t mru; |
| 1848 | int align, vhdrlen, error; |
| 1849 | bool l2tun; |
| 1850 | |
| 1851 | tp = dev->si_drv1; |
| 1852 | ifp = TUN2IFP(tp); |
| 1853 | TUNDEBUG(ifp, "tunwrite\n"); |
| 1854 | if ((ifp->if_flags & IFF_UP) != IFF_UP) |
| 1855 | /* ignore silently */ |
| 1856 | return (0); |
| 1857 | |
| 1858 | if (uio->uio_resid == 0) |
| 1859 | return (0); |
| 1860 | |
| 1861 | l2tun = (tp->tun_flags & TUN_L2) != 0; |
| 1862 | mru = l2tun ? TAPMRU : TUNMRU; |
| 1863 | vhdrlen = tp->tun_vhdrlen; |
| 1864 | align = 0; |
| 1865 | if (l2tun) { |
| 1866 | align = ETHER_ALIGN; |
| 1867 | mru += vhdrlen; |
| 1868 | } else if ((tp->tun_flags & TUN_IFHEAD) != 0) |
| 1869 | mru += sizeof(uint32_t); /* family */ |
| 1870 | if (uio->uio_resid < 0 || uio->uio_resid > mru) { |
| 1871 | TUNDEBUG(ifp, "len=%zd!\n", uio->uio_resid); |
| 1872 | return (EIO); |
| 1873 | } |
| 1874 | |
| 1875 | if (vhdrlen > 0) { |
| 1876 | error = uiomove(&vhdr, vhdrlen, uio); |
| 1877 | if (error != 0) |
| 1878 | return (error); |
| 1879 | TUNDEBUG(ifp, "txvhdr: f %u, gt %u, hl %u, " |
| 1880 | "gs %u, cs %u, co %u\n", vhdr.hdr.flags, |
| 1881 | vhdr.hdr.gso_type, vhdr.hdr.hdr_len, |
| 1882 | vhdr.hdr.gso_size, vhdr.hdr.csum_start, |
| 1883 | vhdr.hdr.csum_offset); |
| 1884 | } |
| 1885 | |
| 1886 | if ((m = m_uiotombuf(uio, M_NOWAIT, 0, align, M_PKTHDR)) == NULL) { |
| 1887 | if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); |
| 1888 | return (ENOBUFS); |
| 1889 | } |
| 1890 | |
| 1891 | m->m_pkthdr.rcvif = ifp; |
| 1892 | #ifdef MAC |
| 1893 | mac_ifnet_create_mbuf(ifp, m); |
| 1894 | #endif |
| 1895 | |
| 1896 | if (l2tun) |
| 1897 | return (tunwrite_l2(tp, m, vhdrlen > 0 ? &vhdr : NULL)); |
nothing calls this directly
no test coverage detected