xref: /openbsd/sys/net/if_vether.c (revision dabd68ec)
1 /* $OpenBSD: if_vether.c,v 1.17 2013/03/26 13:19:26 mpi Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Theo de Raadt
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/mbuf.h>
22 #include <sys/proc.h>
23 #include <sys/socket.h>
24 #include <sys/sockio.h>
25 #include <sys/ioctl.h>
26 
27 #include <net/if.h>
28 #include <net/if_dl.h>
29 #include <net/if_media.h>
30 
31 #ifdef INET
32 #include <netinet/in.h>
33 #include <netinet/if_ether.h>
34 #endif
35 
36 void	vetherattach(int);
37 int	vetherioctl(struct ifnet *, u_long, caddr_t);
38 void	vetherstart(struct ifnet *);
39 int	vether_clone_create(struct if_clone *, int);
40 int	vether_clone_destroy(struct ifnet *);
41 int	vether_media_change(struct ifnet *);
42 void	vether_media_status(struct ifnet *, struct ifmediareq *);
43 
44 struct vether_softc {
45 	struct arpcom		sc_ac;
46 	struct ifmedia		sc_media;
47 };
48 
49 struct if_clone	vether_cloner =
50     IF_CLONE_INITIALIZER("vether", vether_clone_create, vether_clone_destroy);
51 
52 int
53 vether_media_change(struct ifnet *ifp)
54 {
55 	return (0);
56 }
57 
58 void
59 vether_media_status(struct ifnet *ifp, struct ifmediareq *imr)
60 {
61 	imr->ifm_active = IFM_ETHER | IFM_AUTO;
62 	imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
63 }
64 
65 void
66 vetherattach(int nvether)
67 {
68 	if_clone_attach(&vether_cloner);
69 }
70 
71 int
72 vether_clone_create(struct if_clone *ifc, int unit)
73 {
74 	struct ifnet		*ifp;
75 	struct vether_softc	*sc;
76 
77 	if ((sc = malloc(sizeof(*sc),
78 	    M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
79 		return (ENOMEM);
80 
81 	ifp = &sc->sc_ac.ac_if;
82 	snprintf(ifp->if_xname, sizeof ifp->if_xname, "vether%d", unit);
83 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
84 	ether_fakeaddr(ifp);
85 
86 	ifp->if_softc = sc;
87 	ifp->if_ioctl = vetherioctl;
88 	ifp->if_start = vetherstart;
89 	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
90 	IFQ_SET_READY(&ifp->if_snd);
91 
92 	ifp->if_capabilities = IFCAP_VLAN_MTU;
93 
94 	ifmedia_init(&sc->sc_media, 0, vether_media_change,
95 	    vether_media_status);
96 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
97 	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
98 
99 	if_attach(ifp);
100 	ether_ifattach(ifp);
101 	return (0);
102 }
103 
104 int
105 vether_clone_destroy(struct ifnet *ifp)
106 {
107 	struct vether_softc	*sc = ifp->if_softc;
108 
109 	ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
110 	ether_ifdetach(ifp);
111 	if_detach(ifp);
112 	free(sc, M_DEVBUF);
113 	return (0);
114 }
115 
116 /*
117  * The bridge has magically already done all the work for us,
118  * and we only need to discard the packets.
119  */
120 void
121 vetherstart(struct ifnet *ifp)
122 {
123 	struct mbuf		*m;
124 	int			 s;
125 
126 	for (;;) {
127 		s = splnet();
128 		IFQ_DEQUEUE(&ifp->if_snd, m);
129 		splx(s);
130 
131 		if (m == NULL)
132 			return;
133 		ifp->if_opackets++;
134 		m_freem(m);
135 	}
136 }
137 
138 /* ARGSUSED */
139 int
140 vetherioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
141 {
142 	struct vether_softc	*sc = (struct vether_softc *)ifp->if_softc;
143 #ifdef INET
144 	struct ifaddr		*ifa = (struct ifaddr *)data;
145 #endif
146 	struct ifreq		*ifr = (struct ifreq *)data;
147 	int			 error = 0, link_state;
148 
149 	switch (cmd) {
150 	case SIOCSIFADDR:
151 		ifp->if_flags |= IFF_UP;
152 #ifdef INET
153 		if (ifa->ifa_addr->sa_family == AF_INET)
154 			arp_ifinit(&sc->sc_ac, ifa);
155 #endif
156 		/* FALLTHROUGH */
157 
158 	case SIOCSIFFLAGS:
159 		if (ifp->if_flags & IFF_UP) {
160 			ifp->if_flags |= IFF_RUNNING;
161 			link_state = LINK_STATE_UP;
162 		} else {
163 			ifp->if_flags &= ~IFF_RUNNING;
164 			link_state = LINK_STATE_DOWN;
165 		}
166 		if (ifp->if_link_state != link_state) {
167 			ifp->if_link_state = link_state;
168 			if_link_state_change(ifp);
169 		}
170 		break;
171 
172 	case SIOCADDMULTI:
173 	case SIOCDELMULTI: {
174 		if (ifr == 0) {
175 			error = EAFNOSUPPORT;	   /* XXX */
176 			break;
177 		}
178 		error = (cmd == SIOCADDMULTI) ?
179 		    ether_addmulti(ifr, &sc->sc_ac) :
180 		    ether_delmulti(ifr, &sc->sc_ac);
181 		if (error == ENETRESET) {
182 			/*
183 			 * Multicast list has changed; set the hardware
184 			 * filter accordingly. The good thing is we do
185 			 * not have a hardware filter (:
186 			 */
187 			error = 0;
188 		}
189 		break;
190 	}
191 
192 	case SIOCGIFMEDIA:
193 	case SIOCSIFMEDIA:
194 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
195 		break;
196 
197 	default:
198 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
199 	}
200 	return (error);
201 }
202