1 1.8 bouyer /* $NetBSD: can_pcb.c,v 1.8 2019/07/20 15:34:41 bouyer Exp $ */ 2 1.2 bouyer 3 1.2 bouyer /*- 4 1.2 bouyer * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc. 5 1.2 bouyer * All rights reserved. 6 1.2 bouyer * 7 1.2 bouyer * This code is derived from software contributed to The NetBSD Foundation 8 1.2 bouyer * by Robert Swindells and Manuel Bouyer 9 1.2 bouyer * 10 1.2 bouyer * Redistribution and use in source and binary forms, with or without 11 1.2 bouyer * modification, are permitted provided that the following conditions 12 1.2 bouyer * are met: 13 1.2 bouyer * 1. Redistributions of source code must retain the above copyright 14 1.2 bouyer * notice, this list of conditions and the following disclaimer. 15 1.2 bouyer * 2. Redistributions in binary form must reproduce the above copyright 16 1.2 bouyer * notice, this list of conditions and the following disclaimer in the 17 1.2 bouyer * documentation and/or other materials provided with the distribution. 18 1.2 bouyer * 19 1.2 bouyer * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.2 bouyer * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.2 bouyer * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.2 bouyer * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.2 bouyer * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.2 bouyer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.2 bouyer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.2 bouyer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.2 bouyer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.2 bouyer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.2 bouyer * POSSIBILITY OF SUCH DAMAGE. 30 1.2 bouyer */ 31 1.2 bouyer 32 1.2 bouyer #include <sys/cdefs.h> 33 1.8 bouyer __KERNEL_RCSID(0, "$NetBSD: can_pcb.c,v 1.8 2019/07/20 15:34:41 bouyer Exp $"); 34 1.2 bouyer 35 1.2 bouyer #include <sys/param.h> 36 1.2 bouyer #include <sys/systm.h> 37 1.2 bouyer #include <sys/malloc.h> 38 1.2 bouyer #include <sys/kmem.h> 39 1.2 bouyer #include <sys/mbuf.h> 40 1.2 bouyer #include <sys/protosw.h> 41 1.2 bouyer #include <sys/socket.h> 42 1.2 bouyer #include <sys/socketvar.h> 43 1.2 bouyer #include <sys/ioctl.h> 44 1.2 bouyer #include <sys/errno.h> 45 1.2 bouyer #include <sys/time.h> 46 1.2 bouyer #include <sys/pool.h> 47 1.2 bouyer #include <sys/proc.h> 48 1.2 bouyer 49 1.2 bouyer #include <net/if.h> 50 1.2 bouyer #include <net/route.h> 51 1.2 bouyer 52 1.2 bouyer #include <netcan/can.h> 53 1.2 bouyer #include <netcan/can_var.h> 54 1.2 bouyer #include <netcan/can_pcb.h> 55 1.2 bouyer 56 1.2 bouyer #define CANPCBHASH_BIND(table, ifindex) \ 57 1.2 bouyer &(table)->canpt_bindhashtbl[ \ 58 1.2 bouyer (ifindex) & (table)->canpt_bindhash] 59 1.2 bouyer #define CANPCBHASH_CONNECT(table, ifindex) \ 60 1.2 bouyer &(table)->canpt_connecthashtbl[ \ 61 1.2 bouyer (ifindex) & (table)->canpt_bindhash] 62 1.2 bouyer 63 1.2 bouyer struct pool canpcb_pool; 64 1.2 bouyer 65 1.2 bouyer void 66 1.2 bouyer can_pcbinit(struct canpcbtable *table, int bindhashsize, int connecthashsize) 67 1.2 bouyer { 68 1.2 bouyer static int canpcb_pool_initialized; 69 1.2 bouyer 70 1.2 bouyer if (canpcb_pool_initialized == 0) { 71 1.2 bouyer pool_init(&canpcb_pool, sizeof(struct canpcb), 0, 0, 0, 72 1.2 bouyer "canpcbpl", NULL, IPL_SOFTNET); 73 1.2 bouyer canpcb_pool_initialized = 1; 74 1.2 bouyer } 75 1.2 bouyer 76 1.2 bouyer TAILQ_INIT(&table->canpt_queue); 77 1.2 bouyer table->canpt_bindhashtbl = hashinit(bindhashsize, HASH_LIST, true, 78 1.2 bouyer &table->canpt_bindhash); 79 1.2 bouyer table->canpt_connecthashtbl = hashinit(connecthashsize, HASH_LIST, 80 1.2 bouyer true, &table->canpt_connecthash); 81 1.2 bouyer } 82 1.2 bouyer 83 1.2 bouyer int 84 1.2 bouyer can_pcballoc(struct socket *so, void *v) 85 1.2 bouyer { 86 1.2 bouyer struct canpcbtable *table = v; 87 1.2 bouyer struct canpcb *canp; 88 1.2 bouyer struct can_filter *can_init_filter; 89 1.2 bouyer int s; 90 1.2 bouyer 91 1.2 bouyer can_init_filter = kmem_alloc(sizeof(struct can_filter), KM_NOSLEEP); 92 1.2 bouyer if (can_init_filter == NULL) 93 1.2 bouyer return (ENOBUFS); 94 1.2 bouyer can_init_filter->can_id = 0; 95 1.2 bouyer can_init_filter->can_mask = 0; /* accept all by default */ 96 1.2 bouyer 97 1.2 bouyer s = splnet(); 98 1.2 bouyer canp = pool_get(&canpcb_pool, PR_NOWAIT); 99 1.2 bouyer splx(s); 100 1.2 bouyer if (canp == NULL) { 101 1.2 bouyer kmem_free(can_init_filter, sizeof(struct can_filter)); 102 1.2 bouyer return (ENOBUFS); 103 1.2 bouyer } 104 1.2 bouyer memset(canp, 0, sizeof(*canp)); 105 1.2 bouyer canp->canp_table = table; 106 1.2 bouyer canp->canp_socket = so; 107 1.2 bouyer canp->canp_filters = can_init_filter; 108 1.2 bouyer canp->canp_nfilters = 1; 109 1.2 bouyer mutex_init(&canp->canp_mtx, MUTEX_DEFAULT, IPL_NET); 110 1.2 bouyer canp->canp_refcount = 1; 111 1.2 bouyer 112 1.2 bouyer so->so_pcb = canp; 113 1.2 bouyer mutex_enter(&canp->canp_mtx); 114 1.2 bouyer TAILQ_INSERT_HEAD(&table->canpt_queue, canp, canp_queue); 115 1.2 bouyer can_pcbstate(canp, CANP_ATTACHED); 116 1.2 bouyer mutex_exit(&canp->canp_mtx); 117 1.2 bouyer return (0); 118 1.2 bouyer } 119 1.2 bouyer 120 1.2 bouyer int 121 1.2 bouyer can_pcbbind(void *v, struct sockaddr_can *scan, struct lwp *l) 122 1.2 bouyer { 123 1.2 bouyer struct canpcb *canp = v; 124 1.2 bouyer 125 1.2 bouyer if (scan->can_family != AF_CAN) 126 1.2 bouyer return (EAFNOSUPPORT); 127 1.7 maxv if (scan->can_len != sizeof(*scan)) 128 1.7 maxv return EINVAL; 129 1.2 bouyer mutex_enter(&canp->canp_mtx); 130 1.2 bouyer if (scan->can_ifindex != 0) { 131 1.2 bouyer canp->canp_ifp = if_byindex(scan->can_ifindex); 132 1.6 bouyer if (canp->canp_ifp == NULL || 133 1.6 bouyer canp->canp_ifp->if_dlt != DLT_CAN_SOCKETCAN) { 134 1.6 bouyer canp->canp_ifp = NULL; 135 1.6 bouyer mutex_exit(&canp->canp_mtx); 136 1.2 bouyer return (EADDRNOTAVAIL); 137 1.6 bouyer } 138 1.2 bouyer soisconnected(canp->canp_socket); 139 1.2 bouyer } else { 140 1.2 bouyer canp->canp_ifp = NULL; 141 1.2 bouyer canp->canp_socket->so_state &= ~SS_ISCONNECTED; /* XXX */ 142 1.2 bouyer } 143 1.2 bouyer can_pcbstate(canp, CANP_BOUND); 144 1.2 bouyer mutex_exit(&canp->canp_mtx); 145 1.2 bouyer return 0; 146 1.2 bouyer } 147 1.2 bouyer 148 1.2 bouyer /* 149 1.2 bouyer * Connect from a socket to a specified address. 150 1.2 bouyer */ 151 1.2 bouyer int 152 1.2 bouyer can_pcbconnect(void *v, struct sockaddr_can *scan) 153 1.2 bouyer { 154 1.2 bouyer #if 0 155 1.2 bouyer struct canpcb *canp = v; 156 1.2 bouyer struct sockaddr_can *ifaddr = NULL; 157 1.2 bouyer int error; 158 1.2 bouyer #endif 159 1.2 bouyer 160 1.2 bouyer if (scan->can_family != AF_CAN) 161 1.2 bouyer return (EAFNOSUPPORT); 162 1.7 maxv if (scan->can_len != sizeof(*scan)) 163 1.7 maxv return EINVAL; 164 1.2 bouyer #if 0 165 1.2 bouyer mutex_enter(&canp->canp_mtx); 166 1.2 bouyer memcpy(&canp->canp_dst, scan, sizeof(struct sockaddr_can)); 167 1.2 bouyer can_pcbstate(canp, CANP_CONNECTED); 168 1.2 bouyer mutex_exit(&canp->canp_mtx); 169 1.2 bouyer return 0; 170 1.2 bouyer #endif 171 1.2 bouyer return EOPNOTSUPP; 172 1.2 bouyer } 173 1.2 bouyer 174 1.2 bouyer void 175 1.2 bouyer can_pcbdisconnect(void *v) 176 1.2 bouyer { 177 1.2 bouyer struct canpcb *canp = v; 178 1.2 bouyer 179 1.2 bouyer mutex_enter(&canp->canp_mtx); 180 1.2 bouyer can_pcbstate(canp, CANP_DETACHED); 181 1.2 bouyer mutex_exit(&canp->canp_mtx); 182 1.2 bouyer if (canp->canp_socket->so_state & SS_NOFDREF) 183 1.2 bouyer can_pcbdetach(canp); 184 1.2 bouyer } 185 1.2 bouyer 186 1.2 bouyer void 187 1.2 bouyer can_pcbdetach(void *v) 188 1.2 bouyer { 189 1.2 bouyer struct canpcb *canp = v; 190 1.2 bouyer struct socket *so = canp->canp_socket; 191 1.2 bouyer 192 1.2 bouyer KASSERT(mutex_owned(softnet_lock)); 193 1.2 bouyer so->so_pcb = NULL; 194 1.2 bouyer mutex_enter(&canp->canp_mtx); 195 1.2 bouyer can_pcbstate(canp, CANP_DETACHED); 196 1.8 bouyer mutex_exit(&canp->canp_mtx); 197 1.2 bouyer can_pcbsetfilter(canp, NULL, 0); 198 1.2 bouyer TAILQ_REMOVE(&canp->canp_table->canpt_queue, canp, canp_queue); 199 1.2 bouyer sofree(so); /* sofree drops the softnet_lock */ 200 1.2 bouyer canp_unref(canp); 201 1.2 bouyer mutex_enter(softnet_lock); 202 1.2 bouyer } 203 1.2 bouyer 204 1.2 bouyer void 205 1.2 bouyer canp_ref(struct canpcb *canp) 206 1.2 bouyer { 207 1.2 bouyer KASSERT(mutex_owned(&canp->canp_mtx)); 208 1.2 bouyer canp->canp_refcount++; 209 1.2 bouyer } 210 1.2 bouyer 211 1.2 bouyer void 212 1.2 bouyer canp_unref(struct canpcb *canp) 213 1.2 bouyer { 214 1.2 bouyer mutex_enter(&canp->canp_mtx); 215 1.2 bouyer canp->canp_refcount--; 216 1.2 bouyer KASSERT(canp->canp_refcount >= 0); 217 1.2 bouyer if (canp->canp_refcount > 0) { 218 1.2 bouyer mutex_exit(&canp->canp_mtx); 219 1.2 bouyer return; 220 1.2 bouyer } 221 1.2 bouyer mutex_exit(&canp->canp_mtx); 222 1.2 bouyer mutex_destroy(&canp->canp_mtx); 223 1.2 bouyer pool_put(&canpcb_pool, canp); 224 1.2 bouyer } 225 1.2 bouyer 226 1.2 bouyer void 227 1.2 bouyer can_setsockaddr(struct canpcb *canp, struct sockaddr_can *scan) 228 1.2 bouyer { 229 1.2 bouyer 230 1.2 bouyer mutex_enter(&canp->canp_mtx); 231 1.2 bouyer memset(scan, 0, sizeof (*scan)); 232 1.2 bouyer scan->can_family = AF_CAN; 233 1.2 bouyer scan->can_len = sizeof(*scan); 234 1.3 bouyer if (canp->canp_ifp) 235 1.3 bouyer scan->can_ifindex = canp->canp_ifp->if_index; 236 1.3 bouyer else 237 1.3 bouyer scan->can_ifindex = 0; 238 1.2 bouyer mutex_exit(&canp->canp_mtx); 239 1.2 bouyer } 240 1.2 bouyer 241 1.2 bouyer int 242 1.2 bouyer can_pcbsetfilter(struct canpcb *canp, struct can_filter *fp, int nfilters) 243 1.2 bouyer { 244 1.2 bouyer 245 1.2 bouyer struct can_filter *newf; 246 1.8 bouyer struct can_filter *oldf; 247 1.8 bouyer int oldnf; 248 1.8 bouyer int error = 0; 249 1.2 bouyer 250 1.2 bouyer if (nfilters > 0) { 251 1.2 bouyer newf = 252 1.2 bouyer kmem_alloc(sizeof(struct can_filter) * nfilters, KM_SLEEP); 253 1.2 bouyer memcpy(newf, fp, sizeof(struct can_filter) * nfilters); 254 1.2 bouyer } else { 255 1.2 bouyer newf = NULL; 256 1.2 bouyer } 257 1.8 bouyer mutex_enter(&canp->canp_mtx); 258 1.8 bouyer oldf = canp->canp_filters; 259 1.8 bouyer oldnf = canp->canp_nfilters; 260 1.8 bouyer if (newf != NULL && canp->canp_state == CANP_DETACHED) { 261 1.8 bouyer error = ECONNRESET; 262 1.8 bouyer } else { 263 1.8 bouyer canp->canp_filters = newf; 264 1.8 bouyer canp->canp_nfilters = nfilters; 265 1.8 bouyer newf = NULL; 266 1.8 bouyer } 267 1.8 bouyer mutex_exit(&canp->canp_mtx); 268 1.8 bouyer if (oldf != NULL) { 269 1.8 bouyer kmem_free(oldf, sizeof(struct can_filter) * oldnf); 270 1.2 bouyer } 271 1.8 bouyer if (newf != NULL) { 272 1.8 bouyer kmem_free(newf, sizeof(struct can_filter) * nfilters); 273 1.8 bouyer } 274 1.8 bouyer return error; 275 1.2 bouyer } 276 1.2 bouyer 277 1.2 bouyer 278 1.2 bouyer 279 1.2 bouyer #if 0 280 1.2 bouyer /* 281 1.2 bouyer * Pass some notification to all connections of a protocol 282 1.2 bouyer * associated with address dst. The local address and/or port numbers 283 1.2 bouyer * may be specified to limit the search. The "usual action" will be 284 1.2 bouyer * taken, depending on the ctlinput cmd. The caller must filter any 285 1.2 bouyer * cmds that are uninteresting (e.g., no error in the map). 286 1.2 bouyer * Call the protocol specific routine (if any) to report 287 1.2 bouyer * any errors for each matching socket. 288 1.2 bouyer * 289 1.2 bouyer * Must be called at splsoftnet. 290 1.2 bouyer */ 291 1.2 bouyer int 292 1.2 bouyer can_pcbnotify(struct canpcbtable *table, u_int32_t faddr, u_int32_t laddr, 293 1.2 bouyer int errno, void (*notify)(struct canpcb *, int)) 294 1.2 bouyer { 295 1.2 bouyer struct canpcbhead *head; 296 1.2 bouyer struct canpcb *canp, *ncanp; 297 1.2 bouyer int nmatch; 298 1.2 bouyer 299 1.2 bouyer if (faddr == 0 || notify == 0) 300 1.2 bouyer return (0); 301 1.2 bouyer 302 1.2 bouyer nmatch = 0; 303 1.2 bouyer head = CANPCBHASH_CONNECT(table, faddr, laddr); 304 1.2 bouyer for (canp = LIST_FIRST(head); canp != NULL; canp = ncanp) { 305 1.2 bouyer ncanp = LIST_NEXT(canp, canp_hash); 306 1.2 bouyer if (canp->canp_faddr == faddr && 307 1.2 bouyer canp->canp_laddr == laddr) { 308 1.2 bouyer (*notify)(canp, errno); 309 1.2 bouyer nmatch++; 310 1.2 bouyer } 311 1.2 bouyer } 312 1.2 bouyer return (nmatch); 313 1.2 bouyer } 314 1.2 bouyer 315 1.2 bouyer void 316 1.2 bouyer can_pcbnotifyall(struct canpcbtable *table, u_int32_t faddr, int errno, 317 1.2 bouyer void (*notify)(struct canpcb *, int)) 318 1.2 bouyer { 319 1.2 bouyer struct canpcb *canp, *ncanp; 320 1.2 bouyer 321 1.2 bouyer if (faddr == 0 || notify == 0) 322 1.2 bouyer return; 323 1.2 bouyer 324 1.2 bouyer TAILQ_FOREACH_SAFE(canp, &table->canpt_queue, canp_queue, ncanp) { 325 1.2 bouyer if (canp->canp_faddr == faddr) 326 1.2 bouyer (*notify)(canp, errno); 327 1.2 bouyer } 328 1.2 bouyer } 329 1.2 bouyer #endif 330 1.2 bouyer 331 1.2 bouyer #if 0 332 1.2 bouyer void 333 1.2 bouyer can_pcbpurgeif0(struct canpcbtable *table, struct ifnet *ifp) 334 1.2 bouyer { 335 1.2 bouyer struct canpcb *canp, *ncanp; 336 1.2 bouyer struct ip_moptions *imo; 337 1.2 bouyer int i, gap; 338 1.2 bouyer 339 1.2 bouyer } 340 1.2 bouyer 341 1.2 bouyer void 342 1.2 bouyer can_pcbpurgeif(struct canpcbtable *table, struct ifnet *ifp) 343 1.2 bouyer { 344 1.2 bouyer struct canpcb *canp, *ncanp; 345 1.2 bouyer 346 1.2 bouyer for (canp = CIRCLEQ_FIRST(&table->canpt_queue); 347 1.2 bouyer canp != (void *)&table->canpt_queue; 348 1.2 bouyer canp = ncanp) { 349 1.2 bouyer ncanp = CIRCLEQ_NEXT(canp, canp_queue); 350 1.2 bouyer } 351 1.2 bouyer } 352 1.2 bouyer #endif 353 1.2 bouyer 354 1.2 bouyer 355 1.2 bouyer 356 1.2 bouyer void 357 1.2 bouyer can_pcbstate(struct canpcb *canp, int state) 358 1.2 bouyer { 359 1.2 bouyer int ifindex = canp->canp_ifp ? canp->canp_ifp->if_index : 0; 360 1.2 bouyer KASSERT(mutex_owned(&canp->canp_mtx)); 361 1.2 bouyer 362 1.2 bouyer if (canp->canp_state > CANP_ATTACHED) 363 1.2 bouyer LIST_REMOVE(canp, canp_hash); 364 1.2 bouyer 365 1.2 bouyer switch (state) { 366 1.2 bouyer case CANP_BOUND: 367 1.2 bouyer LIST_INSERT_HEAD(CANPCBHASH_BIND(canp->canp_table, 368 1.2 bouyer ifindex), canp, canp_hash); 369 1.2 bouyer break; 370 1.2 bouyer case CANP_CONNECTED: 371 1.2 bouyer LIST_INSERT_HEAD(CANPCBHASH_CONNECT(canp->canp_table, 372 1.2 bouyer ifindex), canp, canp_hash); 373 1.2 bouyer break; 374 1.2 bouyer } 375 1.2 bouyer 376 1.2 bouyer canp->canp_state = state; 377 1.2 bouyer } 378 1.2 bouyer 379 1.2 bouyer /* 380 1.2 bouyer * check mbuf against socket accept filter. 381 1.2 bouyer * returns true if mbuf is accepted, false otherwise 382 1.2 bouyer */ 383 1.2 bouyer bool 384 1.2 bouyer can_pcbfilter(struct canpcb *canp, struct mbuf *m) 385 1.2 bouyer { 386 1.2 bouyer int i; 387 1.2 bouyer struct can_frame *fmp; 388 1.2 bouyer struct can_filter *fip; 389 1.2 bouyer 390 1.2 bouyer KASSERT(mutex_owned(&canp->canp_mtx)); 391 1.2 bouyer KASSERT((m->m_flags & M_PKTHDR) != 0); 392 1.2 bouyer KASSERT(m->m_len == m->m_pkthdr.len); 393 1.2 bouyer 394 1.2 bouyer fmp = mtod(m, struct can_frame *); 395 1.2 bouyer for (i = 0; i < canp->canp_nfilters; i++) { 396 1.2 bouyer fip = &canp->canp_filters[i]; 397 1.2 bouyer if ((fmp->can_id & fip->can_mask) == fip->can_id) 398 1.2 bouyer return true; 399 1.2 bouyer } 400 1.2 bouyer /* no match */ 401 1.2 bouyer return false; 402 1.2 bouyer } 403