1 /* 2 Copyright (c) 2013, The Linux Foundation. All rights reserved. 3 4 Redistribution and use in source and binary forms, with or without 5 modification, are permitted provided that the following conditions are 6 met: 7 * Redistributions of source code must retain the above copyright 8 notice, this list of conditions and the following disclaimer. 9 * Redistributions in binary form must reproduce the above 10 copyright notice, this list of conditions and the following 11 disclaimer in the documentation and/or other materials provided 12 with the distribution. 13 * Neither the name of The Linux Foundation nor the names of its 14 contributors may be used to endorse or promote products derived 15 from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 /*! 30 @file 31 IPACM_Routing.cpp 32 33 @brief 34 This file implements the IPACM routing functionality. 35 36 @Author 37 38 */ 39 40 #include <unistd.h> 41 #include <sys/ioctl.h> 42 #include <fcntl.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 46 #include "IPACM_Routing.h" 47 #include <IPACM_Log.h> 48 49 const char *IPACM_Routing::DEVICE_NAME = "/dev/ipa"; 50 51 IPACM_Routing::IPACM_Routing() 52 { 53 m_fd = open(DEVICE_NAME, O_RDWR); 54 if (0 == m_fd) 55 { 56 IPACMERR("Failed opening %s.\n", DEVICE_NAME); 57 } 58 } 59 60 IPACM_Routing::~IPACM_Routing() 61 { 62 close(m_fd); 63 } 64 65 bool IPACM_Routing::DeviceNodeIsOpened() 66 { 67 int res = fcntl(m_fd, F_GETFL); 68 69 if (m_fd > 0 && res >= 0) return true; 70 else return false; 71 72 } 73 74 bool IPACM_Routing::AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable) 75 { 76 int retval = 0, cnt=0; 77 bool isInvalid = false; 78 79 if (!DeviceNodeIsOpened()) 80 { 81 IPACMERR("Device is not opened\n"); 82 return false; 83 } 84 85 for(cnt=0; cnt<ruleTable->num_rules; cnt++) 86 { 87 if(ruleTable->rules[cnt].rule.dst > IPA_CLIENT_MAX) 88 { 89 IPACMERR("Invalid dst pipe, Rule:%d dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst); 90 isInvalid = true; 91 } 92 } 93 94 if(isInvalid) 95 { 96 return false; 97 } 98 99 retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable); 100 if (retval) 101 { 102 IPACMERR("Failed adding routing rule %p\n", ruleTable); 103 return false; 104 } 105 106 for(cnt=0; cnt<ruleTable->num_rules; cnt++) 107 { 108 IPACMDBG("Rule:%d dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst); 109 } 110 111 IPACMDBG_H("Added routing rule %p\n", ruleTable); 112 return true; 113 } 114 115 bool IPACM_Routing::DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable) 116 { 117 int retval = 0; 118 119 if (!DeviceNodeIsOpened()) return false; 120 121 retval = ioctl(m_fd, IPA_IOC_DEL_RT_RULE, ruleTable); 122 if (retval) 123 { 124 IPACMERR("Failed deleting routing rule table %p\n", ruleTable); 125 return false; 126 } 127 128 IPACMDBG_H("Deleted routing rule %p\n", ruleTable); 129 return true; 130 } 131 132 bool IPACM_Routing::Commit(enum ipa_ip_type ip) 133 { 134 int retval = 0; 135 136 if (!DeviceNodeIsOpened()) return false; 137 138 retval = ioctl(m_fd, IPA_IOC_COMMIT_RT, ip); 139 if (retval) 140 { 141 IPACMERR("Failed commiting routing rules.\n"); 142 return false; 143 } 144 145 IPACMDBG_H("Commited routing rules to IPA HW.\n"); 146 return true; 147 } 148 149 bool IPACM_Routing::Reset(enum ipa_ip_type ip) 150 { 151 int retval = 0; 152 153 if (!DeviceNodeIsOpened()) return false; 154 155 retval = ioctl(m_fd, IPA_IOC_RESET_RT, ip); 156 retval |= ioctl(m_fd, IPA_IOC_COMMIT_RT, ip); 157 if (retval) 158 { 159 IPACMERR("Failed resetting routing block.\n"); 160 return false; 161 } 162 163 IPACMDBG_H("Reset command issued to IPA routing block.\n"); 164 return true; 165 } 166 167 bool IPACM_Routing::GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable) 168 { 169 int retval = 0; 170 171 if (!DeviceNodeIsOpened()) return false; 172 173 retval = ioctl(m_fd, IPA_IOC_GET_RT_TBL, routingTable); 174 if (retval) 175 { 176 IPACMERR("IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", routingTable, retval); 177 return false; 178 } 179 IPACMDBG_H("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n"); 180 /* put routing table right after successfully get routing table */ 181 PutRoutingTable(routingTable->hdl); 182 183 return true; 184 } 185 186 bool IPACM_Routing::PutRoutingTable(uint32_t routingTableHandle) 187 { 188 int retval = 0; 189 190 if (!DeviceNodeIsOpened()) return false; 191 192 retval = ioctl(m_fd, IPA_IOC_PUT_RT_TBL, routingTableHandle); 193 if (retval) 194 { 195 IPACMERR("IPA_IOCTL_PUT_RT_TBL ioctl failed.\n"); 196 return false; 197 } 198 199 IPACMDBG_H("IPA_IOCTL_PUT_RT_TBL ioctl issued to IPA routing block.\n"); 200 return true; 201 } 202 203 bool IPACM_Routing::DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip) 204 { 205 const uint8_t NUM_RULES = 1; 206 struct ipa_ioc_del_rt_rule *rt_rule; 207 struct ipa_rt_rule_del *rt_rule_entry; 208 bool res = true; 209 int len = 0; 210 211 if (rt_rule_hdl == 0) 212 { 213 IPACMERR(" No route handle passed. Ignoring it\n"); 214 return res; 215 } 216 217 len = (sizeof(struct ipa_ioc_del_rt_rule)) + (NUM_RULES * sizeof(struct ipa_rt_rule_del)); 218 rt_rule = (struct ipa_ioc_del_rt_rule *)malloc(len); 219 if (rt_rule == NULL) 220 { 221 IPACMERR("unable to allocate memory for del route rule\n"); 222 return false; 223 } 224 225 memset(rt_rule, 0, len); 226 rt_rule->commit = 1; 227 rt_rule->num_hdls = NUM_RULES; 228 rt_rule->ip = ip; 229 230 rt_rule_entry = &rt_rule->hdl[0]; 231 rt_rule_entry->status = -1; 232 rt_rule_entry->hdl = rt_rule_hdl; 233 234 IPACMDBG_H("Deleting Route hdl:(0x%x) with ip type: %d\n", rt_rule_entry->hdl, ip); 235 if ((false == DeleteRoutingRule(rt_rule)) || 236 (rt_rule_entry->status)) 237 { 238 PERROR("Routing rule deletion failed!\n"); 239 goto fail; 240 res = false; 241 } 242 243 fail: 244 free(rt_rule); 245 246 return res; 247 } 248 249 bool IPACM_Routing::ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule *mdfyRules) 250 { 251 int retval = 0, cnt; 252 253 if (!DeviceNodeIsOpened()) 254 { 255 IPACMERR("Device is not opened\n"); 256 return false; 257 } 258 259 retval = ioctl(m_fd, IPA_IOC_MDFY_RT_RULE, mdfyRules); 260 if (retval) 261 { 262 IPACMERR("Failed modifying routing rules %p\n", mdfyRules); 263 return false; 264 } 265 266 for(cnt=0; cnt<mdfyRules->num_rules; cnt++) 267 { 268 if(mdfyRules->rules[cnt].status != 0) 269 { 270 IPACMERR("Unable to modify rule: %d\n", cnt); 271 } 272 } 273 274 IPACMDBG_H("Modified routing rules %p\n", mdfyRules); 275 return true; 276 } 277