1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 use alloc::rc::{Rc, Weak}; 18 use core::array; 19 use core::ffi::c_void; 20 use core::fmt; 21 use log::error; 22 23 use super::{Channel, Dispatcher}; 24 use crate::sys; 25 use crate::{Handle, Result, TipcError}; 26 27 /// A handle set is a collection of tipc service ports, along with their 28 /// respective connections to clients. 29 /// 30 /// A handle set is specific to a particular service, with a fixed set of ports 31 /// and a maximum number of allowed concurrent connections 32 /// `MAX_CONNECTION_COUNT`. 33 pub(super) struct HandleSet< 34 D: Dispatcher, 35 const PORT_COUNT: usize, 36 const MAX_CONNECTION_COUNT: usize, 37 > { 38 ports: [Rc<Channel<D>>; PORT_COUNT], 39 connections: [Option<Rc<Channel<D>>>; MAX_CONNECTION_COUNT], 40 connection_count: usize, 41 handle: Handle, 42 } 43 44 impl<D: Dispatcher, const PORT_COUNT: usize, const MAX_CONNECTION_COUNT: usize> 45 HandleSet<D, PORT_COUNT, MAX_CONNECTION_COUNT> 46 { try_new(ports: [Rc<Channel<D>>; PORT_COUNT]) -> Result<Self>47 pub fn try_new(ports: [Rc<Channel<D>>; PORT_COUNT]) -> Result<Self> { 48 // SAFETY: syscall, return value is either a negative error code or a 49 // valid handle. 50 let rc = unsafe { trusty_sys::handle_set_create() }; 51 if rc < 0 { 52 Err(TipcError::from_uapi(rc)) 53 } else { 54 for port in &ports { 55 if !port.is_port() { 56 return Err(TipcError::InvalidData); 57 } 58 } 59 60 let handle_set = Self { 61 ports, 62 connections: array::from_fn(|_| None), 63 connection_count: 0, 64 handle: Handle::from_raw(rc as i32)?, 65 }; 66 67 for port in &handle_set.ports { 68 handle_set.do_set_ctrl( 69 sys::HSET_ADD as u32, 70 trusty_sys::uevent::ALL_EVENTS, 71 port, 72 )?; 73 } 74 75 Ok(handle_set) 76 } 77 } 78 79 /// Register a new connection in this handle set 80 /// 81 /// This function does not need to be unsafe because we do not dereference 82 /// the opaque pointer. However, the handler must agree on the type of this 83 /// cookie. add_connection(&mut self, connection: Rc<Channel<D>>) -> Result<()>84 pub fn add_connection(&mut self, connection: Rc<Channel<D>>) -> Result<()> { 85 if !connection.is_connection() { 86 return Err(TipcError::InvalidData); 87 } 88 89 // We should never exceed this count since the port is masked when 90 // we hit the max 91 assert!(!self.at_max_connections(), "Too many connections"); 92 self.do_set_ctrl(sys::HSET_ADD as u32, trusty_sys::uevent::ALL_EVENTS, &connection)?; 93 94 let _ = self 95 .connections 96 .iter_mut() 97 .find(|c| c.is_none()) 98 .expect("No empty slot found, shouldn't happen because we checked at_max_connections") 99 .replace(connection); 100 101 self.connection_count += 1; 102 103 if self.at_max_connections() { 104 self.mask_all_ports(); 105 } 106 Ok(()) 107 } 108 109 /// Wait for an event on this handle set 110 /// 111 /// Waits for `timeout` milliseconds or indefinitely if `None`. wait(&self, timeout: Option<u32>) -> Result<trusty_sys::uevent>112 pub fn wait(&self, timeout: Option<u32>) -> Result<trusty_sys::uevent> { 113 self.handle.wait(timeout) 114 } 115 116 /// Close a connection in this handle set. 117 /// 118 /// This should only be used to close active connections, not ports. close(&mut self, connection: Rc<Channel<D>>)119 pub fn close(&mut self, connection: Rc<Channel<D>>) { 120 assert!(connection.is_connection()); 121 122 let _ = self 123 .connections 124 .iter_mut() 125 .find(|c| c.as_ref() == Some(&connection)) 126 .expect("Could not find connection") 127 .take(); 128 self.do_set_ctrl(sys::HSET_DEL as u32, 0, &connection).unwrap_or_else(|e| { 129 error!("Failed to remove channel {:?} from handle set: {:?}", connection, e) 130 }); 131 132 // This should be the last instance of the channel 133 assert_eq!(Rc::strong_count(&connection), 1); 134 let _ = connection; 135 136 if self.at_max_connections() { 137 self.unmask_all_ports(); 138 } 139 140 self.connection_count -= 1; 141 } 142 mask_all_ports(&self)143 fn mask_all_ports(&self) { 144 for port in &self.ports { 145 self.do_set_ctrl(sys::HSET_MOD as u32, 0, &port).expect("Failed to mask port"); 146 } 147 } 148 unmask_all_ports(&self)149 fn unmask_all_ports(&self) { 150 for port in &self.ports { 151 self.do_set_ctrl(sys::HSET_MOD as u32, trusty_sys::uevent::ALL_EVENTS, &port) 152 .expect("Failed to unmask port"); 153 } 154 } 155 do_set_ctrl(&self, cmd: u32, event: u32, channel: &Rc<Channel<D>>) -> Result<()>156 fn do_set_ctrl(&self, cmd: u32, event: u32, channel: &Rc<Channel<D>>) -> Result<()> { 157 let cookie = Rc::downgrade(&channel).into_raw(); 158 159 let mut uevt = trusty_sys::uevent { 160 handle: channel.handle().as_raw_fd(), 161 event, 162 cookie: cookie as *mut c_void, 163 }; 164 // SAFETY: syscall. The uevent pointer points to a correctly initialized 165 // structure that is borrowed and valid across the call. The handle for 166 // the handle set is valid for the same lifetime as self, so will remain 167 // valid at least as long as the channel being added/modified. 168 let rc = unsafe { trusty_sys::handle_set_ctrl(self.handle.as_raw_fd(), cmd, &mut uevt) }; 169 170 if cmd != sys::HSET_ADD as u32 || trusty_sys::Error::is_err(rc) { 171 // SAFETY: We are constructing the raw pointer to drop here using 172 // Weak::into_raw(), so we know that it is valid to turn back into a 173 // Weak pointer. We transfer ownership of the weak reference to the 174 // kernel when adding a handle to the handle set, so we want to drop 175 // that reference only when the handle is then removed from the set. 176 // We do this by dropping the weak reference twice on a successful 177 // HSET_DEL. This is safe because the weak reference cookie from the 178 // kernel will never be again provided by this handle set in a poll 179 // operation because we have removed the handle from the set, and we 180 // check that the connection has at least one weak reference 181 // outstanding to remove. 182 unsafe { 183 drop(Weak::from_raw(cookie)); 184 if cmd == sys::HSET_DEL as u32 185 && !trusty_sys::Error::is_err(rc) 186 && Rc::weak_count(&channel) >= 1 187 { 188 drop(Weak::from_raw(cookie)); 189 } 190 } 191 } 192 if rc < 0 { 193 Err(TipcError::from_uapi(rc)) 194 } else { 195 Ok(()) 196 } 197 } 198 at_max_connections(&self) -> bool199 fn at_max_connections(&self) -> bool { 200 self.connection_count >= MAX_CONNECTION_COUNT 201 } 202 } 203 204 impl<D: Dispatcher, const PORT_COUNT: usize, const MAX_CONNECTION_COUNT: usize> fmt::Debug 205 for HandleSet<D, PORT_COUNT, MAX_CONNECTION_COUNT> 206 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 208 write!(f, "HandleSet: [{:?}", self.ports) 209 } 210 } 211